Code refactor
This commit is contained in:
parent
d8dc39d293
commit
3a0e130e06
23 changed files with 399 additions and 389 deletions
|
@ -22,8 +22,8 @@ android {
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
|
|
||||||
applicationId "code.name.monkey.retromusic"
|
applicationId "code.name.monkey.retromusic"
|
||||||
versionCode 405
|
versionCode 408
|
||||||
versionName '3.4.900'
|
versionName '3.5.000'
|
||||||
|
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
|
|
||||||
|
@ -129,8 +129,8 @@ dependencies {
|
||||||
implementation 'androidx.preference:preference:1.1.0'
|
implementation 'androidx.preference:preference:1.1.0'
|
||||||
|
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
implementation 'androidx.core:core-ktx:1.1.0'
|
implementation 'androidx.core:core-ktx:1.2.0'
|
||||||
implementation 'androidx.fragment:fragment:1.2.0'
|
implementation 'androidx.fragment:fragment:1.2.1'
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||||
|
|
||||||
implementation 'com.google.android.material:material:1.2.0-alpha04'
|
implementation 'com.google.android.material:material:1.2.0-alpha04'
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
<html>
<head>
<style type="text/css">
* {
word-wrap: break-word;
}
{style-placeholder}
a {
color: {link-color};
}
a:active {
color: {link-color-active};
}
ol {
list-style-position: inside;
padding-left: 0;
padding-right: 0;
}
li {
padding-top: 8px;
}
</style>
</head>
<body>
<h4>v.3.5.000</h4>
<ul>
<li>Major code refactor</li>
<li></li>
</ul>
<h4>v3.4.900</h4>
<ul>
<li>Added playlist search</li>
<li>Added Drive mode</li>
<li>Added Album and Artist layout change option in library</li>
<li>Added Show more album and artist information in details</li>
<li>Added Pixel style scroller bar</li>
<li>Added current now playing share</li>
<li>Fix font issues and colors in some places</li>
<li>Improved Full now playing theme</li>
</ul>
<h4>v3.4.850</h4>
<ul>
<li>Added new theme called circle</li>
<li>Added tiny color card style for home artists</li>
<li>Added extra track info details to now playing themes</li>
<li>Added scroll animation</li>
<li>Added smooth transition animations 🤔</li>
<li>Added current playing tab options for Bottom Navigation View</li>
<li>Added search in genre</li>
<li>Improved selecting feedback effect(ripple with corners)</li>
<li>Fix bugs & crashes</li>
<li>Fix crashing on lyrics</li>
<li>Fix genre details last song is under mini player</li>
<li>Fix colors mistakes and font sizes</li>
<li>Fix slider jumping while scrolling in now playing themes</li>
</ul>
<h4>v3.4.800</h4>
<ul>
<li>Improved dark theme colors and Follow system theme</li>
<li>Rounded rectangle ripple for BottomNavigationView</li>
<li>Follow sleep timer dialog checkbox color as accent</li>
<li>Added song list selection for Album and Artist details</li>
<li>Fixed Toolbar popup text color when selecting songs</li>
</ul>
<h4>v3.4.700</h4>
<ul>
<li>Added splash screen(for app loading time)</li>
<li>Updated dark theme colors</li>
<li>Added circular progress view</li>
<li>Hiding year if not showing</li>
</ul>
<h4>v3.4.600</h4>
<ul>
<li>Fix notification layout height</li>
<li>Fix folder list last item not showing</li>
<li>Added auto hide/ show controls according to first and last item</li>
</ul>
<h4>v3.4.500</h4>
<ul>
<li>Added peak theme</li>
<li>Added app rating dialog</li>
<li>Fix song name scrolling in now playing themes if it's long</li>
<li>Fix playing queue last item hiding FAB</li>
<li>Added desaturated color option for dark mode</li>
<li>Fix slow search loading</li>
<li>Fix last added slow loading</li>
<li>Fix home banner toolbar corner</li>
<li>Fix home crashing when switching between two tabs</li>
<li>Fix remaining time in playing queue</li>
<li>Fix font not applied for some components</li>
<li>Fix crashing on album details sorting</li>
<li>Fixed lot of internal bugs</li>
<li>Fix dialog expand</li>
<li>Fix list card color</li>
<li>Removed SlidingUpPanel to replace with BottomSheet</li>
<li>Removed color theme as per material design guidelines</li>
<li>Removed classic theme(We're bringing back)</li>
<li>Replace line switch to Material Switch in settings</li>
<li>Performance improved</li>
<li>Updated internal libraries</li>
<li>Updated translation</li>
<li>Limiting the use of Theme engine for making use of system colors</li>
<li>Change home icon from the user icon</li>
<li>Corrected all toolbar with elevation when scrolling</li>
</ul>
<p>If you see entire app white or dark or black select same theme in settings to fix </p>
<p style="line-height:150%"><a href="https://github.com/h4h13/RetroMusicPlayer/wiki/FAQ">FAQ's</a>
</p>
<p style="line-height:150%">*If you face any UI related issues you clear app data and cache, if its
not working try to
uninstall and install again. </p>
</body>
|
<html>
<head>
<style type="text/css">
* {
word-wrap: break-word;
}
{style-placeholder}
a {
color: {link-color};
}
a:active {
color: {link-color-active};
}
ol {
list-style-position: inside;
padding-left: 0;
padding-right: 0;
}
li {
padding-top: 8px;
}
</style>
</head>
<body>
<h4>v.3.5.000</h4>
<ul>
<li>Major code refactor for Album and Artist loading</li>
</ul>
<h4>v3.4.900</h4>
<ul>
<li>Added playlist search</li>
<li>Added Drive mode</li>
<li>Added Album and Artist layout change option in library</li>
<li>Added Show more album and artist information in details</li>
<li>Added Pixel style scroller bar</li>
<li>Added current now playing share</li>
<li>Fix font issues and colors in some places</li>
<li>Improved Full now playing theme</li>
</ul>
<h4>v3.4.850</h4>
<ul>
<li>Added new theme called circle</li>
<li>Added tiny color card style for home artists</li>
<li>Added extra track info details to now playing themes</li>
<li>Added scroll animation</li>
<li>Added smooth transition animations 🤔</li>
<li>Added current playing tab options for Bottom Navigation View</li>
<li>Added search in genre</li>
<li>Improved selecting feedback effect(ripple with corners)</li>
<li>Fix bugs & crashes</li>
<li>Fix crashing on lyrics</li>
<li>Fix genre details last song is under mini player</li>
<li>Fix colors mistakes and font sizes</li>
<li>Fix slider jumping while scrolling in now playing themes</li>
</ul>
<h4>v3.4.800</h4>
<ul>
<li>Improved dark theme colors and Follow system theme</li>
<li>Rounded rectangle ripple for BottomNavigationView</li>
<li>Follow sleep timer dialog checkbox color as accent</li>
<li>Added song list selection for Album and Artist details</li>
<li>Fixed Toolbar popup text color when selecting songs</li>
</ul>
<h4>v3.4.700</h4>
<ul>
<li>Added splash screen(for app loading time)</li>
<li>Updated dark theme colors</li>
<li>Added circular progress view</li>
<li>Hiding year if not showing</li>
</ul>
<h4>v3.4.600</h4>
<ul>
<li>Fix notification layout height</li>
<li>Fix folder list last item not showing</li>
<li>Added auto hide/ show controls according to first and last item</li>
</ul>
<h4>v3.4.500</h4>
<ul>
<li>Added peak theme</li>
<li>Added app rating dialog</li>
<li>Fix song name scrolling in now playing themes if it's long</li>
<li>Fix playing queue last item hiding FAB</li>
<li>Added desaturated color option for dark mode</li>
<li>Fix slow search loading</li>
<li>Fix last added slow loading</li>
<li>Fix home banner toolbar corner</li>
<li>Fix home crashing when switching between two tabs</li>
<li>Fix remaining time in playing queue</li>
<li>Fix font not applied for some components</li>
<li>Fix crashing on album details sorting</li>
<li>Fixed lot of internal bugs</li>
<li>Fix dialog expand</li>
<li>Fix list card color</li>
<li>Removed SlidingUpPanel to replace with BottomSheet</li>
<li>Removed color theme as per material design guidelines</li>
<li>Removed classic theme(We're bringing back)</li>
<li>Replace line switch to Material Switch in settings</li>
<li>Performance improved</li>
<li>Updated internal libraries</li>
<li>Updated translation</li>
<li>Limiting the use of Theme engine for making use of system colors</li>
<li>Change home icon from the user icon</li>
<li>Corrected all toolbar with elevation when scrolling</li>
</ul>
<p>If you see entire app white or dark or black select same theme in settings to fix </p>
<p style="line-height:150%"><a href="https://github.com/h4h13/RetroMusicPlayer/wiki/FAQ">FAQ's</a>
</p>
<p style="line-height:150%">*If you face any UI related issues you clear app data and cache, if its
not working try to
uninstall and install again. </p>
</body>
|
|
@ -31,7 +31,7 @@ object Constants {
|
||||||
const val FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md"
|
const val FAQ_LINK = "https://github.com/h4h13/RetroMusicPlayer/blob/master/FAQ.md"
|
||||||
const val PINTEREST = "https://in.pinterest.com/retromusicapp/"
|
const val PINTEREST = "https://in.pinterest.com/retromusicapp/"
|
||||||
|
|
||||||
const val BASE_SELECTION = MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
|
const val baseSelection = MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
|
||||||
|
|
||||||
val baseProjection = arrayOf(BaseColumns._ID, // 0
|
val baseProjection = arrayOf(BaseColumns._ID, // 0
|
||||||
MediaStore.Audio.AudioColumns.TITLE, // 1
|
MediaStore.Audio.AudioColumns.TITLE, // 1
|
||||||
|
|
|
@ -29,8 +29,8 @@ import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
|
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
|
||||||
import com.afollestad.materialdialogs.list.listItems
|
import com.afollestad.materialdialogs.list.listItems
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.*
|
import java.util.Collections
|
||||||
import kotlin.collections.ArrayList
|
import java.util.Comparator
|
||||||
|
|
||||||
class BlacklistFolderChooserDialog : DialogFragment() {
|
class BlacklistFolderChooserDialog : DialogFragment() {
|
||||||
|
|
||||||
|
@ -40,7 +40,6 @@ class BlacklistFolderChooserDialog : DialogFragment() {
|
||||||
private var canGoUp = false
|
private var canGoUp = false
|
||||||
private var callback: FolderCallback? = null
|
private var callback: FolderCallback? = null
|
||||||
|
|
||||||
|
|
||||||
private fun contentsArray(): List<String> {
|
private fun contentsArray(): List<String> {
|
||||||
if (parentContents == null) {
|
if (parentContents == null) {
|
||||||
return if (canGoUp) {
|
return if (canGoUp) {
|
||||||
|
@ -81,7 +80,11 @@ class BlacklistFolderChooserDialog : DialogFragment() {
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
var savedInstanceStateFinal = savedInstanceState
|
var savedInstanceStateFinal = savedInstanceState
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
||||||
ActivityCompat.checkSelfPermission(requireActivity(), Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
ActivityCompat.checkSelfPermission(
|
||||||
|
requireActivity(),
|
||||||
|
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||||
|
) != PackageManager.PERMISSION_GRANTED
|
||||||
|
) {
|
||||||
return MaterialDialog(requireActivity(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
|
return MaterialDialog(requireActivity(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
|
||||||
title(R.string.md_error_label)
|
title(R.string.md_error_label)
|
||||||
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
|
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
|
||||||
|
|
|
@ -10,21 +10,19 @@ enum class NowPlayingScreen constructor(
|
||||||
@param:DrawableRes @field:DrawableRes val drawableResId: Int,
|
@param:DrawableRes @field:DrawableRes val drawableResId: Int,
|
||||||
val id: Int
|
val id: Int
|
||||||
) {
|
) {
|
||||||
|
|
||||||
NORMAL(R.string.normal, R.drawable.np_normal, 0),
|
|
||||||
FLAT(R.string.flat, R.drawable.np_flat, 1),
|
|
||||||
FIT(R.string.fit, R.drawable.np_fit, 12),
|
|
||||||
TINY(R.string.tiny, R.drawable.np_tiny, 7),
|
|
||||||
PEAK(R.string.peak, R.drawable.np_peak, 14),
|
|
||||||
|
|
||||||
ADAPTIVE(R.string.adaptive, R.drawable.np_adaptive, 10),
|
ADAPTIVE(R.string.adaptive, R.drawable.np_adaptive, 10),
|
||||||
BLUR(R.string.blur, R.drawable.np_blur, 4),
|
BLUR(R.string.blur, R.drawable.np_blur, 4),
|
||||||
BLUR_CARD(R.string.blur_card, R.drawable.np_blur_card, 9),
|
BLUR_CARD(R.string.blur_card, R.drawable.np_blur_card, 9),
|
||||||
CARD(R.string.card, R.drawable.np_card, 6),
|
CARD(R.string.card, R.drawable.np_card, 6),
|
||||||
COLOR(R.string.color, R.drawable.np_color, 5),
|
COLOR(R.string.color, R.drawable.np_color, 5),
|
||||||
CIRCLE(R.string.circle, R.drawable.np_minimalistic_circle, 15),
|
CIRCLE(R.string.circle, R.drawable.np_minimalistic_circle, 15),
|
||||||
|
FIT(R.string.fit, R.drawable.np_fit, 12),
|
||||||
|
FLAT(R.string.flat, R.drawable.np_flat, 1),
|
||||||
FULL(R.string.full, R.drawable.np_full, 2),
|
FULL(R.string.full, R.drawable.np_full, 2),
|
||||||
MATERIAL(R.string.material, R.drawable.np_material, 11),
|
MATERIAL(R.string.material, R.drawable.np_material, 11),
|
||||||
|
NORMAL(R.string.normal, R.drawable.np_normal, 0),
|
||||||
|
PEAK(R.string.peak, R.drawable.np_peak, 14),
|
||||||
PLAIN(R.string.plain, R.drawable.np_plain, 3),
|
PLAIN(R.string.plain, R.drawable.np_plain, 3),
|
||||||
SIMPLE(R.string.simple, R.drawable.np_simple, 8),
|
SIMPLE(R.string.simple, R.drawable.np_simple, 8),
|
||||||
|
TINY(R.string.tiny, R.drawable.np_tiny, 7),
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ class BlurPlayerFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPrefer
|
||||||
private fun updateBlur() {
|
private fun updateBlur() {
|
||||||
val blurAmount = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
val blurAmount = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
.getInt(PreferenceUtil.NEW_BLUR_AMOUNT, 25)
|
.getInt(PreferenceUtil.NEW_BLUR_AMOUNT, 25)
|
||||||
colorBackground!!.clearColorFilter()
|
colorBackground?.clearColorFilter()
|
||||||
SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong)
|
SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong)
|
||||||
.checkIgnoreMediaStore(requireContext())
|
.checkIgnoreMediaStore(requireContext())
|
||||||
.generatePalette(requireContext()).build()
|
.generatePalette(requireContext()).build()
|
||||||
|
@ -109,7 +109,7 @@ class BlurPlayerFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPrefer
|
||||||
.into(object : RetroMusicColoredTarget(colorBackground) {
|
.into(object : RetroMusicColoredTarget(colorBackground) {
|
||||||
override fun onColorReady(color: Int) {
|
override fun onColorReady(color: Int) {
|
||||||
if (color == defaultFooterColor) {
|
if (color == defaultFooterColor) {
|
||||||
colorBackground!!.setColorFilter(color)
|
colorBackground?.setColorFilter(color)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -13,9 +13,9 @@ import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
||||||
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
|
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
|
||||||
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
|
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
|
||||||
|
import code.name.monkey.retromusic.glide.AlbumGlideRequest
|
||||||
import code.name.monkey.retromusic.glide.BlurTransformation
|
import code.name.monkey.retromusic.glide.BlurTransformation
|
||||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||||
import code.name.monkey.retromusic.glide.SongGlideRequest
|
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
@ -53,7 +53,7 @@ class CardBlurFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPreferen
|
||||||
override fun onColorChanged(color: Int) {
|
override fun onColorChanged(color: Int) {
|
||||||
playbackControlsFragment.setDark(color)
|
playbackControlsFragment.setDark(color)
|
||||||
lastColor = color
|
lastColor = color
|
||||||
callbacks!!.onPaletteColorChanged()
|
callbacks?.onPaletteColorChanged()
|
||||||
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity)
|
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, Color.WHITE, activity)
|
||||||
|
|
||||||
playerToolbar.setTitleTextColor(Color.WHITE)
|
playerToolbar.setTitleTextColor(Color.WHITE)
|
||||||
|
@ -127,10 +127,19 @@ class CardBlurFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPreferen
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateBlur() {
|
private fun updateBlur() {
|
||||||
|
colorBackground?.clearColorFilter()
|
||||||
val blurAmount = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
val blurAmount = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
.getInt(PreferenceUtil.NEW_BLUR_AMOUNT, 25)
|
.getInt(PreferenceUtil.NEW_BLUR_AMOUNT, 25)
|
||||||
colorBackground!!.clearColorFilter()
|
AlbumGlideRequest.Builder.from(Glide.with(requireContext()), MusicPlayerRemote.currentSong.albumId)
|
||||||
SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong)
|
.generatePalette(requireContext())
|
||||||
|
.build()
|
||||||
|
.transform(BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat()).build())
|
||||||
|
.into(object : RetroMusicColoredTarget(colorBackground) {
|
||||||
|
override fun onColorReady(color: Int) {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
//colorBackground?.clearColorFilter()
|
||||||
|
/*SongGlideRequest.Builder.from(Glide.with(requireActivity()), MusicPlayerRemote.currentSong)
|
||||||
.checkIgnoreMediaStore(requireContext())
|
.checkIgnoreMediaStore(requireContext())
|
||||||
.generatePalette(requireContext()).build()
|
.generatePalette(requireContext()).build()
|
||||||
.transform(BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat()).build())
|
.transform(BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat()).build())
|
||||||
|
@ -138,11 +147,9 @@ class CardBlurFragment : AbsPlayerFragment(), SharedPreferences.OnSharedPreferen
|
||||||
//.override(320, 480)
|
//.override(320, 480)
|
||||||
.into(object : RetroMusicColoredTarget(colorBackground) {
|
.into(object : RetroMusicColoredTarget(colorBackground) {
|
||||||
override fun onColorReady(color: Int) {
|
override fun onColorReady(color: Int) {
|
||||||
if (color == defaultFooterColor) {
|
|
||||||
colorBackground!!.setColorFilter(color)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})*/
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
|
|
|
@ -18,8 +18,8 @@ import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.ViewUtil
|
import code.name.monkey.retromusic.util.ViewUtil
|
||||||
import code.name.monkey.retromusic.views.DrawableGradient
|
import code.name.monkey.retromusic.views.DrawableGradient
|
||||||
import kotlinx.android.synthetic.main.fragment_player.*
|
import kotlinx.android.synthetic.main.fragment_player.colorGradientBackground
|
||||||
|
import kotlinx.android.synthetic.main.fragment_player.playerToolbar
|
||||||
|
|
||||||
class PlayerFragment : AbsPlayerFragment() {
|
class PlayerFragment : AbsPlayerFragment() {
|
||||||
|
|
||||||
|
@ -30,18 +30,21 @@ class PlayerFragment : AbsPlayerFragment() {
|
||||||
private lateinit var playbackControlsFragment: PlayerPlaybackControlsFragment
|
private lateinit var playbackControlsFragment: PlayerPlaybackControlsFragment
|
||||||
private var valueAnimator: ValueAnimator? = null
|
private var valueAnimator: ValueAnimator? = null
|
||||||
|
|
||||||
|
|
||||||
private fun colorize(i: Int) {
|
private fun colorize(i: Int) {
|
||||||
if (valueAnimator != null) {
|
if (valueAnimator != null) {
|
||||||
valueAnimator?.cancel()
|
valueAnimator?.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
valueAnimator = ValueAnimator.ofObject(ArgbEvaluator(), ATHUtil.resolveColor(requireContext(), R.attr.colorSurface), i)
|
valueAnimator = ValueAnimator.ofObject(ArgbEvaluator(), lastColor, i)
|
||||||
valueAnimator?.addUpdateListener { animation ->
|
valueAnimator?.addUpdateListener { animation ->
|
||||||
if (isAdded) {
|
if (isAdded) {
|
||||||
val drawable = DrawableGradient(GradientDrawable.Orientation.TOP_BOTTOM,
|
val drawable = DrawableGradient(
|
||||||
intArrayOf(animation.animatedValue as Int,
|
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||||
ATHUtil.resolveColor(requireContext(), R.attr.colorSurface)), 0)
|
intArrayOf(
|
||||||
|
animation.animatedValue as Int,
|
||||||
|
ATHUtil.resolveColor(requireContext(), R.attr.colorSurface)
|
||||||
|
), 0
|
||||||
|
)
|
||||||
colorGradientBackground?.background = drawable
|
colorGradientBackground?.background = drawable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +73,11 @@ class PlayerFragment : AbsPlayerFragment() {
|
||||||
lastColor = color
|
lastColor = color
|
||||||
callbacks?.onPaletteColorChanged()
|
callbacks?.onPaletteColorChanged()
|
||||||
|
|
||||||
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, ATHUtil.resolveColor(context, R.attr.colorControlNormal), requireActivity())
|
ToolbarContentTintHelper.colorizeToolbar(
|
||||||
|
playerToolbar,
|
||||||
|
ATHUtil.resolveColor(context, R.attr.colorControlNormal),
|
||||||
|
requireActivity()
|
||||||
|
)
|
||||||
|
|
||||||
if (PreferenceUtil.getInstance(requireContext()).adaptiveColor) {
|
if (PreferenceUtil.getInstance(requireContext()).adaptiveColor) {
|
||||||
colorize(color)
|
colorize(color)
|
||||||
|
@ -88,9 +95,10 @@ class PlayerFragment : AbsPlayerFragment() {
|
||||||
toggleFavorite(MusicPlayerRemote.currentSong)
|
toggleFavorite(MusicPlayerRemote.currentSong)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onCreateView(
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?): View? {
|
savedInstanceState: Bundle?
|
||||||
|
): View? {
|
||||||
|
|
||||||
return inflater.inflate(R.layout.fragment_player, container, false)
|
return inflater.inflate(R.layout.fragment_player, container, false)
|
||||||
}
|
}
|
||||||
|
@ -101,19 +109,24 @@ class PlayerFragment : AbsPlayerFragment() {
|
||||||
setUpPlayerToolbar()
|
setUpPlayerToolbar()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun setUpSubFragments() {
|
private fun setUpSubFragments() {
|
||||||
playbackControlsFragment = childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as PlayerPlaybackControlsFragment
|
playbackControlsFragment =
|
||||||
val playerAlbumCoverFragment = childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
|
childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as PlayerPlaybackControlsFragment
|
||||||
|
val playerAlbumCoverFragment =
|
||||||
|
childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
|
||||||
playerAlbumCoverFragment.setCallbacks(this)
|
playerAlbumCoverFragment.setCallbacks(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setUpPlayerToolbar() {
|
private fun setUpPlayerToolbar() {
|
||||||
playerToolbar.inflateMenu(R.menu.menu_player)
|
playerToolbar.inflateMenu(R.menu.menu_player)
|
||||||
playerToolbar.setNavigationOnClickListener {requireActivity().onBackPressed() }
|
playerToolbar.setNavigationOnClickListener { requireActivity().onBackPressed() }
|
||||||
playerToolbar.setOnMenuItemClickListener(this)
|
playerToolbar.setOnMenuItemClickListener(this)
|
||||||
|
|
||||||
ToolbarContentTintHelper.colorizeToolbar(playerToolbar, ATHUtil.resolveColor(context, R.attr.colorControlNormal), requireActivity())
|
ToolbarContentTintHelper.colorizeToolbar(
|
||||||
|
playerToolbar,
|
||||||
|
ATHUtil.resolveColor(context, R.attr.colorControlNormal),
|
||||||
|
requireActivity()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onServiceConnected() {
|
override fun onServiceConnected() {
|
||||||
|
|
|
@ -20,11 +20,9 @@ import code.name.monkey.appthemehelper.util.ATHUtil
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTarget
|
import code.name.monkey.retromusic.glide.palette.BitmapPaletteTarget
|
||||||
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
|
||||||
import code.name.monkey.retromusic.util.RetroColorUtil
|
import code.name.monkey.retromusic.util.RetroColorUtil
|
||||||
import com.bumptech.glide.request.animation.GlideAnimation
|
import com.bumptech.glide.request.animation.GlideAnimation
|
||||||
|
|
||||||
|
|
||||||
abstract class RetroMusicColoredTarget(view: ImageView) : BitmapPaletteTarget(view) {
|
abstract class RetroMusicColoredTarget(view: ImageView) : BitmapPaletteTarget(view) {
|
||||||
|
|
||||||
protected val defaultFooterColor: Int
|
protected val defaultFooterColor: Int
|
||||||
|
@ -40,15 +38,17 @@ abstract class RetroMusicColoredTarget(view: ImageView) : BitmapPaletteTarget(vi
|
||||||
onColorReady(defaultFooterColor)
|
onColorReady(defaultFooterColor)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResourceReady(resource: BitmapPaletteWrapper?, glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?) {
|
override fun onResourceReady(
|
||||||
|
resource: BitmapPaletteWrapper?,
|
||||||
|
glideAnimation: GlideAnimation<in BitmapPaletteWrapper>?
|
||||||
|
) {
|
||||||
super.onResourceReady(resource, glideAnimation)
|
super.onResourceReady(resource, glideAnimation)
|
||||||
val defaultColor = defaultFooterColor
|
val defaultColor = defaultFooterColor
|
||||||
|
|
||||||
resource?.let {
|
resource?.let {
|
||||||
onColorReady(if (PreferenceUtil.getInstance(getView().context).isDominantColor)
|
onColorReady(
|
||||||
RetroColorUtil.getDominantColor(it.bitmap, defaultColor)
|
RetroColorUtil.getColor(it.palette, defaultColor)
|
||||||
else
|
)
|
||||||
RetroColorUtil.getColor(it.palette, defaultColor))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ import android.database.Cursor
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.provider.BaseColumns
|
import android.provider.BaseColumns
|
||||||
import android.provider.MediaStore.Audio.Genres
|
import android.provider.MediaStore.Audio.Genres
|
||||||
import code.name.monkey.retromusic.Constants.BASE_SELECTION
|
import code.name.monkey.retromusic.Constants.baseSelection
|
||||||
import code.name.monkey.retromusic.Constants.baseProjection
|
import code.name.monkey.retromusic.Constants.baseProjection
|
||||||
import code.name.monkey.retromusic.model.Genre
|
import code.name.monkey.retromusic.model.Genre
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
|
@ -94,7 +94,7 @@ object GenreLoader {
|
||||||
try {
|
try {
|
||||||
return context.contentResolver.query(
|
return context.contentResolver.query(
|
||||||
Genres.Members.getContentUri("external", genreId.toLong()),
|
Genres.Members.getContentUri("external", genreId.toLong()),
|
||||||
baseProjection, BASE_SELECTION, null, PreferenceUtil.getInstance(context).songSortOrder)
|
baseProjection, baseSelection, null, PreferenceUtil.getInstance(context).songSortOrder)
|
||||||
} catch (e: SecurityException) {
|
} catch (e: SecurityException) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import android.content.Context
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.provider.MediaStore.Audio.AudioColumns
|
import android.provider.MediaStore.Audio.AudioColumns
|
||||||
import code.name.monkey.retromusic.Constants.BASE_SELECTION
|
import code.name.monkey.retromusic.Constants.baseSelection
|
||||||
import code.name.monkey.retromusic.model.AbsCustomPlaylist
|
import code.name.monkey.retromusic.model.AbsCustomPlaylist
|
||||||
import code.name.monkey.retromusic.model.Playlist
|
import code.name.monkey.retromusic.model.Playlist
|
||||||
import code.name.monkey.retromusic.model.PlaylistSong
|
import code.name.monkey.retromusic.model.PlaylistSong
|
||||||
|
@ -104,7 +104,7 @@ object PlaylistSongsLoader {
|
||||||
MediaStore.Audio.Playlists.Members._ID,//11
|
MediaStore.Audio.Playlists.Members._ID,//11
|
||||||
AudioColumns.COMPOSER
|
AudioColumns.COMPOSER
|
||||||
)// 12
|
)// 12
|
||||||
, BASE_SELECTION, null,
|
, baseSelection, null,
|
||||||
MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER
|
MediaStore.Audio.Playlists.Members.DEFAULT_SORT_ORDER
|
||||||
)
|
)
|
||||||
} catch (e: SecurityException) {
|
} catch (e: SecurityException) {
|
||||||
|
|
|
@ -18,10 +18,9 @@ import android.content.Context
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import android.provider.MediaStore.Audio.AudioColumns
|
import android.provider.MediaStore.Audio.AudioColumns
|
||||||
import code.name.monkey.retromusic.Constants.BASE_SELECTION
|
|
||||||
import code.name.monkey.retromusic.Constants.baseProjection
|
import code.name.monkey.retromusic.Constants.baseProjection
|
||||||
|
import code.name.monkey.retromusic.Constants.baseSelection
|
||||||
import code.name.monkey.retromusic.model.Song
|
import code.name.monkey.retromusic.model.Song
|
||||||
import code.name.monkey.retromusic.providers.BlacklistStore
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import java.util.ArrayList
|
import java.util.ArrayList
|
||||||
|
|
||||||
|
@ -61,7 +60,7 @@ object SongLoader {
|
||||||
return getSongs(cursor)
|
return getSongs(cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSong(
|
private fun getSong(
|
||||||
cursor: Cursor?
|
cursor: Cursor?
|
||||||
): Song {
|
): Song {
|
||||||
val song: Song
|
val song: Song
|
||||||
|
@ -84,71 +83,70 @@ object SongLoader {
|
||||||
cursor: Cursor
|
cursor: Cursor
|
||||||
): Song = Song.fromCursor(cursor)
|
): Song = Song.fromCursor(cursor)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun makeSongCursor(
|
fun makeSongCursor(
|
||||||
context: Context,
|
context: Context,
|
||||||
selection: String?,
|
selectionString: String?,
|
||||||
selectionValues: Array<String>?,
|
selectionValuesArray: Array<String>?,
|
||||||
sortOrder: String = PreferenceUtil.getInstance(context).songSortOrder
|
sortOrder: String = PreferenceUtil.getInstance(context).songSortOrder
|
||||||
): Cursor? {
|
): Cursor {
|
||||||
var selectionFinal = selection
|
var selectionValues: Array<String>? = arrayOf()
|
||||||
var selectionValuesFinal = selectionValues
|
var selection = if (selectionString != null && selectionString.trim() != "") {
|
||||||
selectionFinal = if (selection != null && selection.trim { it <= ' ' } != "") {
|
"$baseSelection AND $selectionString"
|
||||||
"$BASE_SELECTION AND $selectionFinal"
|
|
||||||
} else {
|
} else {
|
||||||
BASE_SELECTION
|
baseSelection
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blacklist
|
// Blacklist
|
||||||
val paths = BlacklistStore.getInstance(context).paths
|
/*val paths = BlacklistStore.getInstance(context).paths
|
||||||
if (paths.isNotEmpty()) {
|
if (paths.isNotEmpty()) {
|
||||||
selectionFinal = generateBlacklistSelection(selectionFinal, paths.size)
|
selection = generateBlacklistSelection(selection, paths.size)
|
||||||
selectionValuesFinal = addBlacklistSelectionValues(selectionValuesFinal, paths)
|
selectionValues = addBlacklistSelectionValues(selectionValuesArray, paths)
|
||||||
|
}*/
|
||||||
|
if (PreferenceUtil.getInstance(context).filterLength != 0) {
|
||||||
|
selection =
|
||||||
|
"$selection AND ${MediaStore.Audio.Media.DURATION} >= ${PreferenceUtil.getInstance(context).filterLength * 1000}"
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
return context.contentResolver.query(
|
||||||
return context.contentResolver.query(
|
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
|
||||||
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
|
baseProjection,
|
||||||
baseProjection,
|
selection,
|
||||||
selectionFinal + " AND " + MediaStore.Audio.Media.DURATION + ">= " + (PreferenceUtil.getInstance(
|
selectionValuesArray,
|
||||||
context
|
sortOrder
|
||||||
).filterLength * 1000),
|
)
|
||||||
selectionValuesFinal,
|
?: throw IllegalStateException("Unable to query ${MediaStore.Audio.Media.EXTERNAL_CONTENT_URI}, system returned null.")
|
||||||
sortOrder
|
|
||||||
)
|
|
||||||
} catch (e: SecurityException) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun generateBlacklistSelection(
|
|
||||||
selection: String?,
|
|
||||||
pathCount: Int
|
|
||||||
): String {
|
|
||||||
val newSelection = StringBuilder(
|
|
||||||
if (selection != null && selection.trim { it <= ' ' } != "") "$selection AND " else "")
|
|
||||||
newSelection.append(AudioColumns.DATA + " NOT LIKE ?")
|
|
||||||
for (i in 0 until pathCount - 1) {
|
|
||||||
newSelection.append(" AND " + AudioColumns.DATA + " NOT LIKE ?")
|
|
||||||
}
|
|
||||||
return newSelection.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addBlacklistSelectionValues(
|
|
||||||
selectionValues: Array<String>?,
|
|
||||||
paths: ArrayList<String>
|
|
||||||
): Array<String>? {
|
|
||||||
var selectionValuesFinal = selectionValues
|
|
||||||
if (selectionValuesFinal == null) {
|
|
||||||
selectionValuesFinal = emptyArray()
|
|
||||||
}
|
|
||||||
val newSelectionValues = Array(selectionValuesFinal.size + paths.size) {
|
|
||||||
"n = $it"
|
|
||||||
}
|
|
||||||
System.arraycopy(selectionValuesFinal, 0, newSelectionValues, 0, selectionValuesFinal.size)
|
|
||||||
for (i in selectionValuesFinal.size until newSelectionValues.size) {
|
|
||||||
newSelectionValues[i] = paths[i - selectionValuesFinal.size] + "%"
|
|
||||||
}
|
|
||||||
return newSelectionValues
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun generateBlacklistSelection(
|
||||||
|
selection: String?,
|
||||||
|
pathCount: Int
|
||||||
|
): String {
|
||||||
|
val newSelection = StringBuilder(
|
||||||
|
if (selection != null && selection.trim { it <= ' ' } != "") "$selection AND " else "")
|
||||||
|
newSelection.append(AudioColumns.DATA + " NOT LIKE ?")
|
||||||
|
for (i in 0 until pathCount - 1) {
|
||||||
|
newSelection.append(" AND " + AudioColumns.DATA + " NOT LIKE ?")
|
||||||
|
}
|
||||||
|
return newSelection.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addBlacklistSelectionValues(
|
||||||
|
selectionValues: Array<String>?,
|
||||||
|
paths: ArrayList<String>
|
||||||
|
): Array<String>? {
|
||||||
|
var selectionValuesFinal = selectionValues
|
||||||
|
if (selectionValuesFinal == null) {
|
||||||
|
selectionValuesFinal = emptyArray()
|
||||||
|
}
|
||||||
|
val newSelectionValues = Array(selectionValuesFinal.size + paths.size) {
|
||||||
|
"n = $it"
|
||||||
|
}
|
||||||
|
System.arraycopy(selectionValuesFinal, 0, newSelectionValues, 0, selectionValuesFinal.size)
|
||||||
|
for (i in selectionValuesFinal.size until newSelectionValues.size) {
|
||||||
|
newSelectionValues[i] = paths[i - selectionValuesFinal.size] + "%"
|
||||||
|
}
|
||||||
|
return newSelectionValues
|
||||||
|
}
|
|
@ -27,52 +27,6 @@ class Artist(
|
||||||
var albumCount: Int = 0
|
var albumCount: Int = 0
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/*val albums: ArrayList<Album>?
|
|
||||||
|
|
||||||
val id: Int
|
|
||||||
get() = safeGetFirstAlbum().artistId
|
|
||||||
|
|
||||||
val name: String
|
|
||||||
get() {
|
|
||||||
val name = safeGetFirstAlbum().artist
|
|
||||||
return if (MusicUtil.isArtistNameUnknown(name)) {
|
|
||||||
UNKNOWN_ARTIST_DISPLAY_NAME
|
|
||||||
} else name!!
|
|
||||||
}
|
|
||||||
|
|
||||||
val songCount: Int
|
|
||||||
get() {
|
|
||||||
var songCount = 0
|
|
||||||
for (album in albums!!) {
|
|
||||||
songCount += album.songCount
|
|
||||||
}
|
|
||||||
return songCount
|
|
||||||
}
|
|
||||||
|
|
||||||
val albumCount: Int
|
|
||||||
get() = albums!!.size
|
|
||||||
|
|
||||||
val songs: ArrayList<Song>
|
|
||||||
get() {
|
|
||||||
val songs = ArrayList<Song>()
|
|
||||||
for (album in albums!!) {
|
|
||||||
//songs.addAll(album.songs!!)
|
|
||||||
}
|
|
||||||
return songs
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(albums: ArrayList<Album>) {
|
|
||||||
this.albums = albums
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.albums = ArrayList()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun safeGetFirstAlbum(): Album {
|
|
||||||
return if (albums!!.isEmpty()) Album() else albums[0]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun fromCursor(cursor: Cursor): Artist {
|
fun fromCursor(cursor: Cursor): Artist {
|
||||||
|
|
|
@ -41,7 +41,12 @@ class BlacklistPreference : ATEDialogPreference {
|
||||||
|
|
||||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
||||||
|
|
||||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
|
||||||
|
context,
|
||||||
|
attrs,
|
||||||
|
defStyleAttr,
|
||||||
|
defStyleRes
|
||||||
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
icon?.setColorFilter(ThemeStore.textColorSecondary(context), PorterDuff.Mode.SRC_IN)
|
icon?.setColorFilter(ThemeStore.textColorSecondary(context), PorterDuff.Mode.SRC_IN)
|
||||||
|
@ -55,23 +60,23 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val blacklistFolderChooserDialog = childFragmentManager.findFragmentByTag("FOLDER_CHOOSER") as BlacklistFolderChooserDialog?
|
val blacklistFolderChooserDialog =
|
||||||
|
childFragmentManager.findFragmentByTag("FOLDER_CHOOSER") as BlacklistFolderChooserDialog?
|
||||||
blacklistFolderChooserDialog?.setCallback(this)
|
blacklistFolderChooserDialog?.setCallback(this)
|
||||||
refreshBlacklistData()
|
refreshBlacklistData()
|
||||||
return MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
|
return MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
|
||||||
title(code.name.monkey.retromusic.R.string.blacklist)
|
title(R.string.blacklist)
|
||||||
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
|
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
|
||||||
positiveButton(android.R.string.ok) {
|
positiveButton(android.R.string.ok) {
|
||||||
dismiss()
|
dismiss()
|
||||||
}
|
}
|
||||||
neutralButton(text = getString(R.string.clear_action)) {
|
neutralButton(text = getString(R.string.clear_action)) {
|
||||||
MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
|
MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
|
||||||
title(code.name.monkey.retromusic.R.string.clear_blacklist)
|
title(R.string.clear_blacklist)
|
||||||
message(code.name.monkey.retromusic.R.string.do_you_want_to_clear_the_blacklist)
|
message(R.string.do_you_want_to_clear_the_blacklist)
|
||||||
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
|
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
|
||||||
positiveButton(code.name.monkey.retromusic.R.string.clear_action) {
|
positiveButton(R.string.clear_action) {
|
||||||
BlacklistStore.getInstance(context).clear()
|
BlacklistStore.getInstance(context).clear()
|
||||||
refreshBlacklistData()
|
refreshBlacklistData()
|
||||||
}
|
}
|
||||||
|
@ -81,13 +86,20 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
|
||||||
negativeButton(R.string.add_action) {
|
negativeButton(R.string.add_action) {
|
||||||
val dialog = BlacklistFolderChooserDialog.create()
|
val dialog = BlacklistFolderChooserDialog.create()
|
||||||
dialog.setCallback(this@BlacklistPreferenceDialog)
|
dialog.setCallback(this@BlacklistPreferenceDialog)
|
||||||
dialog.show(childFragmentManager, "FOLDER_CHOOSER");
|
dialog.show(childFragmentManager, "FOLDER_CHOOSER")
|
||||||
}
|
}
|
||||||
listItems(items = paths, waitForPositiveButton = false) { _, _, text ->
|
listItems(items = paths, waitForPositiveButton = false) { _, _, text ->
|
||||||
MaterialDialog(context, BottomSheet(LayoutMode.WRAP_CONTENT)).show {
|
MaterialDialog(requireContext(), BottomSheet(LayoutMode.WRAP_CONTENT)).show {
|
||||||
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
|
cornerRadius(PreferenceUtil.getInstance(requireContext()).dialogCorner)
|
||||||
title(code.name.monkey.retromusic.R.string.remove_from_blacklist)
|
title(R.string.remove_from_blacklist)
|
||||||
message(text = Html.fromHtml(getString(code.name.monkey.retromusic.R.string.do_you_want_to_remove_from_the_blacklist, text)))
|
message(
|
||||||
|
text = Html.fromHtml(
|
||||||
|
getString(
|
||||||
|
R.string.do_you_want_to_remove_from_the_blacklist,
|
||||||
|
text
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
positiveButton(code.name.monkey.retromusic.R.string.remove_action) {
|
positiveButton(code.name.monkey.retromusic.R.string.remove_action) {
|
||||||
BlacklistStore.getInstance(context).removePath(File(text.toString()))
|
BlacklistStore.getInstance(context).removePath(File(text.toString()))
|
||||||
refreshBlacklistData()
|
refreshBlacklistData()
|
||||||
|
@ -108,7 +120,7 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFolderSelection(dialog: BlacklistFolderChooserDialog, folder: File) {
|
override fun onFolderSelection(dialog: BlacklistFolderChooserDialog, folder: File) {
|
||||||
BlacklistStore.getInstance(context!!).addPath(folder);
|
BlacklistStore.getInstance(context!!).addPath(folder)
|
||||||
refreshBlacklistData();
|
refreshBlacklistData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ package code.name.monkey.retromusic.preferences
|
||||||
|
|
||||||
import android.app.Dialog
|
import android.app.Dialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.content.res.ColorStateList
|
||||||
import android.graphics.PorterDuff
|
import android.graphics.PorterDuff
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
@ -30,8 +31,12 @@ import androidx.viewpager.widget.PagerAdapter
|
||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEDialogPreference
|
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEDialogPreference
|
||||||
|
import code.name.monkey.appthemehelper.util.ColorUtil
|
||||||
|
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||||
import code.name.monkey.retromusic.App
|
import code.name.monkey.retromusic.App
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
|
import code.name.monkey.retromusic.extensions.hide
|
||||||
|
import code.name.monkey.retromusic.extensions.show
|
||||||
import code.name.monkey.retromusic.fragments.NowPlayingScreen
|
import code.name.monkey.retromusic.fragments.NowPlayingScreen
|
||||||
import code.name.monkey.retromusic.util.NavigationUtil
|
import code.name.monkey.retromusic.util.NavigationUtil
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
@ -42,18 +47,23 @@ import com.bumptech.glide.Glide
|
||||||
|
|
||||||
class NowPlayingScreenPreference : ATEDialogPreference {
|
class NowPlayingScreenPreference : ATEDialogPreference {
|
||||||
|
|
||||||
constructor(context: Context) : super(context) {}
|
constructor(context: Context) : super(context)
|
||||||
|
|
||||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
|
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||||
|
|
||||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
|
||||||
|
|
||||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {}
|
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
|
||||||
|
context,
|
||||||
|
attrs,
|
||||||
|
defStyleAttr,
|
||||||
|
defStyleRes
|
||||||
|
)
|
||||||
|
|
||||||
private val mLayoutRes = R.layout.preference_dialog_now_playing_screen
|
private val mLayoutRes = R.layout.preference_dialog_now_playing_screen
|
||||||
|
|
||||||
override fun getDialogLayoutResource(): Int {
|
override fun getDialogLayoutResource(): Int {
|
||||||
return mLayoutRes;
|
return mLayoutRes
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -66,11 +76,9 @@ class NowPlayingScreenPreferenceDialog : PreferenceDialogFragmentCompat(), ViewP
|
||||||
private var viewPagerPosition: Int = 0
|
private var viewPagerPosition: Int = 0
|
||||||
|
|
||||||
override fun onPageScrollStateChanged(state: Int) {
|
override fun onPageScrollStateChanged(state: Int) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPageSelected(position: Int) {
|
override fun onPageSelected(position: Int) {
|
||||||
|
@ -78,13 +86,12 @@ class NowPlayingScreenPreferenceDialog : PreferenceDialogFragmentCompat(), ViewP
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDialogClosed(positiveResult: Boolean) {
|
override fun onDialogClosed(positiveResult: Boolean) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val view = LayoutInflater.from(activity).inflate(R.layout.preference_dialog_now_playing_screen, null)
|
val view = LayoutInflater.from(activity).inflate(R.layout.preference_dialog_now_playing_screen, null)
|
||||||
val viewPager = view.findViewById<ViewPager>(R.id.now_playing_screen_view_pager)
|
val viewPager = view.findViewById<ViewPager>(R.id.now_playing_screen_view_pager)
|
||||||
?: throw IllegalStateException("Dialog view must contain a ViewPager with id 'now_playing_screen_view_pager'")
|
?: throw IllegalStateException("Dialog view must contain a ViewPager with id 'now_playing_screen_view_pager'")
|
||||||
viewPager.adapter = NowPlayingScreenAdapter(activity!!)
|
viewPager.adapter = NowPlayingScreenAdapter(activity!!)
|
||||||
viewPager.addOnPageChangeListener(this)
|
viewPager.addOnPageChangeListener(this)
|
||||||
viewPager.pageMargin = ViewUtil.convertDpToPixel(32f, resources).toInt()
|
viewPager.pageMargin = ViewUtil.convertDpToPixel(32f, resources).toInt()
|
||||||
|
@ -109,24 +116,6 @@ class NowPlayingScreenPreferenceDialog : PreferenceDialogFragmentCompat(), ViewP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isNowPlayingThemes(nowPlayingScreen: NowPlayingScreen): Boolean {
|
|
||||||
if (nowPlayingScreen == NowPlayingScreen.BLUR_CARD) {
|
|
||||||
PreferenceUtil.getInstance(requireContext()).resetCarouselEffect()
|
|
||||||
PreferenceUtil.getInstance(requireContext()).resetCircularAlbumArt()
|
|
||||||
}
|
|
||||||
|
|
||||||
return (nowPlayingScreen == NowPlayingScreen.FULL ||
|
|
||||||
nowPlayingScreen == NowPlayingScreen.CARD ||
|
|
||||||
nowPlayingScreen == NowPlayingScreen.PLAIN ||
|
|
||||||
nowPlayingScreen == NowPlayingScreen.BLUR ||
|
|
||||||
nowPlayingScreen == NowPlayingScreen.COLOR ||
|
|
||||||
nowPlayingScreen == NowPlayingScreen.SIMPLE ||
|
|
||||||
nowPlayingScreen == NowPlayingScreen.BLUR_CARD ||
|
|
||||||
nowPlayingScreen == NowPlayingScreen.CIRCLE ||
|
|
||||||
nowPlayingScreen == NowPlayingScreen.ADAPTIVE)
|
|
||||||
&& !App.isProVersion()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun newInstance(key: String): NowPlayingScreenPreferenceDialog {
|
fun newInstance(key: String): NowPlayingScreenPreferenceDialog {
|
||||||
val bundle = Bundle()
|
val bundle = Bundle()
|
||||||
|
@ -138,7 +127,7 @@ class NowPlayingScreenPreferenceDialog : PreferenceDialogFragmentCompat(), ViewP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NowPlayingScreenAdapter internal constructor(private val context: Context) : PagerAdapter() {
|
private class NowPlayingScreenAdapter(private val context: Context) : PagerAdapter() {
|
||||||
|
|
||||||
override fun instantiateItem(collection: ViewGroup, position: Int): Any {
|
override fun instantiateItem(collection: ViewGroup, position: Int): Any {
|
||||||
val nowPlayingScreen = NowPlayingScreen.values()[position]
|
val nowPlayingScreen = NowPlayingScreen.values()[position]
|
||||||
|
@ -148,16 +137,26 @@ private class NowPlayingScreenAdapter internal constructor(private val context:
|
||||||
collection.addView(layout)
|
collection.addView(layout)
|
||||||
|
|
||||||
val image = layout.findViewById<ImageView>(R.id.image)
|
val image = layout.findViewById<ImageView>(R.id.image)
|
||||||
|
val proText = layout.findViewById<TextView>(R.id.proText)
|
||||||
val title = layout.findViewById<TextView>(R.id.title)
|
val title = layout.findViewById<TextView>(R.id.title)
|
||||||
Glide.with(context).load(nowPlayingScreen.drawableResId).into(image)
|
Glide.with(context).load(nowPlayingScreen.drawableResId).into(image)
|
||||||
title.setText(nowPlayingScreen.titleRes)
|
title.setText(nowPlayingScreen.titleRes)
|
||||||
|
if (isNowPlayingThemes(nowPlayingScreen)) {
|
||||||
|
proText.show()
|
||||||
|
} else {
|
||||||
|
proText.hide()
|
||||||
|
}
|
||||||
|
val color = ThemeStore.accentColor(context)
|
||||||
|
proText.backgroundTintList = ColorStateList.valueOf(color)
|
||||||
|
proText.setTextColor(MaterialValueHelper.getPrimaryTextColor(context,ColorUtil.isColorLight(color)))
|
||||||
return layout
|
return layout
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun destroyItem(collection: ViewGroup,
|
override fun destroyItem(
|
||||||
position: Int,
|
collection: ViewGroup,
|
||||||
view: Any) {
|
position: Int,
|
||||||
|
view: Any
|
||||||
|
) {
|
||||||
collection.removeView(view as View)
|
collection.removeView(view as View)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,3 +172,18 @@ private class NowPlayingScreenAdapter internal constructor(private val context:
|
||||||
return context.getString(NowPlayingScreen.values()[position].titleRes)
|
return context.getString(NowPlayingScreen.values()[position].titleRes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isNowPlayingThemes(nowPlayingScreen: NowPlayingScreen): Boolean {
|
||||||
|
return (nowPlayingScreen == NowPlayingScreen.FULL ||
|
||||||
|
nowPlayingScreen == NowPlayingScreen.CARD ||
|
||||||
|
nowPlayingScreen == NowPlayingScreen.PLAIN ||
|
||||||
|
nowPlayingScreen == NowPlayingScreen.BLUR ||
|
||||||
|
nowPlayingScreen == NowPlayingScreen.COLOR ||
|
||||||
|
nowPlayingScreen == NowPlayingScreen.SIMPLE ||
|
||||||
|
nowPlayingScreen == NowPlayingScreen.BLUR_CARD ||
|
||||||
|
nowPlayingScreen == NowPlayingScreen.CIRCLE ||
|
||||||
|
nowPlayingScreen == NowPlayingScreen.ADAPTIVE ||
|
||||||
|
nowPlayingScreen == NowPlayingScreen.MATERIAL ||
|
||||||
|
nowPlayingScreen == NowPlayingScreen.PEAK)
|
||||||
|
&& !App.isProVersion()
|
||||||
|
}
|
||||||
|
|
|
@ -19,10 +19,11 @@ import android.database.Cursor;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.provider.MediaStore;
|
import android.provider.MediaStore;
|
||||||
import android.webkit.MimeTypeMap;
|
import android.webkit.MimeTypeMap;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import code.name.monkey.retromusic.loaders.SongLoader;
|
||||||
|
import code.name.monkey.retromusic.loaders.SortedCursor;
|
||||||
|
import code.name.monkey.retromusic.model.Song;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -37,137 +38,9 @@ import java.util.Collections;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import code.name.monkey.retromusic.loaders.SongLoader;
|
|
||||||
import code.name.monkey.retromusic.loaders.SortedCursor;
|
|
||||||
import code.name.monkey.retromusic.model.Song;
|
|
||||||
|
|
||||||
|
|
||||||
public final class FileUtil {
|
public final class FileUtil {
|
||||||
|
|
||||||
private FileUtil() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static byte[] readBytes(InputStream stream) throws IOException {
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
byte[] buffer = new byte[4096];
|
|
||||||
int count;
|
|
||||||
while ((count = stream.read(buffer)) != -1) {
|
|
||||||
baos.write(buffer, 0, count);
|
|
||||||
}
|
|
||||||
stream.close();
|
|
||||||
return baos.toByteArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static ArrayList<Song> matchFilesWithMediaStore(@NonNull Context context,
|
|
||||||
@Nullable List<File> files) {
|
|
||||||
return SongLoader.INSTANCE.getSongs(makeSongCursor(context, files));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String safeGetCanonicalPath(File file) {
|
|
||||||
try {
|
|
||||||
return file.getCanonicalPath();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return file.getAbsolutePath();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static SortedCursor makeSongCursor(@NonNull final Context context,
|
|
||||||
@Nullable final List<File> files) {
|
|
||||||
String selection = null;
|
|
||||||
String[] paths = null;
|
|
||||||
|
|
||||||
if (files != null) {
|
|
||||||
paths = toPathArray(files);
|
|
||||||
|
|
||||||
if (files.size() > 0
|
|
||||||
&& files.size() < 999) { // 999 is the max amount Androids SQL implementation can handle.
|
|
||||||
selection =
|
|
||||||
MediaStore.Audio.AudioColumns.DATA + " IN (" + makePlaceholders(files.size()) + ")";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Cursor songCursor = SongLoader.INSTANCE.makeSongCursor(context, selection, selection == null ? null : paths);
|
|
||||||
|
|
||||||
return songCursor == null ? null
|
|
||||||
: new SortedCursor(songCursor, paths, MediaStore.Audio.AudioColumns.DATA);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String makePlaceholders(int len) {
|
|
||||||
StringBuilder sb = new StringBuilder(len * 2 - 1);
|
|
||||||
sb.append("?");
|
|
||||||
for (int i = 1; i < len; i++) {
|
|
||||||
sb.append(",?");
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private static String[] toPathArray(@Nullable List<File> files) {
|
|
||||||
if (files != null) {
|
|
||||||
String[] paths = new String[files.size()];
|
|
||||||
for (int i = 0; i < files.size(); i++) {
|
|
||||||
/*try {
|
|
||||||
paths[i] = files.get(i).getCanonicalPath(); // canonical path is important here because we want to compare the path with the media store entry later
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
paths[i] = files.get(i).getPath();
|
|
||||||
}*/
|
|
||||||
paths[i] = safeGetCanonicalPath(files.get(i));
|
|
||||||
}
|
|
||||||
return paths;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static List<File> listFiles(@NonNull File directory, @Nullable FileFilter fileFilter) {
|
|
||||||
List<File> fileList = new LinkedList<>();
|
|
||||||
File[] found = directory.listFiles(fileFilter);
|
|
||||||
if (found != null) {
|
|
||||||
Collections.addAll(fileList, found);
|
|
||||||
}
|
|
||||||
return fileList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static List<File> listFilesDeep(@NonNull File directory, @Nullable FileFilter fileFilter) {
|
|
||||||
List<File> files = new LinkedList<>();
|
|
||||||
internalListFilesDeep(files, directory, fileFilter);
|
|
||||||
return files;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
public static List<File> listFilesDeep(@NonNull Collection<File> files,
|
|
||||||
@Nullable FileFilter fileFilter) {
|
|
||||||
List<File> resFiles = new LinkedList<>();
|
|
||||||
for (File file : files) {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
internalListFilesDeep(resFiles, file, fileFilter);
|
|
||||||
} else if (fileFilter == null || fileFilter.accept(file)) {
|
|
||||||
resFiles.add(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return resFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void internalListFilesDeep(@NonNull Collection<File> files,
|
|
||||||
@NonNull File directory, @Nullable FileFilter fileFilter) {
|
|
||||||
File[] found = directory.listFiles(fileFilter);
|
|
||||||
|
|
||||||
if (found != null) {
|
|
||||||
for (File file : found) {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
internalListFilesDeep(files, file, fileFilter);
|
|
||||||
} else {
|
|
||||||
files.add(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean fileIsMimeType(File file, String mimeType, MimeTypeMap mimeTypeMap) {
|
public static boolean fileIsMimeType(File file, String mimeType, MimeTypeMap mimeTypeMap) {
|
||||||
if (mimeType == null || mimeType.equals("*/*")) {
|
if (mimeType == null || mimeType.equals("*/*")) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -209,15 +82,95 @@ public final class FileUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String stripExtension(String str) {
|
public static boolean isExternalMemoryAvailable() {
|
||||||
if (str == null) {
|
Boolean isSDPresent = Environment.getExternalStorageState()
|
||||||
return null;
|
.equals(android.os.Environment.MEDIA_MOUNTED);
|
||||||
|
Boolean isSDSupportedDevice = Environment.isExternalStorageRemovable();
|
||||||
|
|
||||||
|
if (isSDSupportedDevice && isSDPresent) {
|
||||||
|
// yes SD-card is present
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
// Sorry
|
||||||
}
|
}
|
||||||
int pos = str.lastIndexOf('.');
|
}
|
||||||
if (pos == -1) {
|
|
||||||
return str;
|
@NonNull
|
||||||
|
public static List<File> listFiles(@NonNull File directory, @Nullable FileFilter fileFilter) {
|
||||||
|
List<File> fileList = new LinkedList<>();
|
||||||
|
File[] found = directory.listFiles(fileFilter);
|
||||||
|
if (found != null) {
|
||||||
|
Collections.addAll(fileList, found);
|
||||||
}
|
}
|
||||||
return str.substring(0, pos);
|
return fileList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static List<File> listFilesDeep(@NonNull File directory, @Nullable FileFilter fileFilter) {
|
||||||
|
List<File> files = new LinkedList<>();
|
||||||
|
internalListFilesDeep(files, directory, fileFilter);
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static List<File> listFilesDeep(@NonNull Collection<File> files,
|
||||||
|
@Nullable FileFilter fileFilter) {
|
||||||
|
List<File> resFiles = new LinkedList<>();
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
internalListFilesDeep(resFiles, file, fileFilter);
|
||||||
|
} else if (fileFilter == null || fileFilter.accept(file)) {
|
||||||
|
resFiles.add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static SortedCursor makeSongCursor(@NonNull final Context context,
|
||||||
|
@Nullable final List<File> files) {
|
||||||
|
String selection = null;
|
||||||
|
String[] paths = null;
|
||||||
|
|
||||||
|
if (files != null) {
|
||||||
|
paths = toPathArray(files);
|
||||||
|
|
||||||
|
if (files.size() > 0
|
||||||
|
&& files.size() < 999) { // 999 is the max amount Androids SQL implementation can handle.
|
||||||
|
selection =
|
||||||
|
MediaStore.Audio.AudioColumns.DATA + " IN (" + makePlaceholders(files.size()) + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Cursor songCursor = SongLoader.makeSongCursor(context, selection, selection == null ? null : paths);
|
||||||
|
|
||||||
|
return songCursor == null ? null
|
||||||
|
: new SortedCursor(songCursor, paths, MediaStore.Audio.AudioColumns.DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static ArrayList<Song> matchFilesWithMediaStore(@NonNull Context context,
|
||||||
|
@Nullable List<File> files) {
|
||||||
|
return SongLoader.INSTANCE.getSongs(makeSongCursor(context, files));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String read(File file) throws Exception {
|
||||||
|
FileInputStream fin = new FileInputStream(file);
|
||||||
|
String ret = readFromStream(fin);
|
||||||
|
fin.close();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] readBytes(InputStream stream) throws IOException {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int count;
|
||||||
|
while ((count = stream.read(buffer)) != -1) {
|
||||||
|
baos.write(buffer, 0, count);
|
||||||
|
}
|
||||||
|
stream.close();
|
||||||
|
return baos.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String readFromStream(InputStream is) throws Exception {
|
public static String readFromStream(InputStream is) throws Exception {
|
||||||
|
@ -234,27 +187,6 @@ public final class FileUtil {
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String read(File file) throws Exception {
|
|
||||||
FileInputStream fin = new FileInputStream(file);
|
|
||||||
String ret = readFromStream(fin);
|
|
||||||
fin.close();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isExternalMemoryAvailable() {
|
|
||||||
Boolean isSDPresent = Environment.getExternalStorageState()
|
|
||||||
.equals(android.os.Environment.MEDIA_MOUNTED);
|
|
||||||
Boolean isSDSupportedDevice = Environment.isExternalStorageRemovable();
|
|
||||||
|
|
||||||
if (isSDSupportedDevice && isSDPresent) {
|
|
||||||
// yes SD-card is present
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
// Sorry
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File safeGetCanonicalFile(File file) {
|
public static File safeGetCanonicalFile(File file) {
|
||||||
try {
|
try {
|
||||||
return file.getCanonicalFile();
|
return file.getCanonicalFile();
|
||||||
|
@ -264,5 +196,70 @@ public final class FileUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String safeGetCanonicalPath(File file) {
|
||||||
|
try {
|
||||||
|
return file.getCanonicalPath();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return file.getAbsolutePath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String stripExtension(String str) {
|
||||||
|
if (str == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int pos = str.lastIndexOf('.');
|
||||||
|
if (pos == -1) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
return str.substring(0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FileUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void internalListFilesDeep(@NonNull Collection<File> files,
|
||||||
|
@NonNull File directory, @Nullable FileFilter fileFilter) {
|
||||||
|
File[] found = directory.listFiles(fileFilter);
|
||||||
|
|
||||||
|
if (found != null) {
|
||||||
|
for (File file : found) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
internalListFilesDeep(files, file, fileFilter);
|
||||||
|
} else {
|
||||||
|
files.add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String makePlaceholders(int len) {
|
||||||
|
StringBuilder sb = new StringBuilder(len * 2 - 1);
|
||||||
|
sb.append("?");
|
||||||
|
for (int i = 1; i < len; i++) {
|
||||||
|
sb.append(",?");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private static String[] toPathArray(@Nullable List<File> files) {
|
||||||
|
if (files != null) {
|
||||||
|
String[] paths = new String[files.size()];
|
||||||
|
for (int i = 0; i < files.size(); i++) {
|
||||||
|
/*try {
|
||||||
|
paths[i] = files.get(i).getCanonicalPath(); // canonical path is important here because we want to compare the path with the media store entry later
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
paths[i] = files.get(i).getPath();
|
||||||
|
}*/
|
||||||
|
paths[i] = safeGetCanonicalPath(files.get(i));
|
||||||
|
}
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,21 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
~ Copyright (c) 2020 Hemanth Savarala.
|
||||||
android:shape="oval">
|
~
|
||||||
<corners android:radius="35dp"/>
|
~ Licensed under the GNU General Public License v3
|
||||||
<stroke
|
~
|
||||||
android:color="@color/md_white_1000"
|
~ This is free software: you can redistribute it and/or modify it under
|
||||||
android:width="2dp"/>
|
~ 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<corners android:radius="4dp" />
|
||||||
|
<stroke
|
||||||
|
android:width="2dp"
|
||||||
|
android:color="?attr/colorAccent" />
|
||||||
|
|
||||||
</shape>
|
</shape>
|
|
@ -4,6 +4,7 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true">
|
android:focusable="true">
|
||||||
|
|
||||||
|
@ -18,10 +19,6 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/shadow_up_full_theme" />
|
android:background="@drawable/shadow_up_full_theme" />
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/mask"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|
|
@ -5,20 +5,16 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
android:focusable="true">
|
android:focusable="true">
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/colorBackground"
|
android:id="@+id/colorBackground"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:background="?attr/colorSurface"
|
||||||
android:scaleType="centerCrop" />
|
android:scaleType="centerCrop" />
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/mask"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="#20000000" />
|
|
||||||
|
|
||||||
<include layout="@layout/shadow_statusbar_toolbar" />
|
<include layout="@layout/shadow_statusbar_toolbar" />
|
||||||
|
|
||||||
|
|
||||||
|
@ -86,5 +82,4 @@
|
||||||
tools:layout="@layout/fragment_card_blur_player_playback_controls" />
|
tools:layout="@layout/fragment_card_blur_player_playback_controls" />
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
|
@ -25,10 +25,25 @@
|
||||||
android:id="@+id/image"
|
android:id="@+id/image"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toTopOf="@id/proText"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/title"
|
app:layout_constraintTop_toBottomOf="@+id/title"
|
||||||
tools:src="@tools:sample/backgrounds/scenic" />
|
tools:src="@tools:sample/backgrounds/scenic" />
|
||||||
|
|
||||||
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
android:id="@+id/proText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/line_button"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingEnd="16dp"
|
||||||
|
android:paddingBottom="8dp"
|
||||||
|
android:text="@string/pro"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
tools:visibility="visible" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -826,4 +826,5 @@
|
||||||
<string name="drive_mode">Drive mode</string>
|
<string name="drive_mode">Drive mode</string>
|
||||||
<string name="retro_music_player">Retro Music Player</string>
|
<string name="retro_music_player">Retro Music Player</string>
|
||||||
<string name="sort_num_songs">Number of songs</string>
|
<string name="sort_num_songs">Number of songs</string>
|
||||||
|
<string name="pro">Pro</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
<code.name.monkey.retromusic.preferences.BlacklistPreference
|
<code.name.monkey.retromusic.preferences.BlacklistPreference
|
||||||
android:key="blacklist"
|
android:key="blacklist"
|
||||||
|
app:enabled="false"
|
||||||
android:layout="@layout/list_item_view"
|
android:layout="@layout/list_item_view"
|
||||||
android:summary="@string/pref_summary_blacklist"
|
android:summary="@string/pref_summary_blacklist"
|
||||||
android:title="@string/pref_title_blacklist"
|
android:title="@string/pref_title_blacklist"
|
||||||
|
|
|
@ -54,12 +54,5 @@
|
||||||
android:summary="@string/pref_summary_colored_app_shortcuts"
|
android:summary="@string/pref_summary_colored_app_shortcuts"
|
||||||
android:title="@string/pref_title_app_shortcuts" />
|
android:title="@string/pref_title_app_shortcuts" />
|
||||||
|
|
||||||
<code.name.monkey.appthemehelper.common.prefs.supportv7.ATESwitchPreference
|
|
||||||
android:defaultValue="false"
|
|
||||||
android:key="dominant_color"
|
|
||||||
android:layout="@layout/list_item_view_switch"
|
|
||||||
android:summary="@string/pref_summary_dominant_color"
|
|
||||||
android:title="@string/pref_title_toggle_dominant_color" />
|
|
||||||
|
|
||||||
</code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceCategory>
|
</code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceCategory>
|
||||||
</androidx.preference.PreferenceScreen>
|
</androidx.preference.PreferenceScreen>
|
Loading…
Add table
Add a link
Reference in a new issue