Merge branch 'dev' into reset_image
This commit is contained in:
commit
647e504f3d
37 changed files with 384 additions and 120 deletions
|
@ -14,8 +14,8 @@ android {
|
|||
vectorDrawables.useSupportLibrary = true
|
||||
|
||||
applicationId "code.name.monkey.retromusic"
|
||||
versionCode 10567
|
||||
versionName '5.7.2'
|
||||
versionCode 10569
|
||||
versionName '5.7.3'
|
||||
|
||||
buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"")
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ dependencies {
|
|||
implementation "androidx.appcompat:appcompat:$appcompat_version"
|
||||
implementation 'androidx.annotation:annotation:1.3.0'
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.3.0-alpha01'
|
||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||
implementation "androidx.preference:preference-ktx:$preference_version"
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'androidx.palette:palette-ktx:1.0.0'
|
||||
|
@ -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.5'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.6'
|
||||
|
||||
def material_dialog_version = "3.3.0"
|
||||
implementation "com.afollestad.material-dialogs:core:$material_dialog_version"
|
||||
|
|
|
@ -62,6 +62,22 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h5>March 13, 2022</h5>
|
||||
<h2>v5.7.3</h2>
|
||||
<h3>What's New</h3>
|
||||
<ul>
|
||||
<li>Added adaptive color in Material now playing theme</li>
|
||||
<li>Added an option to share crash report</li>
|
||||
<li>Added options to clear, pause history</li>
|
||||
</ul>
|
||||
<h3>Fixed</h3>
|
||||
<ul>
|
||||
<li>Adapt Wallpaper accent for better readability</li>
|
||||
<li>Optimized search</li>
|
||||
<li>Made sleep timer precise</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h5>February 13, 2022</h5>
|
||||
<h2>v5.7.2<span class="tag"><i>Beta</i></span></h2>
|
||||
|
|
|
@ -164,3 +164,4 @@ const val WALLPAPER_ACCENT = "wallpaper_accent"
|
|||
const val SCREEN_ON_LYRICS = "screen_on_lyrics"
|
||||
const val CIRCLE_PLAY_BUTTON = "circle_play_button"
|
||||
const val SWIPE_ANYWHERE_NOW_PLAYING = "swipe_anywhere_now_playing"
|
||||
const val PAUSE_HISTORY = "pause_history"
|
|
@ -31,6 +31,7 @@ import code.name.monkey.retromusic.service.MusicService.Companion.PLAY_STATE_CHA
|
|||
import code.name.monkey.retromusic.service.MusicService.Companion.QUEUE_CHANGED
|
||||
import code.name.monkey.retromusic.service.MusicService.Companion.REPEAT_MODE_CHANGED
|
||||
import code.name.monkey.retromusic.service.MusicService.Companion.SHUFFLE_MODE_CHANGED
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.android.ext.android.inject
|
||||
|
@ -123,8 +124,11 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), IMusicServiceEventLi
|
|||
if (entity != null) {
|
||||
repository.updateHistorySong(MusicPlayerRemote.currentSong)
|
||||
} else {
|
||||
// Check whether pause history option is ON or OFF
|
||||
if (!PreferenceUtil.pauseHistory) {
|
||||
repository.addSongToHistory(MusicPlayerRemote.currentSong)
|
||||
}
|
||||
}
|
||||
val songs = repository.checkSongExistInPlayCount(MusicPlayerRemote.currentSong.id)
|
||||
if (songs.isNotEmpty()) {
|
||||
repository.updateSongInPlayCount(songs.first().apply {
|
||||
|
|
|
@ -35,7 +35,7 @@ import kotlinx.coroutines.withContext
|
|||
import java.io.File
|
||||
|
||||
class LibraryViewModel(
|
||||
private val repository: RealRepository
|
||||
private val repository: RealRepository,
|
||||
) : ViewModel(), IMusicServiceEventListener {
|
||||
|
||||
private val _paletteColor = MutableLiveData<Int>()
|
||||
|
@ -50,6 +50,7 @@ class LibraryViewModel(
|
|||
private val searchResults = MutableLiveData<List<Any>>()
|
||||
private val fabMargin = MutableLiveData(0)
|
||||
private val songHistory = MutableLiveData<List<Song>>()
|
||||
private var previousSongHistory = ArrayList<HistoryEntity>()
|
||||
val paletteColor: LiveData<Int> = _paletteColor
|
||||
|
||||
init {
|
||||
|
@ -143,12 +144,11 @@ class LibraryViewModel(
|
|||
suggestions.postValue(repository.suggestions())
|
||||
}
|
||||
|
||||
fun search(query: String?, filter: Filter) {
|
||||
fun search(query: String?, filter: Filter) =
|
||||
viewModelScope.launch(IO) {
|
||||
val result = repository.search(query, filter)
|
||||
val result =repository.search(query, filter)
|
||||
searchResults.postValue(result)
|
||||
}
|
||||
}
|
||||
|
||||
fun forceReload(reloadType: ReloadType) = viewModelScope.launch(IO) {
|
||||
when (reloadType) {
|
||||
|
@ -342,11 +342,27 @@ class LibraryViewModel(
|
|||
|
||||
fun clearHistory() {
|
||||
viewModelScope.launch(IO) {
|
||||
previousSongHistory = repository.historySong() as ArrayList<HistoryEntity>
|
||||
|
||||
repository.clearSongHistory()
|
||||
}
|
||||
songHistory.value = emptyList()
|
||||
}
|
||||
|
||||
|
||||
fun restoreHistory() {
|
||||
viewModelScope.launch(IO) {
|
||||
if (previousSongHistory.isNotEmpty()) {
|
||||
val history = ArrayList<Song>()
|
||||
for (song in previousSongHistory) {
|
||||
repository.addSongToHistory(song.toSong())
|
||||
history.add(song.toSong())
|
||||
}
|
||||
songHistory.postValue(history)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun favorites() = repository.favorites()
|
||||
|
||||
fun clearSearchResult() {
|
||||
|
@ -363,6 +379,14 @@ class LibraryViewModel(
|
|||
createPlaylist(PlaylistEntity(playlistName = playlistName))
|
||||
insertSongs(songs.map { it.toSongEntity(playlistId) })
|
||||
forceReload(Playlists)
|
||||
withContext(Main) {
|
||||
Toast.makeText(
|
||||
App.getContext(),
|
||||
App.getContext()
|
||||
.getString(R.string.playlist_created_sucessfully, playlistName),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
} else {
|
||||
val playlist = playlists.firstOrNull()
|
||||
if (playlist != null) {
|
||||
|
@ -370,21 +394,13 @@ class LibraryViewModel(
|
|||
it.toSongEntity(playListId = playlist.playListId)
|
||||
})
|
||||
}
|
||||
}
|
||||
withContext(Main) {
|
||||
Toast.makeText(
|
||||
App.getContext(),
|
||||
"Playlist already exists",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
if (songs.isNotEmpty()) {
|
||||
Toast.makeText(
|
||||
App.getContext(),
|
||||
"Adding songs to $playlistName",
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
}
|
||||
|
||||
Toast.makeText(App.getContext(), App.getContext().getString(
|
||||
R.string.added_song_count_to_playlist,
|
||||
songs.size,
|
||||
playlistName
|
||||
), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,6 +80,7 @@ import kotlinx.coroutines.withContext
|
|||
import org.koin.android.ext.android.get
|
||||
import org.koin.androidx.viewmodel.ext.android.viewModel
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import java.text.Collator
|
||||
|
||||
class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_details),
|
||||
IAlbumClickListener, ICabHolder {
|
||||
|
@ -437,15 +438,13 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
o2.trackNumber
|
||||
)
|
||||
}
|
||||
SONG_A_Z -> album.songs.sortedWith { o1, o2 ->
|
||||
o1.title.compareTo(
|
||||
o2.title
|
||||
)
|
||||
SONG_A_Z -> {
|
||||
val collator = Collator.getInstance()
|
||||
album.songs.sortedWith { o1, o2 -> collator.compare(o1.title, o2.title) }
|
||||
}
|
||||
SONG_Z_A -> album.songs.sortedWith { o1, o2 ->
|
||||
o2.title.compareTo(
|
||||
o1.title
|
||||
)
|
||||
SONG_Z_A -> {
|
||||
val collator = Collator.getInstance()
|
||||
album.songs.sortedWith { o1, o2 -> collator.compare(o2.title, o1.title) }
|
||||
}
|
||||
SONG_DURATION -> album.songs.sortedWith { o1, o2 ->
|
||||
o1.duration.compareTo(
|
||||
|
|
|
@ -187,7 +187,7 @@ class HomeFragment :
|
|||
}
|
||||
GlideApp.with(requireActivity())
|
||||
.load(RetroGlideExtension.getUserModel())
|
||||
.userProfileOptions(RetroGlideExtension.getUserModel())
|
||||
.userProfileOptions(RetroGlideExtension.getUserModel(), requireContext())
|
||||
.into(binding.userImage)
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
package code.name.monkey.retromusic.fragments.other
|
||||
|
||||
import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.view.Menu
|
||||
import android.view.MenuInflater
|
||||
|
@ -22,6 +23,7 @@ import android.view.View
|
|||
import androidx.activity.addCallback
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.doOnPreDraw
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.navigation.fragment.FragmentNavigatorExtras
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
|
@ -51,8 +53,10 @@ import com.afollestad.materialcab.attached.destroy
|
|||
import com.afollestad.materialcab.attached.isActive
|
||||
import com.afollestad.materialcab.createCab
|
||||
import com.google.android.material.shape.MaterialShapeDrawable
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
|
||||
|
||||
class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_detail),
|
||||
IArtistClickListener, IAlbumClickListener, ICabHolder {
|
||||
private val args by navArgs<DetailListFragmentArgs>()
|
||||
|
@ -162,9 +166,12 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
|||
adapter = songAdapter
|
||||
layoutManager = linearLayoutManager()
|
||||
}
|
||||
|
||||
libraryViewModel.observableHistorySongs().observe(viewLifecycleOwner) {
|
||||
songAdapter.swapDataSet(it)
|
||||
binding.empty.isVisible = it.isEmpty()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun loadFavorite() {
|
||||
|
@ -236,6 +243,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
|||
return if (RetroUtil.isLandscape()) 4 else 2
|
||||
}
|
||||
|
||||
|
||||
override fun onArtist(artistId: Long, view: View) {
|
||||
findNavController().navigate(
|
||||
R.id.artistDetailsFragment,
|
||||
|
@ -305,11 +313,24 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
|
|||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
|
||||
when (item.itemId) {
|
||||
R.id.action_clear_history -> libraryViewModel.clearHistory()
|
||||
/*
|
||||
TODO("Show a snackbar showing that history has been successfully
|
||||
cleared and that will have an undo button")
|
||||
*/
|
||||
R.id.action_clear_history -> {
|
||||
if (binding.recyclerView.adapter?.itemCount!! > 0) {
|
||||
libraryViewModel.clearHistory()
|
||||
|
||||
val snackBar =
|
||||
Snackbar.make(binding.container,
|
||||
getString(R.string.history_cleared),
|
||||
Snackbar.LENGTH_LONG)
|
||||
.setAction(getString(R.string.history_undo_button)) {
|
||||
libraryViewModel.restoreHistory()
|
||||
}
|
||||
.setActionTextColor(Color.YELLOW)
|
||||
val snackBarView = snackBar.view
|
||||
snackBarView.translationY =
|
||||
-(resources.getDimension(R.dimen.mini_player_height))
|
||||
snackBar.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -167,7 +167,7 @@ class UserInfoFragment : Fragment() {
|
|||
}
|
||||
GlideApp.with(this)
|
||||
.load(RetroGlideExtension.getUserModel())
|
||||
.userProfileOptions(RetroGlideExtension.getUserModel())
|
||||
.userProfileOptions(RetroGlideExtension.getUserModel(), requireContext())
|
||||
.into(binding.userImage)
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
*/
|
||||
package code.name.monkey.retromusic.fragments.player.material
|
||||
|
||||
import android.animation.ArgbEvaluator
|
||||
import android.animation.ValueAnimator
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
|
@ -22,12 +25,16 @@ import code.name.monkey.retromusic.R
|
|||
import code.name.monkey.retromusic.databinding.FragmentMaterialBinding
|
||||
import code.name.monkey.retromusic.extensions.colorControlNormal
|
||||
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
|
||||
import code.name.monkey.retromusic.extensions.surfaceColor
|
||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
||||
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
|
||||
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.ViewUtil
|
||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||
import code.name.monkey.retromusic.views.DrawableGradient
|
||||
|
||||
/**
|
||||
* @author Hemanth S (h4h13).
|
||||
|
@ -48,6 +55,33 @@ class MaterialFragment : AbsPlayerFragment(R.layout.fragment_material) {
|
|||
private var _binding: FragmentMaterialBinding? = null
|
||||
private val binding get() = _binding!!
|
||||
|
||||
private var valueAnimator: ValueAnimator? = null
|
||||
|
||||
private fun colorize(i: Int) {
|
||||
if (valueAnimator != null) {
|
||||
valueAnimator?.cancel()
|
||||
}
|
||||
|
||||
valueAnimator = ValueAnimator.ofObject(
|
||||
ArgbEvaluator(),
|
||||
surfaceColor(),
|
||||
i
|
||||
)
|
||||
valueAnimator?.addUpdateListener { animation ->
|
||||
if (isAdded) {
|
||||
val drawable = DrawableGradient(
|
||||
GradientDrawable.Orientation.TOP_BOTTOM,
|
||||
intArrayOf(
|
||||
animation.animatedValue as Int,
|
||||
surfaceColor()
|
||||
), 0
|
||||
)
|
||||
binding.colorGradientBackground.background = drawable
|
||||
}
|
||||
}
|
||||
valueAnimator?.setDuration(ViewUtil.RETRO_MUSIC_ANIM_TIME.toLong())?.start()
|
||||
}
|
||||
|
||||
|
||||
override fun onShow() {
|
||||
playbackControlsFragment.show()
|
||||
|
@ -74,6 +108,10 @@ class MaterialFragment : AbsPlayerFragment(R.layout.fragment_material) {
|
|||
colorControlNormal(),
|
||||
requireActivity()
|
||||
)
|
||||
|
||||
if (PreferenceUtil.isAdaptiveColor) {
|
||||
colorize(color.backgroundColor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toggleFavorite(song: Song) {
|
||||
|
|
|
@ -46,6 +46,7 @@ import com.google.android.material.chip.ChipGroup
|
|||
import com.google.android.material.shape.MaterialShapeDrawable
|
||||
import com.google.android.material.textfield.TextInputEditText
|
||||
import com.google.android.material.transition.MaterialFadeThrough
|
||||
import kotlinx.coroutines.Job
|
||||
import net.yslibrary.android.keyboardvisibilityevent.KeyboardVisibilityEvent
|
||||
import java.util.*
|
||||
|
||||
|
@ -63,6 +64,8 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
|
|||
private lateinit var searchAdapter: SearchAdapter
|
||||
private var query: String? = null
|
||||
|
||||
private var job: Job? = null
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
enterTransition = MaterialFadeThrough().addTarget(view)
|
||||
|
@ -184,7 +187,8 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
|
|||
binding.voiceSearch.isGone = query.isNotEmpty()
|
||||
binding.clearText.isVisible = query.isNotEmpty()
|
||||
val filter = getFilter()
|
||||
libraryViewModel.search(query, filter)
|
||||
job?.cancel()
|
||||
job = libraryViewModel.search(query, filter)
|
||||
}
|
||||
|
||||
private fun getFilter(): Filter {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package code.name.monkey.retromusic.glide
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor
|
||||
import code.name.monkey.appthemehelper.util.TintHelper
|
||||
|
@ -150,10 +151,11 @@ object RetroGlideExtension {
|
|||
@GlideOption
|
||||
fun userProfileOptions(
|
||||
baseRequestOptions: BaseRequestOptions<*>,
|
||||
file: File
|
||||
file: File,
|
||||
context: Context
|
||||
): BaseRequestOptions<*> {
|
||||
return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
|
||||
.error(getErrorUserProfile())
|
||||
.error(getErrorUserProfile(context))
|
||||
.signature(createSignature(file))
|
||||
}
|
||||
|
||||
|
@ -201,11 +203,11 @@ object RetroGlideExtension {
|
|||
return File(dir, USER_BANNER)
|
||||
}
|
||||
|
||||
private fun getErrorUserProfile(): Drawable {
|
||||
private fun getErrorUserProfile(context: Context): Drawable {
|
||||
return TintHelper.createTintedDrawable(
|
||||
getContext(),
|
||||
R.drawable.ic_account,
|
||||
accentColor(getContext())
|
||||
accentColor(context)
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -43,9 +43,7 @@ class WallpaperAccentManager(val context: Context) {
|
|||
.getWallpaperColors(WallpaperManager.FLAG_SYSTEM)
|
||||
if (colors != null) {
|
||||
val primaryColor = colors.primaryColor.toArgb()
|
||||
if (primaryColor != ThemeStore.wallpaperColor(context)) {
|
||||
ThemeStore.editTheme(context).wallpaperColor(primaryColor).commit()
|
||||
}
|
||||
ThemeStore.editTheme(context).wallpaperColor(context, primaryColor).commit()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ package code.name.monkey.retromusic.model
|
|||
import code.name.monkey.retromusic.helper.SortOrder
|
||||
import code.name.monkey.retromusic.util.MusicUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import java.text.Collator
|
||||
|
||||
data class Artist(
|
||||
val id: Long,
|
||||
|
@ -60,22 +61,18 @@ data class Artist(
|
|||
get() = albums.flatMap { it.songs }
|
||||
|
||||
val sortedSongs: List<Song>
|
||||
get() = songs.sortedWith(
|
||||
get() {
|
||||
val collator = Collator.getInstance()
|
||||
return songs.sortedWith(
|
||||
when (PreferenceUtil.artistDetailSongSortOrder) {
|
||||
SortOrder.ArtistSongSortOrder.SONG_A_Z -> { o1, o2 ->
|
||||
o1.title.compareTo(
|
||||
o2.title
|
||||
)
|
||||
collator.compare(o1.title, o2.title)
|
||||
}
|
||||
SortOrder.ArtistSongSortOrder.SONG_Z_A -> { o1, o2 ->
|
||||
o2.title.compareTo(
|
||||
o1.title
|
||||
)
|
||||
collator.compare(o2.title, o1.title)
|
||||
}
|
||||
SortOrder.ArtistSongSortOrder.SONG_ALBUM -> { o1, o2 ->
|
||||
o1.albumName.compareTo(
|
||||
o2.albumName
|
||||
)
|
||||
collator.compare(o1.albumName, o2.albumName)
|
||||
}
|
||||
SortOrder.ArtistSongSortOrder.SONG_YEAR -> { o1, o2 ->
|
||||
o2.year.compareTo(
|
||||
|
@ -91,6 +88,7 @@ data class Artist(
|
|||
throw IllegalArgumentException("invalid ${PreferenceUtil.artistDetailSongSortOrder}")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun safeGetFirstAlbum(): Album {
|
||||
return albums.firstOrNull() ?: Album.empty
|
||||
|
|
|
@ -19,6 +19,7 @@ import code.name.monkey.retromusic.helper.SortOrder
|
|||
import code.name.monkey.retromusic.model.Album
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import java.text.Collator
|
||||
|
||||
|
||||
/**
|
||||
|
@ -65,8 +66,7 @@ class RealAlbumRepository(private val songRepository: RealSongRepository) :
|
|||
)
|
||||
val songs = songRepository.songs(cursor)
|
||||
val album = Album(albumId, songs)
|
||||
sortAlbumSongs(album)
|
||||
return album
|
||||
return sortAlbumSongs(album)
|
||||
}
|
||||
|
||||
// We don't need sorted list of songs (with sortAlbumSongs())
|
||||
|
@ -74,23 +74,36 @@ class RealAlbumRepository(private val songRepository: RealSongRepository) :
|
|||
fun splitIntoAlbums(
|
||||
songs: List<Song>
|
||||
): List<Album> {
|
||||
return if (PreferenceUtil.albumSortOrder != SortOrder.AlbumSortOrder.ALBUM_NUMBER_OF_SONGS) songs.groupBy { it.albumId }
|
||||
.map { Album(it.key, it.value) }
|
||||
// We can't sort Album with the help of MediaStore so a hack
|
||||
else songs.groupBy { it.albumId }.map { Album(it.key, it.value) }
|
||||
.sortedByDescending { it.songCount }
|
||||
val grouped = songs.groupBy { it.albumId }.map { Album(it.key, it.value) }
|
||||
val collator = Collator.getInstance()
|
||||
return when (PreferenceUtil.albumSortOrder) {
|
||||
SortOrder.AlbumSortOrder.ALBUM_A_Z -> {
|
||||
grouped.sortedWith { a1, a2 -> collator.compare(a1.title, a2.title) }
|
||||
}
|
||||
SortOrder.AlbumSortOrder.ALBUM_Z_A -> {
|
||||
grouped.sortedWith { a1, a2 -> collator.compare(a2.title, a1.title) }
|
||||
}
|
||||
SortOrder.AlbumSortOrder.ALBUM_ARTIST -> {
|
||||
grouped.sortedWith { a1, a2 -> collator.compare(a1.albumArtist, a2.albumArtist) }
|
||||
}
|
||||
SortOrder.AlbumSortOrder.ALBUM_NUMBER_OF_SONGS -> {
|
||||
grouped.sortedByDescending { it.songCount }
|
||||
}
|
||||
else -> grouped
|
||||
}
|
||||
}
|
||||
|
||||
private fun sortAlbumSongs(album: Album): Album {
|
||||
val collator = Collator.getInstance()
|
||||
val songs = when (PreferenceUtil.albumDetailSongSortOrder) {
|
||||
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs.sortedWith { o1, o2 ->
|
||||
o1.trackNumber.compareTo(o2.trackNumber)
|
||||
}
|
||||
SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs.sortedWith { o1, o2 ->
|
||||
o1.title.compareTo(o2.title)
|
||||
SortOrder.AlbumSongSortOrder.SONG_A_Z -> {
|
||||
album.songs.sortedWith { o1, o2 -> collator.compare(o1.title, o2.title) }
|
||||
}
|
||||
SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs.sortedWith { o1, o2 ->
|
||||
o2.title.compareTo(o1.title)
|
||||
SortOrder.AlbumSongSortOrder.SONG_Z_A -> {
|
||||
album.songs.sortedWith { o1, o2 -> collator.compare(o2.title, o1.title) }
|
||||
}
|
||||
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs.sortedWith { o1, o2 ->
|
||||
o1.duration.compareTo(o2.duration)
|
||||
|
|
|
@ -20,6 +20,7 @@ import code.name.monkey.retromusic.helper.SortOrder
|
|||
import code.name.monkey.retromusic.model.Album
|
||||
import code.name.monkey.retromusic.model.Artist
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import java.text.Collator
|
||||
|
||||
interface ArtistRepository {
|
||||
fun artists(): List<Artist>
|
||||
|
@ -103,7 +104,8 @@ class RealArtistRepository(
|
|||
getSongLoaderSortOrder()
|
||||
)
|
||||
)
|
||||
return splitIntoArtists(albumRepository.splitIntoAlbums(songs))
|
||||
val artists = splitIntoArtists(albumRepository.splitIntoAlbums(songs))
|
||||
return sortArtists(artists)
|
||||
}
|
||||
|
||||
override fun albumArtists(): List<Artist> {
|
||||
|
@ -115,7 +117,8 @@ class RealArtistRepository(
|
|||
if (PreferenceUtil.artistSortOrder == SortOrder.ArtistSortOrder.ARTIST_A_Z) "" else " DESC"
|
||||
)
|
||||
)
|
||||
return splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs))
|
||||
val artists = splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs))
|
||||
return sortArtists(artists)
|
||||
}
|
||||
|
||||
override fun albumArtists(query: String): List<Artist> {
|
||||
|
@ -126,7 +129,8 @@ class RealArtistRepository(
|
|||
getSongLoaderSortOrder()
|
||||
)
|
||||
)
|
||||
return splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs))
|
||||
val artists = splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs))
|
||||
return sortArtists(artists)
|
||||
}
|
||||
|
||||
override fun artists(query: String): List<Artist> {
|
||||
|
@ -137,7 +141,8 @@ class RealArtistRepository(
|
|||
getSongLoaderSortOrder()
|
||||
)
|
||||
)
|
||||
return splitIntoArtists(albumRepository.splitIntoAlbums(songs))
|
||||
val artists = splitIntoArtists(albumRepository.splitIntoAlbums(songs))
|
||||
return sortArtists(artists)
|
||||
}
|
||||
|
||||
|
||||
|
@ -165,4 +170,17 @@ class RealArtistRepository(
|
|||
return albums.groupBy { it.artistId }
|
||||
.map { Artist(it.key, it.value) }
|
||||
}
|
||||
|
||||
private fun sortArtists(artists: List<Artist>): List<Artist> {
|
||||
val collator = Collator.getInstance()
|
||||
return when (PreferenceUtil.artistSortOrder) {
|
||||
SortOrder.ArtistSortOrder.ARTIST_A_Z -> {
|
||||
artists.sortedWith { a1, a2 -> collator.compare(a1.name, a2.name) }
|
||||
}
|
||||
SortOrder.ArtistSortOrder.ARTIST_Z_A -> {
|
||||
artists.sortedWith { a1, a2 -> collator.compare(a2.name, a1.name) }
|
||||
}
|
||||
else -> artists
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,9 +28,11 @@ import code.name.monkey.retromusic.extensions.getInt
|
|||
import code.name.monkey.retromusic.extensions.getLong
|
||||
import code.name.monkey.retromusic.extensions.getString
|
||||
import code.name.monkey.retromusic.extensions.getStringOrNull
|
||||
import code.name.monkey.retromusic.helper.SortOrder
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.providers.BlacklistStore
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import java.text.Collator
|
||||
|
||||
/**
|
||||
* Created by hemanths on 10/08/17.
|
||||
|
@ -66,7 +68,28 @@ class RealSongRepository(private val context: Context) : SongRepository {
|
|||
} while (cursor.moveToNext())
|
||||
}
|
||||
cursor?.close()
|
||||
return songs
|
||||
val collator = Collator.getInstance()
|
||||
return when (PreferenceUtil.songSortOrder) {
|
||||
SortOrder.SongSortOrder.SONG_A_Z -> {
|
||||
songs.sortedWith{ s1, s2 -> collator.compare(s1.title, s2.title) }
|
||||
}
|
||||
SortOrder.SongSortOrder.SONG_Z_A -> {
|
||||
songs.sortedWith{ s1, s2 -> collator.compare(s2.title, s1.title) }
|
||||
}
|
||||
SortOrder.SongSortOrder.SONG_ALBUM -> {
|
||||
songs.sortedWith{ s1, s2 -> collator.compare(s1.albumName, s2.albumName) }
|
||||
}
|
||||
SortOrder.SongSortOrder.SONG_ALBUM_ARTIST -> {
|
||||
songs.sortedWith{ s1, s2 -> collator.compare(s1.albumArtist, s2.albumArtist) }
|
||||
}
|
||||
SortOrder.SongSortOrder.SONG_ARTIST -> {
|
||||
songs.sortedWith{ s1, s2 -> collator.compare(s1.artistName, s2.artistName) }
|
||||
}
|
||||
SortOrder.SongSortOrder.COMPOSER -> {
|
||||
songs.sortedWith{ s1, s2 -> collator.compare(s1.composer, s2.composer) }
|
||||
}
|
||||
else -> songs
|
||||
}
|
||||
}
|
||||
|
||||
override fun song(cursor: Cursor?): Song {
|
||||
|
|
|
@ -125,8 +125,14 @@ class PlayingNotificationImpl24(
|
|||
}
|
||||
|
||||
override fun updateMetadata(song: Song, onUpdate: () -> Unit) {
|
||||
setContentTitle(song.title)
|
||||
setContentText(
|
||||
setContentTitle(
|
||||
HtmlCompat.fromHtml(
|
||||
"<b>" + song.title + "</b>",
|
||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||
)
|
||||
)
|
||||
setContentText(song.artistName)
|
||||
setSubText(
|
||||
HtmlCompat.fromHtml(
|
||||
"<b>" + song.albumName + "</b>",
|
||||
HtmlCompat.FROM_HTML_MODE_LEGACY
|
||||
|
@ -169,10 +175,12 @@ class PlayingNotificationImpl24(
|
|||
}
|
||||
|
||||
override fun onLoadCleared(placeholder: Drawable?) {
|
||||
setLargeIcon(BitmapFactory.decodeResource(
|
||||
setLargeIcon(
|
||||
BitmapFactory.decodeResource(
|
||||
context.resources,
|
||||
R.drawable.default_audio_art
|
||||
))
|
||||
)
|
||||
)
|
||||
onUpdate()
|
||||
}
|
||||
})
|
||||
|
|
|
@ -637,6 +637,12 @@ object PreferenceUtil {
|
|||
true
|
||||
)
|
||||
|
||||
val pauseHistory: Boolean
|
||||
get() = sharedPreferences.getBoolean(
|
||||
PAUSE_HISTORY,
|
||||
false
|
||||
)
|
||||
|
||||
var audioFadeDuration
|
||||
get() = sharedPreferences
|
||||
.getInt(AUDIO_FADE_DURATION, 0)
|
||||
|
|
|
@ -49,7 +49,6 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
|
||||
import code.name.monkey.appthemehelper.util.TintHelper;
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils;
|
||||
import code.name.monkey.retromusic.App;
|
||||
|
||||
public class RetroUtil {
|
||||
|
|
|
@ -17,12 +17,10 @@ package code.name.monkey.retromusic.util
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.BaseColumns
|
||||
import android.provider.MediaStore
|
||||
import android.provider.Settings
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.RequiresApi
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
|
|
|
@ -14,6 +14,15 @@
|
|||
|
||||
<include layout="@layout/shadow_statusbar_toolbar" />
|
||||
|
||||
<View
|
||||
android:id="@+id/colorGradientBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
|
|
@ -10,6 +10,15 @@
|
|||
|
||||
<include layout="@layout/shadow_statusbar_toolbar" />
|
||||
|
||||
<View
|
||||
android:id="@+id/colorGradientBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/statusBarContainer"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -67,6 +67,7 @@
|
|||
android:textAppearance="@style/TextViewHeadline5"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
android:id="@android:id/icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingEnd="16dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tint="?attr/colorControlNormal"
|
||||
|
@ -53,6 +55,8 @@
|
|||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:textAppearance="@style/TextViewNormal"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:layout_constrainedWidth="true"
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
~ See the GNU General Public License for more details.
|
||||
-->
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<resources>
|
||||
|
||||
<style name="Theme.RetroMusic.Base.Adaptive" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<item name="toolbarPopupTheme">@style/ThemeOverlay.AppCompat.Dark</item>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<bool name="wallpaper_accent_enabled">true</bool>
|
||||
<bool name="wallpaper_accent_visible">true</bool>
|
||||
</resources>
|
|
@ -12,7 +12,7 @@
|
|||
~ See the GNU General Public License for more details.
|
||||
-->
|
||||
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<resources>
|
||||
|
||||
<style name="Theme.RetroMusic.Base.Adaptive" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<item name="toolbarPopupTheme">@style/ThemeOverlay.AppCompat.Light</item>
|
||||
|
|
|
@ -4,6 +4,5 @@
|
|||
<bool name="md3_enabled">true</bool>
|
||||
|
||||
<integer name="overScrollMode">0</integer>
|
||||
<bool name="wallpaper_accent_enabled">false</bool>
|
||||
<bool name="wallpaper_accent_visible">false</bool>
|
||||
</resources>
|
|
@ -356,6 +356,7 @@
|
|||
<string name="pref_summary_toggle_volume">If enough space is available, show volume controls in the now playing screen</string>
|
||||
<string name="pref_summary_wallpaper_accent">Extract accent color from wallpaper</string>
|
||||
<string name="pref_summary_whitelist">Only show music from /Music Folder</string>
|
||||
<string name="pref_summary_pause_history">When enabled, newly played songs won\'t show in history</string>
|
||||
<string name="pref_title_album_art_on_lockscreen">Show album cover</string>
|
||||
<string name="pref_title_album_artists_only">Navigate by Album Artist</string>
|
||||
<string name="pref_title_album_cover_style">Album cover theme</string>
|
||||
|
@ -402,6 +403,7 @@
|
|||
<string name="pref_title_toggle_volume">Volume controls</string>
|
||||
<string name="pref_title_wallpaper_accent">Wallpaper accent color</string>
|
||||
<string name="pref_title_whitelist">Whitelist music</string>
|
||||
<string name="pref_title_pause_history">Pause history</string>
|
||||
<string name="pro">Pro</string>
|
||||
<string name="pro_summary">Black theme, Now playing themes, Carousel effect and more..</string>
|
||||
<string name="profile">Profile</string>
|
||||
|
@ -544,6 +546,11 @@
|
|||
<string name="you_will_be_forwarded_to_the_issue_tracker_website">You will be forwarded to the issue tracker website.</string>
|
||||
<string name="your_account_data_is_only_used_for_authentication">Your account data is only used for authentication.</string>
|
||||
<string name="customactivityoncrash_error_activity_error_details_share">Share Crash Report</string>
|
||||
<string name="playlist_created_sucessfully">%s created successfully</string>
|
||||
<string name="playList_already_exits">Playlist already exists</string>
|
||||
<string name="added_song_count_to_playlist">Added %d song(s) to %s</string>
|
||||
<string name="history_cleared">History cleared</string>
|
||||
<string name="history_undo_button">Undo</string>
|
||||
<string name="choose_image">Choose Image</string>
|
||||
<string name="remove_image">Remove Image</string>
|
||||
</resources>
|
||||
|
|
|
@ -211,7 +211,7 @@
|
|||
<style name="SearchChipStyle" parent="Widget.Material3.Chip.Filter">
|
||||
<item name="android:checked">false</item>
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="checkedIconEnabled">true</item>
|
||||
<item name="checkedIconVisible">false</item>
|
||||
<item name="chipEndPadding">10dp</item>
|
||||
<item name="chipMinHeight">40dp</item>
|
||||
<item name="chipStartPadding">10dp</item>
|
||||
|
|
|
@ -48,8 +48,7 @@
|
|||
android:key="wallpaper_accent"
|
||||
android:layout="@layout/list_item_view_switch"
|
||||
android:summary="@string/pref_summary_wallpaper_accent"
|
||||
android:title="@string/pref_title_wallpaper_accent"
|
||||
app:isPreferenceVisible="@bool/wallpaper_accent_visible" />
|
||||
android:title="@string/pref_title_wallpaper_accent" />
|
||||
|
||||
<code.name.monkey.appthemehelper.common.prefs.supportv7.ATEColorPreference
|
||||
android:dependency="material_you"
|
||||
|
|
|
@ -40,6 +40,13 @@
|
|||
android:summary="@string/pref_summary_suggestions"
|
||||
android:title="@string/pref_title_suggestions" />
|
||||
|
||||
<code.name.monkey.appthemehelper.common.prefs.supportv7.ATESwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="pause_history"
|
||||
android:layout="@layout/list_item_view_switch"
|
||||
android:summary="@string/pref_summary_pause_history"
|
||||
android:title="@string/pref_title_pause_history" />
|
||||
|
||||
</code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceCategory>
|
||||
|
||||
<code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceCategory
|
||||
|
|
|
@ -59,8 +59,26 @@ private constructor(private val mContext: Context) : ThemeStorePrefKeys, ThemeSt
|
|||
return this
|
||||
}
|
||||
|
||||
override fun wallpaperColor(color: Int): ThemeStore {
|
||||
mEditor.putInt(ThemeStorePrefKeys.KEY_WALLPAPER_COLOR, color)
|
||||
override fun wallpaperColor(context: Context, color: Int): ThemeStore {
|
||||
if (ColorUtil.isColorLight(color)) {
|
||||
mEditor.putInt(ThemeStorePrefKeys.KEY_WALLPAPER_COLOR_DARK, color)
|
||||
mEditor.putInt(
|
||||
ThemeStorePrefKeys.KEY_WALLPAPER_COLOR_LIGHT,
|
||||
ColorUtil.getReadableColorLight(
|
||||
color,
|
||||
Color.WHITE
|
||||
)
|
||||
)
|
||||
} else {
|
||||
mEditor.putInt(ThemeStorePrefKeys.KEY_WALLPAPER_COLOR_LIGHT, color)
|
||||
mEditor.putInt(
|
||||
ThemeStorePrefKeys.KEY_WALLPAPER_COLOR_DARK,
|
||||
ColorUtil.getReadableColorDark(
|
||||
color,
|
||||
Color.parseColor("#202124")
|
||||
)
|
||||
)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -217,7 +235,7 @@ private constructor(private val mContext: Context) : ThemeStorePrefKeys, ThemeSt
|
|||
}
|
||||
val desaturatedColor = prefs(context).getBoolean("desaturated_color", false)
|
||||
val color = if (isWallpaperAccentEnabled(context)) {
|
||||
wallpaperColor(context)
|
||||
wallpaperColor(context, isWindowBackgroundDark(context))
|
||||
} else {
|
||||
prefs(context).getInt(
|
||||
ThemeStorePrefKeys.KEY_ACCENT_COLOR,
|
||||
|
@ -232,9 +250,9 @@ private constructor(private val mContext: Context) : ThemeStorePrefKeys, ThemeSt
|
|||
|
||||
@CheckResult
|
||||
@ColorInt
|
||||
fun wallpaperColor(context: Context): Int {
|
||||
fun wallpaperColor(context: Context, isDarkMode: Boolean): Int {
|
||||
return prefs(context).getInt(
|
||||
ThemeStorePrefKeys.KEY_WALLPAPER_COLOR,
|
||||
if (isDarkMode) ThemeStorePrefKeys.KEY_WALLPAPER_COLOR_DARK else ThemeStorePrefKeys.KEY_WALLPAPER_COLOR_LIGHT,
|
||||
resolveColor(context, R.attr.colorAccent, Color.parseColor("#263238"))
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package code.name.monkey.appthemehelper
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.ColorRes
|
||||
|
@ -34,7 +35,7 @@ internal interface ThemeStoreInterface {
|
|||
|
||||
fun accentColor(@ColorInt color: Int): ThemeStore
|
||||
|
||||
fun wallpaperColor(@ColorInt color: Int): ThemeStore
|
||||
fun wallpaperColor(context: Context, color: Int): ThemeStore
|
||||
|
||||
fun accentColorRes(@ColorRes colorRes: Int): ThemeStore
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ internal interface ThemeStorePrefKeys {
|
|||
const val KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark"
|
||||
|
||||
const val KEY_MATERIAL_YOU = "material_you"
|
||||
const val KEY_WALLPAPER_COLOR = "wallpaper_color"
|
||||
const val KEY_WALLPAPER_COLOR_LIGHT = "wallpaper_color_light"
|
||||
const val KEY_WALLPAPER_COLOR_DARK = "wallpaper_color_dark"
|
||||
}
|
||||
}
|
|
@ -3,7 +3,11 @@ package code.name.monkey.appthemehelper.util
|
|||
import android.graphics.Color
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.FloatRange
|
||||
import kotlin.math.*
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
object ColorUtil {
|
||||
fun desaturateColor(color: Int, ratio: Float): Int {
|
||||
|
@ -44,6 +48,50 @@ object ColorUtil {
|
|||
return shiftColor(color, 1.1f)
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
fun lightenColor(
|
||||
@ColorInt color: Int,
|
||||
value: Float
|
||||
): Int {
|
||||
val hsl = FloatArray(3)
|
||||
ColorUtils.colorToHSL(color, hsl)
|
||||
hsl[2] += value
|
||||
hsl[2] = hsl[2].coerceIn(0f, 1f)
|
||||
return ColorUtils.HSLToColor(hsl)
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
fun darkenColor(
|
||||
@ColorInt color: Int,
|
||||
value: Float
|
||||
): Int {
|
||||
val hsl = FloatArray(3)
|
||||
ColorUtils.colorToHSL(color, hsl)
|
||||
hsl[2] -= value
|
||||
hsl[2] = hsl[2].coerceIn(0f, 1f)
|
||||
return ColorUtils.HSLToColor(hsl)
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
fun getReadableColorLight(@ColorInt color: Int, @ColorInt bgColor: Int): Int {
|
||||
var foregroundColor = color
|
||||
while (ColorUtils.calculateContrast(foregroundColor, bgColor) <= 3.0
|
||||
) {
|
||||
foregroundColor = darkenColor(foregroundColor, 0.1F)
|
||||
}
|
||||
return foregroundColor
|
||||
}
|
||||
|
||||
@ColorInt
|
||||
fun getReadableColorDark(@ColorInt color: Int, @ColorInt bgColor: Int): Int {
|
||||
var foregroundColor = color
|
||||
while (ColorUtils.calculateContrast(foregroundColor, bgColor) <= 3.0
|
||||
) {
|
||||
foregroundColor = lightenColor(foregroundColor, 0.1F)
|
||||
}
|
||||
return foregroundColor
|
||||
}
|
||||
|
||||
fun isColorLight(@ColorInt color: Int): Boolean {
|
||||
val darkness =
|
||||
1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue