Conflicts:
	app/src/main/java/io/github/muntashirakon/music/Constants.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/GenreAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/HomeAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/adapter/SearchAdapter.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/LibraryViewModel.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsPlayerFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/base/AbsRecyclerViewFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/genres/GenreDetailsFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/genres/GenresFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/home/HomeFragment.kt
	app/src/main/java/io/github/muntashirakon/music/fragments/search/SearchFragment.kt
	app/src/main/java/io/github/muntashirakon/music/interfaces/IGenreClickListener.kt
	app/src/main/java/io/github/muntashirakon/music/interfaces/IHomeClickListener.kt
	app/src/main/java/io/github/muntashirakon/music/preferences/AlbumCoverStylePreferenceDialog.kt
	app/src/main/java/io/github/muntashirakon/music/preferences/NowPlayingScreenPreferenceDialog.kt
	app/src/main/java/io/github/muntashirakon/music/service/notification/PlayingNotificationImpl.kt
	app/src/main/java/io/github/muntashirakon/music/util/MusicUtil.kt
	app/src/main/java/io/github/muntashirakon/music/util/PreferenceUtil.kt
	app/src/main/res/layout/activity_donation.xml
	app/src/main/res/layout/activity_pro_version.xml
	app/src/main/res/layout/card_other.xml
	app/src/main/res/layout/fragment_settings.xml
	app/src/main/res/layout/fragment_synced.xml
	app/src/main/res/layout/image.xml
	app/src/main/res/transition/change_bounds.xml
	appthemehelper/src/main/res/layout/ate_preference_custom.xml
This commit is contained in:
Muntashir Al-Islam 2020-11-07 07:34:17 +06:00
commit 2dea5c31ca
192 changed files with 10165 additions and 8185 deletions

View file

@ -10,6 +10,7 @@
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package io.github.muntashirakon.music
@ -51,7 +52,7 @@ object Constants {
)
const val NUMBER_OF_TOP_TRACKS = 99
}
const val EXTRA_PLAYLIST_TYPE = "type"
const val EXTRA_GENRE = "extra_genre"
const val EXTRA_PLAYLIST = "extra_playlist"
const val EXTRA_PLAYLIST_ID = "extra_playlist_id"

View file

@ -17,13 +17,12 @@ package io.github.muntashirakon.music.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import androidx.core.view.ViewCompat
import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController
import androidx.recyclerview.widget.RecyclerView
import io.github.muntashirakon.music.EXTRA_GENRE
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import io.github.muntashirakon.music.interfaces.IGenreClickListener
import io.github.muntashirakon.music.model.Genre
import java.util.*
@ -34,7 +33,8 @@ import java.util.*
class GenreAdapter(
private val activity: FragmentActivity,
var dataSet: List<Genre>,
private val mItemLayoutRes: Int
private val mItemLayoutRes: Int,
private val listener: IGenreClickListener
) : RecyclerView.Adapter<GenreAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(activity).inflate(mItemLayoutRes, parent, false))
@ -62,10 +62,8 @@ class GenreAdapter(
inner class ViewHolder(itemView: View) : MediaEntryViewHolder(itemView) {
override fun onClick(v: View?) {
activity.findNavController(R.id.fragment_container).navigate(
R.id.genreDetailsFragment,
bundleOf(EXTRA_GENRE to dataSet[layoutPosition])
)
ViewCompat.setTransitionName(itemView, "genre")
listener.onClickGenre(dataSet[layoutPosition], itemView)
}
}
}

View file

@ -38,6 +38,7 @@ import io.github.muntashirakon.music.glide.SongGlideRequest
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.interfaces.IAlbumClickListener
import io.github.muntashirakon.music.interfaces.IArtistClickListener
import io.github.muntashirakon.music.interfaces.IGenreClickListener
import io.github.muntashirakon.music.model.*
import io.github.muntashirakon.music.util.PreferenceUtil
import com.bumptech.glide.Glide
@ -45,7 +46,8 @@ import com.google.android.material.card.MaterialCardView
class HomeAdapter(
private val activity: AppCompatActivity
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), IArtistClickListener, IAlbumClickListener {
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), IArtistClickListener, IAlbumClickListener,
IGenreClickListener {
private var list = listOf<Home>()
@ -220,7 +222,8 @@ class HomeAdapter(
val genreAdapter = GenreAdapter(
activity,
home.arrayList as List<Genre>,
R.layout.item_grid_genre
R.layout.item_grid_genre,
this@HomeAdapter
)
recyclerView.apply {
layoutManager = GridLayoutManager(activity, 3, GridLayoutManager.HORIZONTAL, false)
@ -267,4 +270,16 @@ class HomeAdapter(
)
)
}
override fun onClickGenre(genre: Genre, view: View) {
activity.findNavController(R.id.fragment_container).navigate(
R.id.genreDetailsFragment,
bundleOf(EXTRA_GENRE to genre),
null,
FragmentNavigatorExtras(
view to "genre"
)
)
}
}

View file

@ -18,6 +18,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import androidx.core.view.isGone
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.fragment.app.FragmentActivity
@ -26,6 +27,7 @@ import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore
import io.github.muntashirakon.music.*
import io.github.muntashirakon.music.adapter.base.MediaEntryViewHolder
import io.github.muntashirakon.music.db.PlaylistEntity
import io.github.muntashirakon.music.db.PlaylistWithSongs
import io.github.muntashirakon.music.glide.AlbumGlideRequest
import io.github.muntashirakon.music.glide.ArtistGlideRequest
@ -52,7 +54,7 @@ class SearchAdapter(
if (dataSet[position] is Album) return ALBUM
if (dataSet[position] is Artist) return ARTIST
if (dataSet[position] is Genre) return GENRE
if (dataSet[position] is PlaylistWithSongs) return PLAYLIST
if (dataSet[position] is PlaylistEntity) return PLAYLIST
return if (dataSet[position] is Song) SONG else HEADER
}
@ -107,9 +109,9 @@ class SearchAdapter(
)
}
PLAYLIST -> {
val playlist = dataSet[position] as PlaylistWithSongs
holder.title?.text = playlist.playlistEntity.playlistName
holder.text?.text = MusicUtil.playlistInfoString(activity, playlist.songs)
val playlist = dataSet[position] as PlaylistEntity
holder.title?.text = playlist.playlistName
//holder.text?.text = MusicUtil.playlistInfoString(activity, playlist.songs)
}
else -> {
holder.title?.text = dataSet[position].toString()
@ -137,6 +139,7 @@ class SearchAdapter(
itemView.setOnLongClickListener(null)
imageTextContainer?.isInvisible = true
if (itemViewType == SONG) {
imageTextContainer?.isGone = true
menu?.visibility = View.VISIBLE
menu?.setOnClickListener(object : SongMenuHelper.OnClickSongMenu(activity) {
override val song: Song

View file

@ -89,15 +89,6 @@ open class AlbumAdapter(
holder.itemView.isActivated = isChecked
holder.title?.text = getAlbumTitle(album)
holder.text?.text = getAlbumText(album)
holder.playSongs?.setOnClickListener {
album.songs.let { songs ->
MusicPlayerRemote.openQueue(
songs,
0,
true
)
}
}
loadAlbumCover(album, holder)
}

View file

@ -21,6 +21,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.recyclerview.widget.RecyclerView;
import io.github.muntashirakon.music.R;
import com.google.android.material.card.MaterialCardView;
@ -47,11 +48,10 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
@Nullable public View mask;
@Nullable public View menu;
@Nullable public AppCompatImageView menu;
@Nullable public View paletteColorContainer;
@Nullable public ImageButton playSongs;
@Nullable public RecyclerView recyclerView;
@ -83,7 +83,6 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold
paletteColorContainer = itemView.findViewById(R.id.paletteColorContainer);
recyclerView = itemView.findViewById(R.id.recycler_view);
mask = itemView.findViewById(R.id.mask);
playSongs = itemView.findViewById(R.id.playSongs);
dummyContainer = itemView.findViewById(R.id.dummy_view);
if (imageContainerCard != null) {

View file

@ -111,6 +111,7 @@ open class SongAdapter(
holder.title?.setTextColor(color.primaryTextColor)
holder.text?.setTextColor(color.secondaryTextColor)
holder.paletteColorContainer?.setBackgroundColor(color.backgroundColor)
holder.menu?.imageTintList= ColorStateList.valueOf(color.primaryTextColor)
}
holder.mask?.backgroundTintList = ColorStateList.valueOf(color.primaryTextColor)
}

View file

@ -14,9 +14,12 @@
package io.github.muntashirakon.music.extensions
import android.animation.ObjectAnimator
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import androidx.annotation.LayoutRes
import androidx.core.animation.doOnEnd
@ -74,3 +77,39 @@ fun BottomSheetBehavior<*>.peekHeightAnimate(value: Int) {
start()
}
}
fun View.focusAndShowKeyboard() {
/**
* This is to be called when the window already has focus.
*/
fun View.showTheKeyboardNow() {
if (isFocused) {
post {
// We still post the call, just in case we are being notified of the windows focus
// but InputMethodManager didn't get properly setup yet.
val imm =
context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT)
}
}
}
requestFocus()
if (hasWindowFocus()) {
// No need to wait for the window to get focus.
showTheKeyboardNow()
} else {
// We need to wait until the window gets focus.
viewTreeObserver.addOnWindowFocusChangeListener(
object : ViewTreeObserver.OnWindowFocusChangeListener {
override fun onWindowFocusChanged(hasFocus: Boolean) {
// This notification will arrive just before the InputMethodManager gets set up.
if (hasFocus) {
this@focusAndShowKeyboard.showTheKeyboardNow()
// Its very important to remove this listener once we are done.
viewTreeObserver.removeOnWindowFocusChangeListener(this)
}
}
})
}
}

View file

@ -15,36 +15,19 @@
package io.github.muntashirakon.music.fragments
import android.widget.Toast
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import androidx.lifecycle.viewModelScope
import io.github.muntashirakon.music.App
import io.github.muntashirakon.music.RECENT_ALBUMS
import io.github.muntashirakon.music.RECENT_ARTISTS
import io.github.muntashirakon.music.TOP_ALBUMS
import io.github.muntashirakon.music.TOP_ARTISTS
import io.github.muntashirakon.music.db.PlaylistEntity
import io.github.muntashirakon.music.db.PlaylistWithSongs
import io.github.muntashirakon.music.db.SongEntity
import io.github.muntashirakon.music.db.toSong
import io.github.muntashirakon.music.db.toSongEntity
import androidx.lifecycle.*
import io.github.muntashirakon.music.*
import io.github.muntashirakon.music.db.*
import io.github.muntashirakon.music.fragments.ReloadType.*
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.interfaces.IMusicServiceEventListener
import io.github.muntashirakon.music.model.Album
import io.github.muntashirakon.music.model.Artist
import io.github.muntashirakon.music.model.Contributor
import io.github.muntashirakon.music.model.Genre
import io.github.muntashirakon.music.model.Home
import io.github.muntashirakon.music.model.Playlist
import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.model.*
import io.github.muntashirakon.music.repository.RealRepository
import io.github.muntashirakon.music.state.NowPlayingPanelState
import io.github.muntashirakon.music.util.PreferenceUtil
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class LibraryViewModel(
private val repository: RealRepository
@ -152,9 +135,11 @@ class LibraryViewModel(
}
}
fun search(query: String?) = viewModelScope.launch(IO) {
val result = repository.search(query)
searchResults.postValue(result)
fun search(query: String?) {
viewModelScope.launch(IO) {
val result = repository.search(query)
withContext(Main) { searchResults.postValue(result) }
}
}
fun forceReload(reloadType: ReloadType) = viewModelScope.launch {
@ -322,7 +307,8 @@ class LibraryViewModel(
viewModelScope.launch(IO) {
val playlists = checkPlaylistExists(playlistName)
if (playlists.isEmpty()) {
val playlistId: Long = createPlaylist(PlaylistEntity(playlistName = playlistName))
val playlistId: Long =
createPlaylist(PlaylistEntity(playlistName = playlistName))
insertSongs(songs.map { it.toSongEntity(playlistId) })
forceReload(Playlists)
} else {

View file

@ -17,11 +17,7 @@ package io.github.muntashirakon.music.fragments.albums
import android.app.ActivityOptions
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.SubMenu
import android.view.View
import android.view.*
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import androidx.core.text.HtmlCompat
@ -287,8 +283,8 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
}
private fun setColors(color: Int) {
shuffleAction.applyColor(color)
playAction.applyOutlineColor(color)
shuffleAction?.applyColor(color)
playAction?.applyOutlineColor(color)
}
override fun onAlbumClick(albumId: Long, view: View) {

View file

@ -14,6 +14,7 @@
*/
package io.github.muntashirakon.music.fragments.artists
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.text.Spanned
@ -137,7 +138,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
}
}
fun showArtist(artist: Artist) {
private fun showArtist(artist: Artist) {
this.artist = artist
loadArtistImage(artist)
if (RetroUtil.isAllowedToDownloadMetadata(requireContext())) {
@ -164,7 +165,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
songTitle.text = songText
albumTitle.text = albumText
songAdapter.swapDataSet(artist.songs.sortedBy { it.trackNumber })
artist.albums?.let { albumAdapter.swapDataSet(it) }
albumAdapter.swapDataSet(artist.albums)
}
private fun loadBiography(
@ -174,7 +175,7 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
biography = null
this.lang = lang
detailsViewModel.getArtistInfo(name, lang, null)
.observe(viewLifecycleOwner, Observer { result ->
.observe(viewLifecycleOwner, { result ->
when (result) {
is Result.Loading -> println("Loading")
is Result.Error -> println("Error")
@ -222,8 +223,8 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
}
private fun setColors(color: Int) {
shuffleAction.applyColor(color)
playAction.applyOutlineColor(color)
shuffleAction?.applyColor(color)
playAction?.applyOutlineColor(color)
}
override fun onAlbumClick(albumId: Long, view: View) {
@ -282,6 +283,21 @@ class ArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_artist_d
return true
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let {
CustomArtistImageUtil.getInstance(requireContext())
.setCustomArtistImage(artist, it)
}
}
else -> if (resultCode == Activity.RESULT_OK) {
println("OK")
}
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
inflater.inflate(R.menu.menu_artist_detail, menu)

View file

@ -50,13 +50,13 @@ import io.github.muntashirakon.music.model.lyrics.Lyrics
import io.github.muntashirakon.music.repository.RealRepository
import io.github.muntashirakon.music.service.MusicService
import io.github.muntashirakon.music.util.*
import java.io.FileNotFoundException
import kotlinx.android.synthetic.main.shadow_statusbar_toolbar.*
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.get
import java.io.FileNotFoundException
abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragment(layout),
Toolbar.OnMenuItemClickListener, IPaletteColorHolder, PlayerAlbumCoverFragment.Callbacks {

View file

@ -112,7 +112,7 @@ abstract class AbsRecyclerViewCustomGridSizeFragment<A : RecyclerView.Adapter<*>
} else {
0
}
recyclerView.setPadding(padding, padding, padding, padding)
//recyclerView.setPadding(padding, padding, padding, padding)
}
protected abstract fun setGridSize(gridSize: Int)

View file

@ -15,10 +15,14 @@
package io.github.muntashirakon.music.fragments.base
import android.os.Bundle
import android.view.*
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.annotation.NonNull
import androidx.annotation.StringRes
import androidx.core.text.HtmlCompat
import androidx.core.view.updatePadding
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore
@ -28,12 +32,9 @@ import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.dialogs.CreatePlaylistDialog
import io.github.muntashirakon.music.dialogs.ImportPlaylistDialog
import io.github.muntashirakon.music.helper.MusicPlayerRemote
import io.github.muntashirakon.music.state.NowPlayingPanelState
import io.github.muntashirakon.music.util.DensityUtil
import io.github.muntashirakon.music.util.ThemedFastScroller.create
import io.github.muntashirakon.music.views.ScrollingViewOnApplyWindowInsetsListener
import com.google.android.material.appbar.AppBarLayout
import com.google.android.material.transition.Hold
import kotlinx.android.synthetic.main.fragment_main_recycler.*
import me.zhanghai.android.fastscroll.FastScroller
import me.zhanghai.android.fastscroll.FastScrollerBuilder
@ -50,15 +51,6 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
protected var adapter: A? = null
protected var layoutManager: LM? = null
private fun setUpTransitions() {
exitTransition = Hold()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setUpTransitions()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mainActivity.setBottomBarVisibility(View.VISIBLE)
@ -86,12 +78,7 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
layoutManager = this@AbsRecyclerViewFragment.layoutManager
adapter = this@AbsRecyclerViewFragment.adapter
val fastScroller = create(this)
setOnApplyWindowInsetsListener(
ScrollingViewOnApplyWindowInsetsListener(
recyclerView,
fastScroller
)
)
}
checkForPadding()
}
@ -125,13 +112,13 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
private fun checkForPadding() {
val itemCount: Int = adapter?.itemCount ?: 0
val params = container.layoutParams as ViewGroup.MarginLayoutParams
if (itemCount > 0 && MusicPlayerRemote.playingQueue.isNotEmpty()) {
val height = DensityUtil.dip2px(requireContext(), 104f)
params.bottomMargin = height
val height = DensityUtil.dip2px(requireContext(), 112f)
recyclerView.updatePadding(0, 0, 0, height)
} else {
val height = DensityUtil.dip2px(requireContext(), 52f)
params.bottomMargin = height
val height = DensityUtil.dip2px(requireContext(), 56f)
recyclerView.updatePadding(0, 0, 0, height)
}
}
@ -145,12 +132,12 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
protected abstract fun createAdapter(): A
override fun onOffsetChanged(p0: AppBarLayout?, i: Int) {
container.setPadding(
container.paddingLeft,
container.paddingTop,
container.paddingRight,
/*recyclerView.setPadding(
recyclerView.paddingLeft,
recyclerView.paddingTop,
recyclerView.paddingRight,
i
)
)*/
}
override fun onQueueChanged() {

View file

@ -19,10 +19,12 @@ import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.core.view.ViewCompat
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.util.ATHUtil
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.song.SongAdapter
import io.github.muntashirakon.music.extensions.dipToPix
@ -30,11 +32,11 @@ import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
import io.github.muntashirakon.music.helper.menu.GenreMenuHelper
import io.github.muntashirakon.music.model.Genre
import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.state.NowPlayingPanelState
import java.util.*
import com.google.android.material.transition.MaterialContainerTransform
import kotlinx.android.synthetic.main.fragment_playlist_detail.*
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
import java.util.*
class GenreDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_detail) {
private val arguments by navArgs<GenreDetailsFragmentArgs>()
@ -43,22 +45,31 @@ class GenreDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_
}
private lateinit var genre: Genre
private lateinit var songAdapter: SongAdapter
private fun setUpTransitions() {
val transform = MaterialContainerTransform()
transform.setAllContainerColors(ATHUtil.resolveColor(requireContext(), R.attr.colorSurface))
sharedElementEnterTransition = transform
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setUpTransitions()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true)
mainActivity.setBottomBarVisibility(View.GONE)
mainActivity.addMusicServiceEventListener(detailsViewModel)
mainActivity.setSupportActionBar(toolbar)
progressIndicator.hide()
ViewCompat.setTransitionName(container, "genre")
genre = arguments.extraGenre
toolbar?.title = arguments.extraGenre.name
setupRecyclerView()
detailsViewModel.getSongs().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
detailsViewModel.getSongs().observe(viewLifecycleOwner, {
songs(it)
})
detailsViewModel.getGenre().observe(viewLifecycleOwner, androidx.lifecycle.Observer {
genre = it
toolbar?.title = it.name
})
}
private fun setupRecyclerView() {
@ -77,7 +88,9 @@ class GenreDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_
}
fun songs(songs: List<Song>) {
songAdapter.swapDataSet(songs)
progressIndicator.hide()
if (songs.isNotEmpty()) songAdapter.swapDataSet(songs)
else songAdapter.swapDataSet(emptyList())
}
private fun getEmojiByUnicode(unicode: Int): String {

View file

@ -16,13 +16,20 @@ package io.github.muntashirakon.music.fragments.genres
import android.os.Bundle
import android.view.View
import androidx.core.os.bundleOf
import androidx.lifecycle.Observer
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import io.github.muntashirakon.music.EXTRA_GENRE
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.GenreAdapter
import io.github.muntashirakon.music.fragments.base.AbsRecyclerViewFragment
import io.github.muntashirakon.music.interfaces.IGenreClickListener
import io.github.muntashirakon.music.model.Genre
class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>() {
class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(),
IGenreClickListener {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
libraryViewModel.getGenre().observe(viewLifecycleOwner, Observer {
@ -39,7 +46,7 @@ class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager
override fun createAdapter(): GenreAdapter {
val dataSet = if (adapter == null) ArrayList() else adapter!!.dataSet
return GenreAdapter(requireActivity(), dataSet, R.layout.item_list_no_image)
return GenreAdapter(requireActivity(), dataSet, R.layout.item_list_no_image, this)
}
override val emptyMessage: Int
@ -54,4 +61,15 @@ class GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager
return GenresFragment()
}
}
override fun onClickGenre(genre: Genre, view: View) {
findNavController().navigate(
R.id.genreDetailsFragment,
bundleOf(EXTRA_GENRE to genre),
null,
FragmentNavigatorExtras(
view to "genre"
)
)
}
}

View file

@ -29,17 +29,13 @@ import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.common.ATHToolbarActivity
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import io.github.muntashirakon.music.HISTORY_PLAYLIST
import io.github.muntashirakon.music.LAST_ADDED_PLAYLIST
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.TOP_PLAYED_PLAYLIST
import io.github.muntashirakon.music.*
import io.github.muntashirakon.music.adapter.HomeAdapter
import io.github.muntashirakon.music.dialogs.CreatePlaylistDialog
import io.github.muntashirakon.music.dialogs.ImportPlaylistDialog
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
import io.github.muntashirakon.music.glide.ProfileBannerGlideRequest
import io.github.muntashirakon.music.glide.UserProfileGlideRequest
import io.github.muntashirakon.music.state.NowPlayingPanelState
import io.github.muntashirakon.music.util.NavigationUtil
import io.github.muntashirakon.music.util.PreferenceUtil
import com.bumptech.glide.Glide
@ -68,14 +64,14 @@ class HomeFragment :
lastAdded.setOnClickListener {
findNavController().navigate(
R.id.detailListFragment,
bundleOf("type" to LAST_ADDED_PLAYLIST)
bundleOf(EXTRA_PLAYLIST_TYPE to LAST_ADDED_PLAYLIST)
)
}
topPlayed.setOnClickListener {
findNavController().navigate(
R.id.detailListFragment,
bundleOf("type" to TOP_PLAYED_PLAYLIST)
bundleOf(EXTRA_PLAYLIST_TYPE to TOP_PLAYED_PLAYLIST)
)
}
@ -86,7 +82,7 @@ class HomeFragment :
history.setOnClickListener {
findNavController().navigate(
R.id.detailListFragment,
bundleOf("type" to HISTORY_PLAYLIST)
bundleOf(EXTRA_PLAYLIST_TYPE to HISTORY_PLAYLIST)
)
}

View file

@ -21,8 +21,6 @@ import android.speech.RecognizerIntent
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.view.inputmethod.InputMethodManager
import androidx.core.content.ContextCompat.getSystemService
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
@ -32,6 +30,7 @@ import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.adapter.SearchAdapter
import io.github.muntashirakon.music.extensions.accentColor
import io.github.muntashirakon.music.extensions.dipToPix
import io.github.muntashirakon.music.extensions.focusAndShowKeyboard
import io.github.muntashirakon.music.extensions.showToast
import io.github.muntashirakon.music.fragments.base.AbsMainActivityFragment
import com.google.android.material.textfield.TextInputEditText
@ -54,17 +53,16 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa
mainActivity.setSupportActionBar(toolbar)
libraryViewModel.clearSearchResult()
setupRecyclerView()
searchView.addTextChangedListener(this)
searchView.apply {
addTextChangedListener(this@SearchFragment)
focusAndShowKeyboard()
}
voiceSearch.setOnClickListener { startMicSearch() }
clearText.setOnClickListener { searchView.clearText() }
keyboardPopup.apply {
accentColor()
setOnClickListener {
val inputManager = getSystemService(
requireContext(),
InputMethodManager::class.java
)
inputManager?.showSoftInput(searchView, InputMethodManager.SHOW_IMPLICIT)
searchView.focusAndShowKeyboard()
}
}
if (savedInstanceState != null) {

View file

@ -25,7 +25,7 @@ import com.bumptech.glide.request.animation.GlideAnimation
abstract class SingleColorTarget(view: ImageView) : BitmapPaletteTarget(view) {
protected val defaultFooterColor: Int
private val defaultFooterColor: Int
get() = ATHUtil.resolveColor(view.context, R.attr.colorControlNormal)
abstract fun onColorReady(color: Int)

View file

@ -0,0 +1,8 @@
package io.github.muntashirakon.music.interfaces
import android.view.View
import io.github.muntashirakon.music.model.Genre
interface IGenreClickListener {
fun onClickGenre(genre: Genre, view: View)
}

View file

@ -0,0 +1,13 @@
package io.github.muntashirakon.music.interfaces
import io.github.muntashirakon.music.model.Album
import io.github.muntashirakon.music.model.Artist
import io.github.muntashirakon.music.model.Genre
interface IHomeClickListener {
fun onAlbumClick(album: Album)
fun onArtistClick(artist: Artist)
fun onGenreClick(genre: Genre)
}

View file

@ -30,11 +30,12 @@ import androidx.fragment.app.DialogFragment
import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager.widget.ViewPager
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEDialogPreference
import io.github.muntashirakon.music.App
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.extensions.colorButtons
import io.github.muntashirakon.music.extensions.colorControlNormal
import io.github.muntashirakon.music.extensions.materialDialog
import io.github.muntashirakon.music.extensions.*
import io.github.muntashirakon.music.fragments.AlbumCoverStyle
import io.github.muntashirakon.music.fragments.AlbumCoverStyle.*
import io.github.muntashirakon.music.util.NavigationUtil
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.ViewUtil
import com.bumptech.glide.Glide
@ -115,7 +116,7 @@ class AlbumCoverStylePreferenceDialog : DialogFragment(),
val proText = layout.findViewById<TextView>(R.id.proText)
Glide.with(context).load(albumCoverStyle.drawableResId).into(image)
title.setText(albumCoverStyle.titleRes)
proText.setText(R.string.pro)
proText.hide()
return layout
}

View file

@ -29,13 +29,14 @@ import androidx.fragment.app.DialogFragment
import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager.widget.ViewPager
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEDialogPreference
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.extensions.colorButtons
import io.github.muntashirakon.music.extensions.colorControlNormal
import io.github.muntashirakon.music.extensions.materialDialog
import io.github.muntashirakon.music.fragments.NowPlayingScreen.*
import io.github.muntashirakon.music.util.PreferenceUtil
import io.github.muntashirakon.music.util.ViewUtil
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.*
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.PreferenceUtil
import code.name.monkey.retromusic.util.ViewUtil
import com.bumptech.glide.Glide
class NowPlayingScreenPreference @JvmOverloads constructor(
@ -119,7 +120,7 @@ private class NowPlayingScreenAdapter(private val context: Context) : PagerAdapt
val proText = layout.findViewById<TextView>(R.id.proText)
Glide.with(context).load(nowPlayingScreen.drawableResId).into(image)
title.setText(nowPlayingScreen.titleRes)
proText.setText(R.string.pro)
proText.hide()
return layout
}

View file

@ -26,7 +26,7 @@ class RealSearchRepository(
private val roomRepository: RoomRepository,
private val genreRepository: GenreRepository,
) {
suspend fun searchAll(context: Context, query: String?): MutableList<Any> {
fun searchAll(context: Context, query: String?): MutableList<Any> {
val results = mutableListOf<Any>()
query?.let { searchString ->
val songs = songRepository.songs(searchString)
@ -53,14 +53,14 @@ class RealSearchRepository(
results.add(context.resources.getString(R.string.genres))
results.addAll(genres)
}
val playlist = roomRepository.playlistWithSongs().filter { playlist ->
playlist.playlistEntity.playlistName.toLowerCase(Locale.getDefault())
.contains(searchString.toLowerCase(Locale.getDefault()))
}
if (playlist.isNotEmpty()) {
results.add(context.getString(R.string.playlists))
results.addAll(playlist)
}
/* val playlist = roomRepository.playlists().filter { playlist ->
playlist.playlistName.toLowerCase(Locale.getDefault())
.contains(searchString.toLowerCase(Locale.getDefault()))
}
if (playlist.isNotEmpty()) {
results.add(context.getString(R.string.playlists))
results.addAll(playlist)
}*/
}
return results
}

View file

@ -27,6 +27,8 @@ import androidx.core.text.HtmlCompat
import androidx.media.app.NotificationCompat.MediaStyle
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.activities.MainActivity
import io.github.muntashirakon.music.db.PlaylistEntity
import io.github.muntashirakon.music.db.toSongEntity
import io.github.muntashirakon.music.glide.SongGlideRequest
import io.github.muntashirakon.music.glide.palette.BitmapPaletteWrapper
import io.github.muntashirakon.music.service.MusicService
@ -38,140 +40,149 @@ import com.bumptech.glide.Glide
import com.bumptech.glide.request.animation.GlideAnimation
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.target.Target
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.koin.core.KoinComponent
class PlayingNotificationImpl : PlayingNotification() {
class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
private var target: Target<BitmapPaletteWrapper>? = null
@Synchronized
override fun update() {
stopped = false
GlobalScope.launch {
val song = service.currentSong
val playlist: PlaylistEntity? = MusicUtil.repository.favoritePlaylist()
val isPlaying = service.isPlaying
val isFavorite = if (playlist != null) {
val songEntity = song.toSongEntity(playlist.playListId)
MusicUtil.repository.isFavoriteSong(songEntity).isNotEmpty()
} else false
val song = service.currentSong
val isPlaying = service.isPlaying
val isFavorite = MusicUtil.isFavorite(service, song)
val playButtonResId =
if (isPlaying) R.drawable.ic_pause_white_48dp else R.drawable.ic_play_arrow_white_48dp
val favoriteResId =
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
val playButtonResId =
if (isPlaying) R.drawable.ic_pause_white_48dp else R.drawable.ic_play_arrow_white_48dp
val favoriteResId =
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
val action = Intent(service, MainActivity::class.java)
action.putExtra(MainActivity.EXPAND_PANEL, PreferenceUtil.isExpandPanel)
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
val clickIntent =
PendingIntent.getActivity(service, 0, action, PendingIntent.FLAG_UPDATE_CURRENT)
val action = Intent(service, MainActivity::class.java)
action.putExtra(MainActivity.EXPAND_PANEL, PreferenceUtil.isExpandPanel)
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
val clickIntent =
PendingIntent.getActivity(service, 0, action, PendingIntent.FLAG_UPDATE_CURRENT)
val serviceName = ComponentName(service, MusicService::class.java)
val intent = Intent(ACTION_QUIT)
intent.component = serviceName
val deleteIntent = PendingIntent.getService(service, 0, intent, 0)
val serviceName = ComponentName(service, MusicService::class.java)
val intent = Intent(ACTION_QUIT)
intent.component = serviceName
val deleteIntent = PendingIntent.getService(service, 0, intent, 0)
val bigNotificationImageSize = service.resources
.getDimensionPixelSize(R.dimen.notification_big_image_size)
service.runOnUiThread {
if (target != null) {
Glide.clear(target)
}
target = SongGlideRequest.Builder.from(Glide.with(service), song)
.checkIgnoreMediaStore(service)
.generatePalette(service).build()
.centerCrop()
.into(object : SimpleTarget<BitmapPaletteWrapper>(
bigNotificationImageSize,
bigNotificationImageSize
) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
glideAnimation: GlideAnimation<in BitmapPaletteWrapper>
val bigNotificationImageSize = service.resources
.getDimensionPixelSize(R.dimen.notification_big_image_size)
service.runOnUiThread {
if (target != null) {
Glide.clear(target)
}
target = SongGlideRequest.Builder.from(Glide.with(service), song)
.checkIgnoreMediaStore(service)
.generatePalette(service).build()
.centerCrop()
.into(object : SimpleTarget<BitmapPaletteWrapper>(
bigNotificationImageSize,
bigNotificationImageSize
) {
update(
resource.bitmap,
RetroColorUtil.getColor(resource.palette, Color.TRANSPARENT)
)
}
override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
super.onLoadFailed(e, errorDrawable)
update(null, Color.TRANSPARENT)
}
fun update(bitmap: Bitmap?, color: Int) {
var bitmapFinal = bitmap
if (bitmapFinal == null) {
bitmapFinal = BitmapFactory.decodeResource(
service.resources,
R.drawable.default_audio_art
override fun onResourceReady(
resource: BitmapPaletteWrapper,
glideAnimation: GlideAnimation<in BitmapPaletteWrapper>
) {
update(
resource.bitmap,
RetroColorUtil.getColor(resource.palette, Color.TRANSPARENT)
)
}
val toggleFavorite = NotificationCompat.Action(
favoriteResId,
service.getString(R.string.action_toggle_favorite),
retrievePlaybackAction(TOGGLE_FAVORITE)
)
val playPauseAction = NotificationCompat.Action(
playButtonResId,
service.getString(R.string.action_play_pause),
retrievePlaybackAction(ACTION_TOGGLE_PAUSE)
)
val previousAction = NotificationCompat.Action(
R.drawable.ic_skip_previous_round_white_32dp,
service.getString(R.string.action_previous),
retrievePlaybackAction(ACTION_REWIND)
)
val nextAction = NotificationCompat.Action(
R.drawable.ic_skip_next_round_white_32dp,
service.getString(R.string.action_next),
retrievePlaybackAction(ACTION_SKIP)
)
override fun onLoadFailed(e: Exception?, errorDrawable: Drawable?) {
super.onLoadFailed(e, errorDrawable)
update(null, Color.TRANSPARENT)
}
val builder = NotificationCompat.Builder(
service,
NOTIFICATION_CHANNEL_ID
)
.setSmallIcon(R.drawable.ic_notification)
.setLargeIcon(bitmapFinal)
.setContentIntent(clickIntent)
.setDeleteIntent(deleteIntent)
.setContentTitle(
HtmlCompat.fromHtml(
"<b>" + song.title + "</b>",
HtmlCompat.FROM_HTML_MODE_LEGACY
fun update(bitmap: Bitmap?, color: Int) {
var bitmapFinal = bitmap
if (bitmapFinal == null) {
bitmapFinal = BitmapFactory.decodeResource(
service.resources,
R.drawable.default_audio_art
)
)
.setContentText(song.artistName)
.setSubText(
HtmlCompat.fromHtml(
"<b>" + song.albumName + "</b>",
HtmlCompat.FROM_HTML_MODE_LEGACY
)
)
.setOngoing(isPlaying)
.setShowWhen(false)
.addAction(toggleFavorite)
.addAction(previousAction)
.addAction(playPauseAction)
.addAction(nextAction)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder.setStyle(
MediaStyle()
.setMediaSession(service.mediaSession.sessionToken)
.setShowActionsInCompactView(1, 2, 3)
)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
if (Build.VERSION.SDK_INT <=
Build.VERSION_CODES.O && PreferenceUtil.isColoredNotification
) {
builder.color = color
}
}
if (stopped) {
return // notification has been stopped before loading was finished
val toggleFavorite = NotificationCompat.Action(
favoriteResId,
service.getString(R.string.action_toggle_favorite),
retrievePlaybackAction(TOGGLE_FAVORITE)
)
val playPauseAction = NotificationCompat.Action(
playButtonResId,
service.getString(R.string.action_play_pause),
retrievePlaybackAction(ACTION_TOGGLE_PAUSE)
)
val previousAction = NotificationCompat.Action(
R.drawable.ic_skip_previous_round_white_32dp,
service.getString(R.string.action_previous),
retrievePlaybackAction(ACTION_REWIND)
)
val nextAction = NotificationCompat.Action(
R.drawable.ic_skip_next_round_white_32dp,
service.getString(R.string.action_next),
retrievePlaybackAction(ACTION_SKIP)
)
val builder = NotificationCompat.Builder(
service,
NOTIFICATION_CHANNEL_ID
)
.setSmallIcon(R.drawable.ic_notification)
.setLargeIcon(bitmapFinal)
.setContentIntent(clickIntent)
.setDeleteIntent(deleteIntent)
.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
)
)
.setOngoing(isPlaying)
.setShowWhen(false)
.addAction(toggleFavorite)
.addAction(previousAction)
.addAction(playPauseAction)
.addAction(nextAction)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
builder.setStyle(
MediaStyle()
.setMediaSession(service.mediaSession.sessionToken)
.setShowActionsInCompactView(1, 2, 3)
)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
if (Build.VERSION.SDK_INT <=
Build.VERSION_CODES.O && PreferenceUtil.isColoredNotification
) {
builder.color = color
}
}
if (stopped) {
return // notification has been stopped before loading was finished
}
updateNotifyModeAndPostNotification(builder.build())
}
updateNotifyModeAndPostNotification(builder.build())
}
})
})
}
}
}

View file

@ -15,7 +15,9 @@ import android.widget.Toast
import androidx.core.content.FileProvider
import androidx.fragment.app.FragmentActivity
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.db.PlaylistEntity
import io.github.muntashirakon.music.db.SongEntity
import io.github.muntashirakon.music.db.toSongEntity
import io.github.muntashirakon.music.extensions.getLong
import io.github.muntashirakon.music.helper.MusicPlayerRemote.removeFromQueue
import io.github.muntashirakon.music.model.Artist
@ -24,8 +26,11 @@ import io.github.muntashirakon.music.model.Song
import io.github.muntashirakon.music.model.lyrics.AbsSynchronizedLyrics
import io.github.muntashirakon.music.repository.RealPlaylistRepository
import io.github.muntashirakon.music.repository.RealSongRepository
import io.github.muntashirakon.music.repository.Repository
import io.github.muntashirakon.music.repository.SongRepository
import io.github.muntashirakon.music.service.MusicService
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.jaudiotagger.audio.AudioFileIO
import org.jaudiotagger.tag.FieldKey
import org.koin.core.KoinComponent
@ -321,16 +326,21 @@ object MusicUtil : KoinComponent {
return playlist.name == context.getString(R.string.favorites)
}
val repository = get<Repository>()
fun toggleFavorite(context: Context, song: Song) {
if (isFavorite(context, song)) {
PlaylistsUtil.removeFromPlaylist(context, song, getFavoritesPlaylist(context).id)
} else {
PlaylistsUtil.addToPlaylist(
context, song, getOrCreateFavoritesPlaylist(context).id,
false
)
GlobalScope.launch {
val playlist: PlaylistEntity? = repository.favoritePlaylist()
if (playlist != null) {
val songEntity = song.toSongEntity(playlist.playListId)
val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty()
if (isFavorite) {
repository.removeSongFromPlaylist(songEntity)
} else {
repository.insertSongs(listOf(song.toSongEntity(playlist.playListId)))
}
}
context.sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED))
}
context.sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED))
}
private fun getFavoritesPlaylist(context: Context): Playlist {

View file

@ -1,6 +1,5 @@
package io.github.muntashirakon.music.util
import android.content.Context
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.net.ConnectivityManager
import android.net.NetworkInfo
@ -8,75 +7,7 @@ import androidx.core.content.ContextCompat
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import androidx.viewpager.widget.ViewPager
import io.github.muntashirakon.music.ADAPTIVE_COLOR_APP
import io.github.muntashirakon.music.ALBUM_ARTISTS_ONLY
import io.github.muntashirakon.music.ALBUM_ART_ON_LOCK_SCREEN
import io.github.muntashirakon.music.ALBUM_COVER_STYLE
import io.github.muntashirakon.music.ALBUM_COVER_TRANSFORM
import io.github.muntashirakon.music.ALBUM_DETAIL_SONG_SORT_ORDER
import io.github.muntashirakon.music.ALBUM_GRID_SIZE
import io.github.muntashirakon.music.ALBUM_GRID_SIZE_LAND
import io.github.muntashirakon.music.ALBUM_GRID_STYLE
import io.github.muntashirakon.music.ALBUM_SONG_SORT_ORDER
import io.github.muntashirakon.music.ALBUM_SORT_ORDER
import io.github.muntashirakon.music.ARTIST_ALBUM_SORT_ORDER
import io.github.muntashirakon.music.ARTIST_GRID_SIZE
import io.github.muntashirakon.music.ARTIST_GRID_SIZE_LAND
import io.github.muntashirakon.music.ARTIST_GRID_STYLE
import io.github.muntashirakon.music.ARTIST_SONG_SORT_ORDER
import io.github.muntashirakon.music.ARTIST_SORT_ORDER
import io.github.muntashirakon.music.AUDIO_DUCKING
import io.github.muntashirakon.music.AUTO_DOWNLOAD_IMAGES_POLICY
import io.github.muntashirakon.music.App
import io.github.muntashirakon.music.BLACK_THEME
import io.github.muntashirakon.music.BLUETOOTH_PLAYBACK
import io.github.muntashirakon.music.BLURRED_ALBUM_ART
import io.github.muntashirakon.music.CAROUSEL_EFFECT
import io.github.muntashirakon.music.CHOOSE_EQUALIZER
import io.github.muntashirakon.music.CLASSIC_NOTIFICATION
import io.github.muntashirakon.music.COLORED_APP_SHORTCUTS
import io.github.muntashirakon.music.COLORED_NOTIFICATION
import io.github.muntashirakon.music.DESATURATED_COLOR
import io.github.muntashirakon.music.EXPAND_NOW_PLAYING_PANEL
import io.github.muntashirakon.music.EXTRA_SONG_INFO
import io.github.muntashirakon.music.FILTER_SONG
import io.github.muntashirakon.music.GAP_LESS_PLAYBACK
import io.github.muntashirakon.music.GENERAL_THEME
import io.github.muntashirakon.music.GENRE_SORT_ORDER
import io.github.muntashirakon.music.HOME_ALBUM_GRID_STYLE
import io.github.muntashirakon.music.HOME_ARTIST_GRID_STYLE
import io.github.muntashirakon.music.IGNORE_MEDIA_STORE_ARTWORK
import io.github.muntashirakon.music.INITIALIZED_BLACKLIST
import io.github.muntashirakon.music.KEEP_SCREEN_ON
import io.github.muntashirakon.music.LANGUAGE_NAME
import io.github.muntashirakon.music.LAST_ADDED_CUTOFF
import io.github.muntashirakon.music.LAST_CHANGELOG_VERSION
import io.github.muntashirakon.music.LAST_PAGE
import io.github.muntashirakon.music.LAST_SLEEP_TIMER_VALUE
import io.github.muntashirakon.music.LIBRARY_CATEGORIES
import io.github.muntashirakon.music.LOCK_SCREEN
import io.github.muntashirakon.music.LYRICS_OPTIONS
import io.github.muntashirakon.music.NEXT_SLEEP_TIMER_ELAPSED_REALTIME
import io.github.muntashirakon.music.NOW_PLAYING_SCREEN_ID
import io.github.muntashirakon.music.PAUSE_ON_ZERO_VOLUME
import io.github.muntashirakon.music.PLAYLIST_SORT_ORDER
import io.github.muntashirakon.music.R
import io.github.muntashirakon.music.RECENTLY_PLAYED_CUTOFF
import io.github.muntashirakon.music.SAF_SDCARD_URI
import io.github.muntashirakon.music.SLEEP_TIMER_FINISH_SONG
import io.github.muntashirakon.music.SONG_GRID_SIZE
import io.github.muntashirakon.music.SONG_GRID_SIZE_LAND
import io.github.muntashirakon.music.SONG_GRID_STYLE
import io.github.muntashirakon.music.SONG_SORT_ORDER
import io.github.muntashirakon.music.START_DIRECTORY
import io.github.muntashirakon.music.TAB_TEXT_MODE
import io.github.muntashirakon.music.TOGGLE_ADD_CONTROLS
import io.github.muntashirakon.music.TOGGLE_FULL_SCREEN
import io.github.muntashirakon.music.TOGGLE_HEADSET
import io.github.muntashirakon.music.TOGGLE_HOME_BANNER
import io.github.muntashirakon.music.TOGGLE_SHUFFLE
import io.github.muntashirakon.music.TOGGLE_VOLUME
import io.github.muntashirakon.music.USER_NAME
import io.github.muntashirakon.music.*
import io.github.muntashirakon.music.extensions.getIntRes
import io.github.muntashirakon.music.extensions.getStringOrDefault
import io.github.muntashirakon.music.fragments.AlbumCoverStyle
@ -84,13 +15,7 @@ import io.github.muntashirakon.music.fragments.NowPlayingScreen
import io.github.muntashirakon.music.fragments.folder.FoldersFragment
import io.github.muntashirakon.music.helper.SortOrder.*
import io.github.muntashirakon.music.model.CategoryInfo
import io.github.muntashirakon.music.transform.CascadingPageTransformer
import io.github.muntashirakon.music.transform.DepthTransformation
import io.github.muntashirakon.music.transform.HingeTransformation
import io.github.muntashirakon.music.transform.HorizontalFlipTransformation
import io.github.muntashirakon.music.transform.NormalPageTransformer
import io.github.muntashirakon.music.transform.VerticalFlipTransformation
import io.github.muntashirakon.music.transform.VerticalStackTransformer
import io.github.muntashirakon.music.transform.*
import io.github.muntashirakon.music.util.theme.ThemeMode
import com.google.android.material.bottomnavigation.LabelVisibilityMode
import com.google.gson.Gson
@ -183,13 +108,6 @@ object PreferenceUtil {
putString(SAF_SDCARD_URI, value)
}
val selectedEqualizer
get() = sharedPreferences.getStringOrDefault(
CHOOSE_EQUALIZER,
"system"
)
val autoDownloadImagesPolicy
get() = sharedPreferences.getStringOrDefault(
AUTO_DOWNLOAD_IMAGES_POLICY,
@ -458,11 +376,6 @@ object PreferenceUtil {
putInt(LAST_SLEEP_TIMER_VALUE, value)
}
var lastPage
get() = sharedPreferences.getInt(LAST_PAGE, R.id.action_song)
set(value) = sharedPreferences.edit {
putInt(LAST_PAGE, value)
}
var nextSleepTimerElapsedRealTime
get() = sharedPreferences.getInt(
@ -486,8 +399,8 @@ object PreferenceUtil {
val position = sharedPreferences.getStringOrDefault(
HOME_ARTIST_GRID_STYLE, "0"
).toInt()
val typedArray =
App.getContext().resources.obtainTypedArray(R.array.pref_home_grid_style_layout)
val typedArray = App.getContext()
.resources.obtainTypedArray(R.array.pref_home_grid_style_layout)
val layoutRes = typedArray.getResourceId(position, 0)
typedArray.recycle()
return if (layoutRes == 0) {
@ -497,10 +410,12 @@ object PreferenceUtil {
val homeAlbumGridStyle: Int
get() {
val position = sharedPreferences.getStringOrDefault(HOME_ALBUM_GRID_STYLE, "4").toInt()
val typedArray =
App.getContext().resources.obtainTypedArray(R.array.pref_home_grid_style_layout)
val layoutRes = typedArray.getResourceId(position, 0)
val position = sharedPreferences.getStringOrDefault(
HOME_ALBUM_GRID_STYLE, "4"
).toInt()
val typedArray = App.getContext()
.resources.obtainTypedArray(R.array.pref_home_grid_style_layout)
val layoutRes = typedArray.getResourceId(position, 4)
typedArray.recycle()
return if (layoutRes == 0) {
R.layout.item_artist
@ -510,7 +425,7 @@ object PreferenceUtil {
val tabTitleMode: Int
get() {
return when (sharedPreferences.getStringOrDefault(
TAB_TEXT_MODE, "0"
TAB_TEXT_MODE, "1"
).toInt()) {
1 -> LabelVisibilityMode.LABEL_VISIBILITY_LABELED
0 -> LabelVisibilityMode.LABEL_VISIBILITY_AUTO
@ -639,32 +554,9 @@ object PreferenceUtil {
}
fun getRecentlyPlayedCutoffTimeMillis(): Long {
return getCutoffTimeMillis(RECENTLY_PLAYED_CUTOFF)
}
fun getRecentlyPlayedCutoffText(context: Context): String? {
return getCutoffText(RECENTLY_PLAYED_CUTOFF, context)
}
private fun getCutoffText(
cutoff: String,
context: Context
): String? {
return when (sharedPreferences.getString(cutoff, "")) {
"today" -> context.getString(R.string.today)
"this_week" -> context.getString(R.string.this_week)
"past_seven_days" -> context.getString(R.string.past_seven_days)
"past_three_months" -> context.getString(R.string.past_three_months)
"this_year" -> context.getString(R.string.this_year)
"this_month" -> context.getString(R.string.this_month)
else -> context.getString(R.string.this_month)
}
}
private fun getCutoffTimeMillis(cutoff: String): Long {
val calendarUtil = CalendarUtil()
val interval: Long
interval = when (sharedPreferences.getString(cutoff, "")) {
interval = when (sharedPreferences.getString(RECENTLY_PLAYED_CUTOFF, "")) {
"today" -> calendarUtil.elapsedToday
"this_week" -> calendarUtil.elapsedWeek
"past_seven_days" -> calendarUtil.getElapsedDays(7)
@ -690,5 +582,4 @@ object PreferenceUtil {
}
return (System.currentTimeMillis() - interval) / 1000
}
}

View file

@ -72,7 +72,7 @@ class RingtoneManager(val context: Context) {
return false
}
fun getDialog(context: Context): AlertDialog {
fun getDialog(context: Context) {
return MaterialAlertDialogBuilder(context, R.style.MaterialAlertDialogTheme)
.setTitle(R.string.dialog_title_set_ringtone)
.setMessage(R.string.dialog_message_set_ringtone)
@ -82,7 +82,7 @@ class RingtoneManager(val context: Context) {
context.startActivity(intent)
}
.setNegativeButton(android.R.string.cancel, null)
.create()
.create().show()
}
}
}