Merge branch 'dev' into reset_image

This commit is contained in:
Phani-22 2022-03-18 07:51:40 +05:30 committed by GitHub
commit 647e504f3d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
37 changed files with 384 additions and 120 deletions

View file

@ -14,8 +14,8 @@ android {
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
applicationId "code.name.monkey.retromusic" applicationId "code.name.monkey.retromusic"
versionCode 10567 versionCode 10569
versionName '5.7.2' versionName '5.7.3'
buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"") buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"")
} }
@ -93,7 +93,7 @@ dependencies {
implementation "androidx.appcompat:appcompat:$appcompat_version" implementation "androidx.appcompat:appcompat:$appcompat_version"
implementation 'androidx.annotation:annotation:1.3.0' implementation 'androidx.annotation:annotation:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3' 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.preference:preference-ktx:$preference_version"
implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.palette:palette-ktx:1.0.0' implementation 'androidx.palette:palette-ktx:1.0.0'
@ -126,7 +126,7 @@ dependencies {
def retrofit_version = '2.9.0' def retrofit_version = '2.9.0'
implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.5' implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.6'
def material_dialog_version = "3.3.0" def material_dialog_version = "3.3.0"
implementation "com.afollestad.material-dialogs:core:$material_dialog_version" implementation "com.afollestad.material-dialogs:core:$material_dialog_version"

View file

@ -62,6 +62,22 @@
</head> </head>
<body> <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> <div>
<h5>February 13, 2022</h5> <h5>February 13, 2022</h5>
<h2>v5.7.2<span class="tag"><i>Beta</i></span></h2> <h2>v5.7.2<span class="tag"><i>Beta</i></span></h2>

View file

@ -163,4 +163,5 @@ const val APPBAR_MODE = "appbar_mode"
const val WALLPAPER_ACCENT = "wallpaper_accent" const val WALLPAPER_ACCENT = "wallpaper_accent"
const val SCREEN_ON_LYRICS = "screen_on_lyrics" const val SCREEN_ON_LYRICS = "screen_on_lyrics"
const val CIRCLE_PLAY_BUTTON = "circle_play_button" const val CIRCLE_PLAY_BUTTON = "circle_play_button"
const val SWIPE_ANYWHERE_NOW_PLAYING = "swipe_anywhere_now_playing" const val SWIPE_ANYWHERE_NOW_PLAYING = "swipe_anywhere_now_playing"
const val PAUSE_HISTORY = "pause_history"

View file

@ -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.QUEUE_CHANGED
import code.name.monkey.retromusic.service.MusicService.Companion.REPEAT_MODE_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.service.MusicService.Companion.SHUFFLE_MODE_CHANGED
import code.name.monkey.retromusic.util.PreferenceUtil
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
@ -123,7 +124,10 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), IMusicServiceEventLi
if (entity != null) { if (entity != null) {
repository.updateHistorySong(MusicPlayerRemote.currentSong) repository.updateHistorySong(MusicPlayerRemote.currentSong)
} else { } else {
repository.addSongToHistory(MusicPlayerRemote.currentSong) // Check whether pause history option is ON or OFF
if (!PreferenceUtil.pauseHistory) {
repository.addSongToHistory(MusicPlayerRemote.currentSong)
}
} }
val songs = repository.checkSongExistInPlayCount(MusicPlayerRemote.currentSong.id) val songs = repository.checkSongExistInPlayCount(MusicPlayerRemote.currentSong.id)
if (songs.isNotEmpty()) { if (songs.isNotEmpty()) {

View file

@ -35,7 +35,7 @@ import kotlinx.coroutines.withContext
import java.io.File import java.io.File
class LibraryViewModel( class LibraryViewModel(
private val repository: RealRepository private val repository: RealRepository,
) : ViewModel(), IMusicServiceEventListener { ) : ViewModel(), IMusicServiceEventListener {
private val _paletteColor = MutableLiveData<Int>() private val _paletteColor = MutableLiveData<Int>()
@ -50,6 +50,7 @@ class LibraryViewModel(
private val searchResults = MutableLiveData<List<Any>>() private val searchResults = MutableLiveData<List<Any>>()
private val fabMargin = MutableLiveData(0) private val fabMargin = MutableLiveData(0)
private val songHistory = MutableLiveData<List<Song>>() private val songHistory = MutableLiveData<List<Song>>()
private var previousSongHistory = ArrayList<HistoryEntity>()
val paletteColor: LiveData<Int> = _paletteColor val paletteColor: LiveData<Int> = _paletteColor
init { init {
@ -143,12 +144,11 @@ class LibraryViewModel(
suggestions.postValue(repository.suggestions()) suggestions.postValue(repository.suggestions())
} }
fun search(query: String?, filter: Filter) { fun search(query: String?, filter: Filter) =
viewModelScope.launch(IO) { viewModelScope.launch(IO) {
val result = repository.search(query, filter) val result =repository.search(query, filter)
searchResults.postValue(result) searchResults.postValue(result)
} }
}
fun forceReload(reloadType: ReloadType) = viewModelScope.launch(IO) { fun forceReload(reloadType: ReloadType) = viewModelScope.launch(IO) {
when (reloadType) { when (reloadType) {
@ -342,11 +342,27 @@ class LibraryViewModel(
fun clearHistory() { fun clearHistory() {
viewModelScope.launch(IO) { viewModelScope.launch(IO) {
previousSongHistory = repository.historySong() as ArrayList<HistoryEntity>
repository.clearSongHistory() repository.clearSongHistory()
} }
songHistory.value = emptyList() 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 favorites() = repository.favorites()
fun clearSearchResult() { fun clearSearchResult() {
@ -363,6 +379,14 @@ class LibraryViewModel(
createPlaylist(PlaylistEntity(playlistName = playlistName)) createPlaylist(PlaylistEntity(playlistName = playlistName))
insertSongs(songs.map { it.toSongEntity(playlistId) }) insertSongs(songs.map { it.toSongEntity(playlistId) })
forceReload(Playlists) forceReload(Playlists)
withContext(Main) {
Toast.makeText(
App.getContext(),
App.getContext()
.getString(R.string.playlist_created_sucessfully, playlistName),
Toast.LENGTH_SHORT
).show()
}
} else { } else {
val playlist = playlists.firstOrNull() val playlist = playlists.firstOrNull()
if (playlist != null) { if (playlist != null) {
@ -370,21 +394,13 @@ class LibraryViewModel(
it.toSongEntity(playListId = playlist.playListId) it.toSongEntity(playListId = playlist.playListId)
}) })
} }
withContext(Main) { }
Toast.makeText( withContext(Main) {
App.getContext(), Toast.makeText(App.getContext(), App.getContext().getString(
"Playlist already exists", R.string.added_song_count_to_playlist,
Toast.LENGTH_SHORT songs.size,
).show() playlistName
if (songs.isNotEmpty()) { ), Toast.LENGTH_SHORT).show()
Toast.makeText(
App.getContext(),
"Adding songs to $playlistName",
Toast.LENGTH_SHORT
).show()
}
}
} }
} }
} }

View file

@ -80,6 +80,7 @@ import kotlinx.coroutines.withContext
import org.koin.android.ext.android.get import org.koin.android.ext.android.get
import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf import org.koin.core.parameter.parametersOf
import java.text.Collator
class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_details), class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_details),
IAlbumClickListener, ICabHolder { IAlbumClickListener, ICabHolder {
@ -437,15 +438,13 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
o2.trackNumber o2.trackNumber
) )
} }
SONG_A_Z -> album.songs.sortedWith { o1, o2 -> SONG_A_Z -> {
o1.title.compareTo( val collator = Collator.getInstance()
o2.title album.songs.sortedWith { o1, o2 -> collator.compare(o1.title, o2.title) }
)
} }
SONG_Z_A -> album.songs.sortedWith { o1, o2 -> SONG_Z_A -> {
o2.title.compareTo( val collator = Collator.getInstance()
o1.title album.songs.sortedWith { o1, o2 -> collator.compare(o2.title, o1.title) }
)
} }
SONG_DURATION -> album.songs.sortedWith { o1, o2 -> SONG_DURATION -> album.songs.sortedWith { o1, o2 ->
o1.duration.compareTo( o1.duration.compareTo(

View file

@ -187,7 +187,7 @@ class HomeFragment :
} }
GlideApp.with(requireActivity()) GlideApp.with(requireActivity())
.load(RetroGlideExtension.getUserModel()) .load(RetroGlideExtension.getUserModel())
.userProfileOptions(RetroGlideExtension.getUserModel()) .userProfileOptions(RetroGlideExtension.getUserModel(), requireContext())
.into(binding.userImage) .into(binding.userImage)
} }

View file

@ -14,6 +14,7 @@
*/ */
package code.name.monkey.retromusic.fragments.other package code.name.monkey.retromusic.fragments.other
import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
@ -22,6 +23,7 @@ import android.view.View
import androidx.activity.addCallback import androidx.activity.addCallback
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.view.doOnPreDraw import androidx.core.view.doOnPreDraw
import androidx.core.view.isVisible
import androidx.navigation.fragment.FragmentNavigatorExtras import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs 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.attached.isActive
import com.afollestad.materialcab.createCab import com.afollestad.materialcab.createCab
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.transition.MaterialSharedAxis import com.google.android.material.transition.MaterialSharedAxis
class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_detail), class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_detail),
IArtistClickListener, IAlbumClickListener, ICabHolder { IArtistClickListener, IAlbumClickListener, ICabHolder {
private val args by navArgs<DetailListFragmentArgs>() private val args by navArgs<DetailListFragmentArgs>()
@ -162,9 +166,12 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
adapter = songAdapter adapter = songAdapter
layoutManager = linearLayoutManager() layoutManager = linearLayoutManager()
} }
libraryViewModel.observableHistorySongs().observe(viewLifecycleOwner) { libraryViewModel.observableHistorySongs().observe(viewLifecycleOwner) {
songAdapter.swapDataSet(it) songAdapter.swapDataSet(it)
binding.empty.isVisible = it.isEmpty()
} }
} }
private fun loadFavorite() { private fun loadFavorite() {
@ -236,6 +243,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
return if (RetroUtil.isLandscape()) 4 else 2 return if (RetroUtil.isLandscape()) 4 else 2
} }
override fun onArtist(artistId: Long, view: View) { override fun onArtist(artistId: Long, view: View) {
findNavController().navigate( findNavController().navigate(
R.id.artistDetailsFragment, R.id.artistDetailsFragment,
@ -305,11 +313,24 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
override fun onOptionsItemSelected(item: MenuItem): Boolean { override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) { when (item.itemId) {
R.id.action_clear_history -> libraryViewModel.clearHistory() R.id.action_clear_history -> {
/* if (binding.recyclerView.adapter?.itemCount!! > 0) {
TODO("Show a snackbar showing that history has been successfully libraryViewModel.clearHistory()
cleared and that will have an undo button")
*/ 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 return false
} }

View file

@ -167,7 +167,7 @@ class UserInfoFragment : Fragment() {
} }
GlideApp.with(this) GlideApp.with(this)
.load(RetroGlideExtension.getUserModel()) .load(RetroGlideExtension.getUserModel())
.userProfileOptions(RetroGlideExtension.getUserModel()) .userProfileOptions(RetroGlideExtension.getUserModel(), requireContext())
.into(binding.userImage) .into(binding.userImage)
} }

View file

@ -14,6 +14,9 @@
*/ */
package code.name.monkey.retromusic.fragments.player.material 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.os.Bundle
import android.view.View import android.view.View
import androidx.appcompat.widget.Toolbar 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.databinding.FragmentMaterialBinding
import code.name.monkey.retromusic.extensions.colorControlNormal import code.name.monkey.retromusic.extensions.colorControlNormal
import code.name.monkey.retromusic.extensions.drawAboveSystemBars import code.name.monkey.retromusic.extensions.drawAboveSystemBars
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.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.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.ViewUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import code.name.monkey.retromusic.views.DrawableGradient
/** /**
* @author Hemanth S (h4h13). * @author Hemanth S (h4h13).
@ -48,6 +55,33 @@ class MaterialFragment : AbsPlayerFragment(R.layout.fragment_material) {
private var _binding: FragmentMaterialBinding? = null private var _binding: FragmentMaterialBinding? = null
private val binding get() = _binding!! 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() { override fun onShow() {
playbackControlsFragment.show() playbackControlsFragment.show()
@ -74,6 +108,10 @@ class MaterialFragment : AbsPlayerFragment(R.layout.fragment_material) {
colorControlNormal(), colorControlNormal(),
requireActivity() requireActivity()
) )
if (PreferenceUtil.isAdaptiveColor) {
colorize(color.backgroundColor)
}
} }
override fun toggleFavorite(song: Song) { override fun toggleFavorite(song: Song) {

View file

@ -46,6 +46,7 @@ import com.google.android.material.chip.ChipGroup
import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.textfield.TextInputEditText import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.transition.MaterialFadeThrough import com.google.android.material.transition.MaterialFadeThrough
import kotlinx.coroutines.Job
import net.yslibrary.android.keyboardvisibilityevent.KeyboardVisibilityEvent import net.yslibrary.android.keyboardvisibilityevent.KeyboardVisibilityEvent
import java.util.* import java.util.*
@ -63,6 +64,8 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
private lateinit var searchAdapter: SearchAdapter private lateinit var searchAdapter: SearchAdapter
private var query: String? = null private var query: String? = null
private var job: Job? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
enterTransition = MaterialFadeThrough().addTarget(view) enterTransition = MaterialFadeThrough().addTarget(view)
@ -184,7 +187,8 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
binding.voiceSearch.isGone = query.isNotEmpty() binding.voiceSearch.isGone = query.isNotEmpty()
binding.clearText.isVisible = query.isNotEmpty() binding.clearText.isVisible = query.isNotEmpty()
val filter = getFilter() val filter = getFilter()
libraryViewModel.search(query, filter) job?.cancel()
job = libraryViewModel.search(query, filter)
} }
private fun getFilter(): Filter { private fun getFilter(): Filter {

View file

@ -1,5 +1,6 @@
package code.name.monkey.retromusic.glide package code.name.monkey.retromusic.glide
import android.content.Context
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor
import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.TintHelper
@ -150,10 +151,11 @@ object RetroGlideExtension {
@GlideOption @GlideOption
fun userProfileOptions( fun userProfileOptions(
baseRequestOptions: BaseRequestOptions<*>, baseRequestOptions: BaseRequestOptions<*>,
file: File file: File,
context: Context
): BaseRequestOptions<*> { ): BaseRequestOptions<*> {
return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
.error(getErrorUserProfile()) .error(getErrorUserProfile(context))
.signature(createSignature(file)) .signature(createSignature(file))
} }
@ -201,11 +203,11 @@ object RetroGlideExtension {
return File(dir, USER_BANNER) return File(dir, USER_BANNER)
} }
private fun getErrorUserProfile(): Drawable { private fun getErrorUserProfile(context: Context): Drawable {
return TintHelper.createTintedDrawable( return TintHelper.createTintedDrawable(
getContext(), getContext(),
R.drawable.ic_account, R.drawable.ic_account,
accentColor(getContext()) accentColor(context)
) )
} }

View file

@ -43,9 +43,7 @@ class WallpaperAccentManager(val context: Context) {
.getWallpaperColors(WallpaperManager.FLAG_SYSTEM) .getWallpaperColors(WallpaperManager.FLAG_SYSTEM)
if (colors != null) { if (colors != null) {
val primaryColor = colors.primaryColor.toArgb() val primaryColor = colors.primaryColor.toArgb()
if (primaryColor != ThemeStore.wallpaperColor(context)) { ThemeStore.editTheme(context).wallpaperColor(context, primaryColor).commit()
ThemeStore.editTheme(context).wallpaperColor(primaryColor).commit()
}
} }
} }
} }

View file

@ -17,6 +17,7 @@ package code.name.monkey.retromusic.model
import code.name.monkey.retromusic.helper.SortOrder import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import java.text.Collator
data class Artist( data class Artist(
val id: Long, val id: Long,
@ -60,37 +61,34 @@ data class Artist(
get() = albums.flatMap { it.songs } get() = albums.flatMap { it.songs }
val sortedSongs: List<Song> val sortedSongs: List<Song>
get() = songs.sortedWith( get() {
when (PreferenceUtil.artistDetailSongSortOrder) { val collator = Collator.getInstance()
SortOrder.ArtistSongSortOrder.SONG_A_Z -> { o1, o2 -> return songs.sortedWith(
o1.title.compareTo( when (PreferenceUtil.artistDetailSongSortOrder) {
o2.title SortOrder.ArtistSongSortOrder.SONG_A_Z -> { o1, o2 ->
) collator.compare(o1.title, o2.title)
} }
SortOrder.ArtistSongSortOrder.SONG_Z_A -> { o1, o2 -> SortOrder.ArtistSongSortOrder.SONG_Z_A -> { o1, o2 ->
o2.title.compareTo( collator.compare(o2.title, o1.title)
o1.title }
) SortOrder.ArtistSongSortOrder.SONG_ALBUM -> { o1, o2 ->
} collator.compare(o1.albumName, o2.albumName)
SortOrder.ArtistSongSortOrder.SONG_ALBUM -> { o1, o2 -> }
o1.albumName.compareTo( SortOrder.ArtistSongSortOrder.SONG_YEAR -> { o1, o2 ->
o2.albumName o2.year.compareTo(
) o1.year
} )
SortOrder.ArtistSongSortOrder.SONG_YEAR -> { o1, o2 -> }
o2.year.compareTo( SortOrder.ArtistSongSortOrder.SONG_DURATION -> { o1, o2 ->
o1.year o1.duration.compareTo(
) o2.duration
} )
SortOrder.ArtistSongSortOrder.SONG_DURATION -> { o1, o2 -> }
o1.duration.compareTo( else -> {
o2.duration throw IllegalArgumentException("invalid ${PreferenceUtil.artistDetailSongSortOrder}")
) }
} })
else -> { }
throw IllegalArgumentException("invalid ${PreferenceUtil.artistDetailSongSortOrder}")
}
})
fun safeGetFirstAlbum(): Album { fun safeGetFirstAlbum(): Album {
return albums.firstOrNull() ?: Album.empty return albums.firstOrNull() ?: Album.empty

View file

@ -19,6 +19,7 @@ import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil 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 songs = songRepository.songs(cursor)
val album = Album(albumId, songs) val album = Album(albumId, songs)
sortAlbumSongs(album) return sortAlbumSongs(album)
return album
} }
// We don't need sorted list of songs (with sortAlbumSongs()) // We don't need sorted list of songs (with sortAlbumSongs())
@ -74,23 +74,36 @@ class RealAlbumRepository(private val songRepository: RealSongRepository) :
fun splitIntoAlbums( fun splitIntoAlbums(
songs: List<Song> songs: List<Song>
): List<Album> { ): List<Album> {
return if (PreferenceUtil.albumSortOrder != SortOrder.AlbumSortOrder.ALBUM_NUMBER_OF_SONGS) songs.groupBy { it.albumId } val grouped = songs.groupBy { it.albumId }.map { Album(it.key, it.value) }
.map { Album(it.key, it.value) } val collator = Collator.getInstance()
// We can't sort Album with the help of MediaStore so a hack return when (PreferenceUtil.albumSortOrder) {
else songs.groupBy { it.albumId }.map { Album(it.key, it.value) } SortOrder.AlbumSortOrder.ALBUM_A_Z -> {
.sortedByDescending { it.songCount } 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 { private fun sortAlbumSongs(album: Album): Album {
val collator = Collator.getInstance()
val songs = when (PreferenceUtil.albumDetailSongSortOrder) { val songs = when (PreferenceUtil.albumDetailSongSortOrder) {
SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs.sortedWith { o1, o2 -> SortOrder.AlbumSongSortOrder.SONG_TRACK_LIST -> album.songs.sortedWith { o1, o2 ->
o1.trackNumber.compareTo(o2.trackNumber) o1.trackNumber.compareTo(o2.trackNumber)
} }
SortOrder.AlbumSongSortOrder.SONG_A_Z -> album.songs.sortedWith { o1, o2 -> SortOrder.AlbumSongSortOrder.SONG_A_Z -> {
o1.title.compareTo(o2.title) album.songs.sortedWith { o1, o2 -> collator.compare(o1.title, o2.title) }
} }
SortOrder.AlbumSongSortOrder.SONG_Z_A -> album.songs.sortedWith { o1, o2 -> SortOrder.AlbumSongSortOrder.SONG_Z_A -> {
o2.title.compareTo(o1.title) album.songs.sortedWith { o1, o2 -> collator.compare(o2.title, o1.title) }
} }
SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs.sortedWith { o1, o2 -> SortOrder.AlbumSongSortOrder.SONG_DURATION -> album.songs.sortedWith { o1, o2 ->
o1.duration.compareTo(o2.duration) o1.duration.compareTo(o2.duration)

View file

@ -20,6 +20,7 @@ import code.name.monkey.retromusic.helper.SortOrder
import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import java.text.Collator
interface ArtistRepository { interface ArtistRepository {
fun artists(): List<Artist> fun artists(): List<Artist>
@ -103,7 +104,8 @@ class RealArtistRepository(
getSongLoaderSortOrder() getSongLoaderSortOrder()
) )
) )
return splitIntoArtists(albumRepository.splitIntoAlbums(songs)) val artists = splitIntoArtists(albumRepository.splitIntoAlbums(songs))
return sortArtists(artists)
} }
override fun albumArtists(): List<Artist> { override fun albumArtists(): List<Artist> {
@ -115,7 +117,8 @@ class RealArtistRepository(
if (PreferenceUtil.artistSortOrder == SortOrder.ArtistSortOrder.ARTIST_A_Z) "" else " DESC" 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> { override fun albumArtists(query: String): List<Artist> {
@ -126,7 +129,8 @@ class RealArtistRepository(
getSongLoaderSortOrder() getSongLoaderSortOrder()
) )
) )
return splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs)) val artists = splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs))
return sortArtists(artists)
} }
override fun artists(query: String): List<Artist> { override fun artists(query: String): List<Artist> {
@ -137,7 +141,8 @@ class RealArtistRepository(
getSongLoaderSortOrder() 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 } return albums.groupBy { it.artistId }
.map { Artist(it.key, it.value) } .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
}
}
} }

View file

@ -28,9 +28,11 @@ import code.name.monkey.retromusic.extensions.getInt
import code.name.monkey.retromusic.extensions.getLong import code.name.monkey.retromusic.extensions.getLong
import code.name.monkey.retromusic.extensions.getString import code.name.monkey.retromusic.extensions.getString
import code.name.monkey.retromusic.extensions.getStringOrNull 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.model.Song
import code.name.monkey.retromusic.providers.BlacklistStore import code.name.monkey.retromusic.providers.BlacklistStore
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import java.text.Collator
/** /**
* Created by hemanths on 10/08/17. * Created by hemanths on 10/08/17.
@ -66,7 +68,28 @@ class RealSongRepository(private val context: Context) : SongRepository {
} while (cursor.moveToNext()) } while (cursor.moveToNext())
} }
cursor?.close() 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 { override fun song(cursor: Cursor?): Song {

View file

@ -125,8 +125,14 @@ class PlayingNotificationImpl24(
} }
override fun updateMetadata(song: Song, onUpdate: () -> Unit) { override fun updateMetadata(song: Song, onUpdate: () -> Unit) {
setContentTitle(song.title) setContentTitle(
setContentText( HtmlCompat.fromHtml(
"<b>" + song.title + "</b>",
HtmlCompat.FROM_HTML_MODE_LEGACY
)
)
setContentText(song.artistName)
setSubText(
HtmlCompat.fromHtml( HtmlCompat.fromHtml(
"<b>" + song.albumName + "</b>", "<b>" + song.albumName + "</b>",
HtmlCompat.FROM_HTML_MODE_LEGACY HtmlCompat.FROM_HTML_MODE_LEGACY
@ -169,10 +175,12 @@ class PlayingNotificationImpl24(
} }
override fun onLoadCleared(placeholder: Drawable?) { override fun onLoadCleared(placeholder: Drawable?) {
setLargeIcon(BitmapFactory.decodeResource( setLargeIcon(
context.resources, BitmapFactory.decodeResource(
R.drawable.default_audio_art context.resources,
)) R.drawable.default_audio_art
)
)
onUpdate() onUpdate()
} }
}) })

View file

@ -637,6 +637,12 @@ object PreferenceUtil {
true true
) )
val pauseHistory: Boolean
get() = sharedPreferences.getBoolean(
PAUSE_HISTORY,
false
)
var audioFadeDuration var audioFadeDuration
get() = sharedPreferences get() = sharedPreferences
.getInt(AUDIO_FADE_DURATION, 0) .getInt(AUDIO_FADE_DURATION, 0)

View file

@ -49,7 +49,6 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import code.name.monkey.appthemehelper.util.TintHelper; import code.name.monkey.appthemehelper.util.TintHelper;
import code.name.monkey.appthemehelper.util.VersionUtils;
import code.name.monkey.retromusic.App; import code.name.monkey.retromusic.App;
public class RetroUtil { public class RetroUtil {

View file

@ -17,12 +17,10 @@ package code.name.monkey.retromusic.util
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build
import android.provider.BaseColumns import android.provider.BaseColumns
import android.provider.MediaStore import android.provider.MediaStore
import android.provider.Settings import android.provider.Settings
import android.widget.Toast import android.widget.Toast
import androidx.annotation.RequiresApi
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song

View file

@ -14,6 +14,15 @@
<include layout="@layout/shadow_statusbar_toolbar" /> <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 <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View file

@ -10,6 +10,15 @@
<include layout="@layout/shadow_statusbar_toolbar" /> <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 <FrameLayout
android:id="@+id/statusBarContainer" android:id="@+id/statusBarContainer"
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -67,6 +67,7 @@
android:textAppearance="@style/TextViewHeadline5" android:textAppearance="@style/TextViewHeadline5"
android:textColor="?android:attr/textColorSecondary" android:textColor="?android:attr/textColorSecondary"
tools:visibility="visible" /> tools:visibility="visible" />
</LinearLayout> </LinearLayout>
<com.google.android.material.progressindicator.CircularProgressIndicator <com.google.android.material.progressindicator.CircularProgressIndicator
@ -76,4 +77,4 @@
android:layout_gravity="center" android:layout_gravity="center"
android:gravity="center" android:gravity="center"
android:indeterminate="true" /> android:indeterminate="true" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -31,6 +31,8 @@
android:id="@android:id/icon" android:id="@android:id/icon"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingStart="0dp"
android:paddingEnd="16dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:tint="?attr/colorControlNormal" app:tint="?attr/colorControlNormal"
@ -53,6 +55,8 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="2dp" android:layout_marginTop="2dp"
android:paddingStart="0dp"
android:paddingEnd="16dp"
android:textAppearance="@style/TextViewNormal" android:textAppearance="@style/TextViewNormal"
android:textColor="?android:attr/textColorSecondary" android:textColor="?android:attr/textColorSecondary"
app:layout_constrainedWidth="true" app:layout_constrainedWidth="true"

View file

@ -12,7 +12,7 @@
~ See the GNU General Public License for more details. ~ 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"> <style name="Theme.RetroMusic.Base.Adaptive" parent="Theme.Material3.DayNight.NoActionBar">
<item name="toolbarPopupTheme">@style/ThemeOverlay.AppCompat.Dark</item> <item name="toolbarPopupTheme">@style/ThemeOverlay.AppCompat.Dark</item>

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<bool name="wallpaper_accent_enabled">true</bool>
<bool name="wallpaper_accent_visible">true</bool> <bool name="wallpaper_accent_visible">true</bool>
</resources> </resources>

View file

@ -12,7 +12,7 @@
~ See the GNU General Public License for more details. ~ 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"> <style name="Theme.RetroMusic.Base.Adaptive" parent="Theme.Material3.DayNight.NoActionBar">
<item name="toolbarPopupTheme">@style/ThemeOverlay.AppCompat.Light</item> <item name="toolbarPopupTheme">@style/ThemeOverlay.AppCompat.Light</item>

View file

@ -4,6 +4,5 @@
<bool name="md3_enabled">true</bool> <bool name="md3_enabled">true</bool>
<integer name="overScrollMode">0</integer> <integer name="overScrollMode">0</integer>
<bool name="wallpaper_accent_enabled">false</bool>
<bool name="wallpaper_accent_visible">false</bool> <bool name="wallpaper_accent_visible">false</bool>
</resources> </resources>

View file

@ -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_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_wallpaper_accent">Extract accent color from wallpaper</string>
<string name="pref_summary_whitelist">Only show music from /Music Folder</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_art_on_lockscreen">Show album cover</string>
<string name="pref_title_album_artists_only">Navigate by Album Artist</string> <string name="pref_title_album_artists_only">Navigate by Album Artist</string>
<string name="pref_title_album_cover_style">Album cover theme</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_toggle_volume">Volume controls</string>
<string name="pref_title_wallpaper_accent">Wallpaper accent color</string> <string name="pref_title_wallpaper_accent">Wallpaper accent color</string>
<string name="pref_title_whitelist">Whitelist music</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">Pro</string>
<string name="pro_summary">Black theme, Now playing themes, Carousel effect and more..</string> <string name="pro_summary">Black theme, Now playing themes, Carousel effect and more..</string>
<string name="profile">Profile</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="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="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="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="choose_image">Choose Image</string>
<string name="remove_image">Remove Image</string> <string name="remove_image">Remove Image</string>
</resources> </resources>

View file

@ -211,7 +211,7 @@
<style name="SearchChipStyle" parent="Widget.Material3.Chip.Filter"> <style name="SearchChipStyle" parent="Widget.Material3.Chip.Filter">
<item name="android:checked">false</item> <item name="android:checked">false</item>
<item name="android:textSize">16sp</item> <item name="android:textSize">16sp</item>
<item name="checkedIconEnabled">true</item> <item name="checkedIconVisible">false</item>
<item name="chipEndPadding">10dp</item> <item name="chipEndPadding">10dp</item>
<item name="chipMinHeight">40dp</item> <item name="chipMinHeight">40dp</item>
<item name="chipStartPadding">10dp</item> <item name="chipStartPadding">10dp</item>

View file

@ -48,8 +48,7 @@
android:key="wallpaper_accent" android:key="wallpaper_accent"
android:layout="@layout/list_item_view_switch" android:layout="@layout/list_item_view_switch"
android:summary="@string/pref_summary_wallpaper_accent" android:summary="@string/pref_summary_wallpaper_accent"
android:title="@string/pref_title_wallpaper_accent" android:title="@string/pref_title_wallpaper_accent" />
app:isPreferenceVisible="@bool/wallpaper_accent_visible" />
<code.name.monkey.appthemehelper.common.prefs.supportv7.ATEColorPreference <code.name.monkey.appthemehelper.common.prefs.supportv7.ATEColorPreference
android:dependency="material_you" android:dependency="material_you"

View file

@ -40,6 +40,13 @@
android:summary="@string/pref_summary_suggestions" android:summary="@string/pref_summary_suggestions"
android:title="@string/pref_title_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>
<code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceCategory <code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceCategory

View file

@ -59,8 +59,26 @@ private constructor(private val mContext: Context) : ThemeStorePrefKeys, ThemeSt
return this return this
} }
override fun wallpaperColor(color: Int): ThemeStore { override fun wallpaperColor(context: Context, color: Int): ThemeStore {
mEditor.putInt(ThemeStorePrefKeys.KEY_WALLPAPER_COLOR, color) 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 return this
} }
@ -217,7 +235,7 @@ private constructor(private val mContext: Context) : ThemeStorePrefKeys, ThemeSt
} }
val desaturatedColor = prefs(context).getBoolean("desaturated_color", false) val desaturatedColor = prefs(context).getBoolean("desaturated_color", false)
val color = if (isWallpaperAccentEnabled(context)) { val color = if (isWallpaperAccentEnabled(context)) {
wallpaperColor(context) wallpaperColor(context, isWindowBackgroundDark(context))
} else { } else {
prefs(context).getInt( prefs(context).getInt(
ThemeStorePrefKeys.KEY_ACCENT_COLOR, ThemeStorePrefKeys.KEY_ACCENT_COLOR,
@ -232,9 +250,9 @@ private constructor(private val mContext: Context) : ThemeStorePrefKeys, ThemeSt
@CheckResult @CheckResult
@ColorInt @ColorInt
fun wallpaperColor(context: Context): Int { fun wallpaperColor(context: Context, isDarkMode: Boolean): Int {
return prefs(context).getInt( 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")) resolveColor(context, R.attr.colorAccent, Color.parseColor("#263238"))
) )
} }

View file

@ -1,5 +1,6 @@
package code.name.monkey.appthemehelper package code.name.monkey.appthemehelper
import android.content.Context
import androidx.annotation.AttrRes import androidx.annotation.AttrRes
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.annotation.ColorRes import androidx.annotation.ColorRes
@ -34,7 +35,7 @@ internal interface ThemeStoreInterface {
fun accentColor(@ColorInt color: Int): ThemeStore 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 fun accentColorRes(@ColorRes colorRes: Int): ThemeStore

View file

@ -29,6 +29,7 @@ internal interface ThemeStorePrefKeys {
const val KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark" const val KEY_AUTO_GENERATE_PRIMARYDARK = "auto_generate_primarydark"
const val KEY_MATERIAL_YOU = "material_you" 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"
} }
} }

View file

@ -3,7 +3,11 @@ package code.name.monkey.appthemehelper.util
import android.graphics.Color import android.graphics.Color
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.annotation.FloatRange 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 { object ColorUtil {
fun desaturateColor(color: Int, ratio: Float): Int { fun desaturateColor(color: Int, ratio: Float): Int {
@ -44,6 +48,50 @@ object ColorUtil {
return shiftColor(color, 1.1f) 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 { fun isColorLight(@ColorInt color: Int): Boolean {
val darkness = val darkness =
1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255