diff --git a/app/build.gradle b/app/build.gradle index b4d7fbf0..f8c719dc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -22,7 +22,7 @@ android { vectorDrawables.useSupportLibrary = true applicationId "code.name.monkey.retromusic" - versionCode 403 + versionCode 404 versionName '3.4.850' multiDexEnabled true @@ -175,6 +175,7 @@ dependencies { implementation 'com.anjlab.android.iab.v3:library:1.1.0' implementation 'com.r0adkll:slidableactivity:2.1.0' implementation 'com.heinrichreimersoftware:material-intro:1.6' + implementation 'me.zhanghai.android.fastscroll:library:1.1.0' def dagger_version = "2.23.1" implementation "com.google.dagger:dagger:$dagger_version" diff --git a/app/src/main/assets/contributors.json b/app/src/main/assets/contributors.json index e84023c3..48116569 100644 --- a/app/src/main/assets/contributors.json +++ b/app/src/main/assets/contributors.json @@ -12,21 +12,15 @@ "profile_image": "https://i.imgur.com/Q5Nsx1R.jpg" }, { - "name": "Gaming Inc.", + "name": "GameSpeck", "summary": "Telegram group maintainer", - "link": "https://www.gaminginc.tk/", - "profile_image": "https://i.imgur.com/pfvN7d9.png" + "link": "https://t.me/GameSpeck", + "profile_image": "https://imgur.com/B15Kb9a.jpg" }, { "name": "Milind Goel", "summary": "Github & Telegram maintainer", "link": "https://t.me/MilindGoel15", "profile_image": "https://i.imgur.com/Bz4De21_d.jpg" - }, - { - "name": "Abilas Sathiya", - "summary": "Design & Suggestions", - "link": "https://t.me/@abs2606", - "profile_image": "https://i.imgur.com/MUyEWlx.jpg" } ] \ No newline at end of file diff --git a/app/src/main/assets/retro-changelog.html b/app/src/main/assets/retro-changelog.html index 02168721..2b7a291d 100644 --- a/app/src/main/assets/retro-changelog.html +++ b/app/src/main/assets/retro-changelog.html @@ -1 +1 @@ -

v3.4.850

v3.4.800

v3.4.700

v3.4.600

v3.4.500

v3.3.200

v.3.3.100

v3.3.000

v3.2.240

v3.2.220

v3.2.203

v3.2.135

v3.2.125

v3.2.120

v3.2.105

v3.2.100

v3.2.000

v3.1.900

v3.1.850

v3.1.800

v3.1.700

v3.1.400

v3.1.300

If you see entire app white or dark or black select same theme in settings to fix

FAQ's

*If you face any UI related issues you clear app data and cache, if its not working try to uninstall and install again.

\ No newline at end of file +

v3.4.850

v3.4.800

v3.4.700

v3.4.600

v3.4.500

v3.3.200

v.3.3.100

v3.3.000

v3.2.240

v3.2.220

v3.2.203

v3.2.135

v3.2.125

v3.2.120

v3.2.105

v3.2.100

v3.2.000

v3.1.900

v3.1.850

v3.1.800

v3.1.700

v3.1.400

v3.1.300

If you see entire app white or dark or black select same theme in settings to fix

FAQ's

*If you face any UI related issues you clear app data and cache, if its not working try to uninstall and install again.

\ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/AlbumDetailsActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/AlbumDetailsActivity.kt index ce145306..d4987eb8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/AlbumDetailsActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/AlbumDetailsActivity.kt @@ -187,14 +187,14 @@ class AlbumDetailsActivity : AbsSlidingMusicPanelActivity(), AlbumDetailsView, C albumText.text = String.format( "%s • %s", album.artistName, - MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(this, album.songs)) + MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs)) ) } else { albumText.text = String.format( "%s • %s • %s", album.artistName, MusicUtil.getYearString(album.year), - MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(this, album.songs)) + MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(album.songs)) ) } loadAlbumCover() diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/ArtistDetailActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/ArtistDetailActivity.kt index 0873ad44..5414af1b 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/ArtistDetailActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/ArtistDetailActivity.kt @@ -219,7 +219,7 @@ class ArtistDetailActivity : AbsSlidingMusicPanelActivity(), ArtistDetailsView, text.text = String.format( "%s • %s", MusicUtil.getArtistInfoString(this, artist), - MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(this, artist.songs)) + MusicUtil.getReadableDurationString(MusicUtil.getTotalDuration(artist.songs)) ) songAdapter.swapDataSet(artist.songs) diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/GenreDetailsActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/GenreDetailsActivity.kt index 290f8779..13e9a8f1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/GenreDetailsActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/GenreDetailsActivity.kt @@ -116,7 +116,7 @@ class GenreDetailsActivity : AbsSlidingMusicPanelActivity(), CabHolder, GenreDet private fun setupRecyclerView() { ViewUtil.setUpFastScrollRecyclerViewColor(this, recyclerView) - songAdapter = ShuffleButtonSongAdapter(this, ArrayList(), R.layout.item_list, false, this) + songAdapter = ShuffleButtonSongAdapter(this, ArrayList(), R.layout.item_list, this) recyclerView.apply { itemAnimator = DefaultItemAnimator() layoutManager = LinearLayoutManager(this@GenreDetailsActivity) diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt index 4d4c3743..a8fee264 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/PlaylistDetailActivity.kt @@ -77,7 +77,7 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli recyclerView.layoutManager = LinearLayoutManager(this) if (playlist is AbsCustomPlaylist) { - adapter = PlaylistSongAdapter(this, ArrayList(), R.layout.item_list, false, this) + adapter = PlaylistSongAdapter(this, ArrayList(), R.layout.item_list, this) recyclerView.adapter = adapter } else { recyclerViewDragDropManager = RecyclerViewDragDropManager() @@ -85,7 +85,6 @@ class PlaylistDetailActivity : AbsSlidingMusicPanelActivity(), CabHolder, Playli adapter = OrderablePlaylistSongAdapter(this, ArrayList(), R.layout.item_list, - false, this, object : OrderablePlaylistSongAdapter.OnMoveItemListener { override fun onMoveItem(fromPosition: Int, toPosition: Int) { diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.java b/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.java index 83273edc..fbafe636 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.java +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.java @@ -22,22 +22,39 @@ import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; - import androidx.annotation.NonNull; import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.RecyclerView; - -import com.google.android.material.checkbox.MaterialCheckBox; - -import java.util.List; - import code.name.monkey.appthemehelper.ThemeStore; import code.name.monkey.retromusic.R; import code.name.monkey.retromusic.model.CategoryInfo; import code.name.monkey.retromusic.util.SwipeAndDragHelper; +import com.google.android.material.checkbox.MaterialCheckBox; +import java.util.List; + +public class CategoryInfoAdapter extends RecyclerView.Adapter + implements SwipeAndDragHelper.ActionCompletionContract { + + static class ViewHolder extends RecyclerView.ViewHolder { + + MaterialCheckBox checkBox; + + View dragView; + + TextView title; + + ViewHolder(View view) { + super(view); + checkBox = view.findViewById(R.id.checkbox); + checkBox.setButtonTintList( + ColorStateList.valueOf(ThemeStore.Companion.accentColor(checkBox.getContext()))); + title = view.findViewById(R.id.title); + dragView = view.findViewById(R.id.drag_view); + } + } -public class CategoryInfoAdapter extends RecyclerView.Adapter implements SwipeAndDragHelper.ActionCompletionContract { private List categoryInfos; + private ItemTouchHelper touchHelper; public CategoryInfoAdapter(@NonNull List categoryInfos) { @@ -46,52 +63,6 @@ public class CategoryInfoAdapter extends RecyclerView.Adapter { - if (!(categoryInfo.visible && isLastCheckedCategory(categoryInfo))) { - categoryInfo.visible = !categoryInfo.visible; - holder.checkBox.setChecked(categoryInfo.visible); - } else { - Toast.makeText(holder.itemView.getContext(), R.string.you_have_to_select_at_least_one_category, Toast.LENGTH_SHORT).show(); - } - }); - - holder.dragView.setOnTouchListener((view, event) -> { - if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { - touchHelper.startDrag(holder); - } - return false; - } - ); - } - - @Override - public int getItemCount() { - return categoryInfos.size(); - } - - @Override - public void onViewMoved(int oldPosition, int newPosition) { - CategoryInfo categoryInfo = categoryInfos.get(oldPosition); - categoryInfos.remove(oldPosition); - categoryInfos.add(newPosition, categoryInfo); - notifyItemMoved(oldPosition, newPosition); - } - public void attachToRecyclerView(RecyclerView recyclerView) { touchHelper.attachToRecyclerView(recyclerView); } @@ -106,26 +77,62 @@ public class CategoryInfoAdapter extends RecyclerView.Adapter { + if (!(categoryInfo.visible && isLastCheckedCategory(categoryInfo))) { + categoryInfo.visible = !categoryInfo.visible; + holder.checkBox.setChecked(categoryInfo.visible); + } else { + Toast.makeText(holder.itemView.getContext(), R.string.you_have_to_select_at_least_one_category, + Toast.LENGTH_SHORT).show(); + } + }); + + holder.dragView.setOnTouchListener((view, event) -> { + if (event.getActionMasked() == MotionEvent.ACTION_DOWN) { + touchHelper.startDrag(holder); + } + return false; + } + ); + } + + @Override + @NonNull + public CategoryInfoAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.preference_dialog_library_categories_listitem, parent, false); + return new ViewHolder(view); + } + + @Override + public void onViewMoved(int oldPosition, int newPosition) { + CategoryInfo categoryInfo = categoryInfos.get(oldPosition); + categoryInfos.remove(oldPosition); + categoryInfos.add(newPosition, categoryInfo); + notifyItemMoved(oldPosition, newPosition); + } + private boolean isLastCheckedCategory(CategoryInfo categoryInfo) { if (categoryInfo.visible) { for (CategoryInfo c : categoryInfos) { - if (c != categoryInfo && c.visible) return false; + if (c != categoryInfo && c.visible) { + return false; + } } } return true; } - - static class ViewHolder extends RecyclerView.ViewHolder { - MaterialCheckBox checkBox; - TextView title; - View dragView; - - ViewHolder(View view) { - super(view); - checkBox = view.findViewById(R.id.checkbox); - checkBox.setButtonTintList(ColorStateList.valueOf(ThemeStore.Companion.accentColor(checkBox.getContext()))); - title = view.findViewById(R.id.title); - dragView = view.findViewById(R.id.drag_view); - } - } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/ContributorAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/ContributorAdapter.kt index df7fec52..2042e3c5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/ContributorAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/ContributorAdapter.kt @@ -1,7 +1,9 @@ package code.name.monkey.retromusic.adapter import android.app.Activity -import android.view.* +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import code.name.monkey.retromusic.R @@ -11,64 +13,64 @@ import code.name.monkey.retromusic.views.CircularImageView import com.bumptech.glide.Glide class ContributorAdapter( - private var contributors: List + private var contributors: List ) : RecyclerView.Adapter() { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - return if (viewType == HEADER) { - ViewHolder( - LayoutInflater.from(parent.context).inflate( - R.layout.item_contributor_header, - parent, - false - ) - ) - } else ViewHolder( - LayoutInflater.from(parent.context).inflate( - R.layout.item_contributor, - parent, - false - ) - ) - } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { + return if (viewType == HEADER) { + ViewHolder( + LayoutInflater.from(parent.context).inflate( + R.layout.item_contributor_header, + parent, + false + ) + ) + } else ViewHolder( + LayoutInflater.from(parent.context).inflate( + R.layout.item_contributor, + parent, + false + ) + ) + } - companion object { - const val HEADER: Int = 0 - const val ITEM: Int = 1 - } + companion object { + const val HEADER: Int = 0 + const val ITEM: Int = 1 + } - override fun getItemViewType(position: Int): Int { - return if (position == 0) { - HEADER - } else { - ITEM - } - } + override fun getItemViewType(position: Int): Int { + return if (position == 0) { + HEADER + } else { + ITEM + } + } - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - val contributor = contributors[position] - holder.bindData(contributor) - holder.itemView.setOnClickListener { - openUrl(it?.context as Activity, contributors[position].link) - } - } + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val contributor = contributors[position] + holder.bindData(contributor) + holder.itemView.setOnClickListener { + openUrl(it?.context as Activity, contributors[position].link) + } + } - override fun getItemCount(): Int { - return contributors.size - } + override fun getItemCount(): Int { + return contributors.size + } - inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val title: TextView = itemView.findViewById(R.id.title) - val text: TextView = itemView.findViewById(R.id.text) - val image: CircularImageView = itemView.findViewById(R.id.icon) + inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val title: TextView = itemView.findViewById(R.id.title) + val text: TextView = itemView.findViewById(R.id.text) + val image: CircularImageView = itemView.findViewById(R.id.icon) - internal fun bindData(contributor: Contributor) { - title.text = contributor.name - text.text = contributor.summary - println(contributor.profileImage) - Glide.with(image.context).load(contributor.profileImage) - .error(R.drawable.ic_account_white_24dp) - .placeholder(R.drawable.ic_account_white_24dp).dontAnimate().into(image) - } - } + internal fun bindData(contributor: Contributor) { + title.text = contributor.name + text.text = contributor.summary + println(contributor.profileImage) + Glide.with(image.context).load(contributor.profileImage) + .error(R.drawable.ic_account_white_24dp) + .placeholder(R.drawable.ic_account_white_24dp).dontAnimate().into(image) + } + } } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/GenreAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/GenreAdapter.kt index d8166e4f..ae5ed811 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/GenreAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/GenreAdapter.kt @@ -9,15 +9,19 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import code.name.monkey.retromusic.model.Genre import code.name.monkey.retromusic.util.NavigationUtil -import java.util.* +import java.util.ArrayList +import java.util.Locale /** * @author Hemanth S (h4h13). */ class GenreAdapter( - private val activity: Activity, dataSet: ArrayList, private val mItemLayoutRes: Int + private val activity: Activity, + dataSet: ArrayList, + private val mItemLayoutRes: Int ) : RecyclerView.Adapter() { + var dataSet = ArrayList() private set @@ -32,7 +36,12 @@ class GenreAdapter( override fun onBindViewHolder(holder: ViewHolder, position: Int) { val genre = dataSet[position] holder.title?.text = genre.name - holder.text?.text = String.format(Locale.getDefault(), "%d %s", genre.songCount, if (genre.songCount > 1) activity.getString(R.string.songs) else activity.getString(R.string.song)) + holder.text?.text = String.format( + Locale.getDefault(), + "%d %s", + genre.songCount, + if (genre.songCount > 1) activity.getString(R.string.songs) else activity.getString(R.string.song) + ) } override fun getItemCount(): Int { diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/HomeAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/HomeAdapter.kt index d0218318..10ce8b0a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/HomeAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/HomeAdapter.kt @@ -23,7 +23,8 @@ import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.util.PreferenceUtil class HomeAdapter( - private val activity: AppCompatActivity, private val displayMetrics: DisplayMetrics + private val activity: AppCompatActivity, + private val displayMetrics: DisplayMetrics ) : RecyclerView.Adapter() { private var list = ArrayList() @@ -137,14 +138,9 @@ class HomeAdapter( if (songs.isNotEmpty()) { recyclerView.apply { show() - val songAdapter = SongAdapter( - activity, songs, R.layout.item_album_card, false, null - ) - layoutManager = GridLayoutManager( - activity, 1, GridLayoutManager.HORIZONTAL, false - ) + val songAdapter = SongAdapter(activity, songs, R.layout.item_album_card, null) + layoutManager = GridLayoutManager(activity, 1, GridLayoutManager.HORIZONTAL, false) adapter = songAdapter - } title.text = activity.getString(titleRes) } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt index dc5c066d..bd479725 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/SearchAdapter.kt @@ -23,7 +23,8 @@ import com.bumptech.glide.Glide import android.util.Pair as UtilPair class SearchAdapter( - private val activity: AppCompatActivity, private var dataSet: List? + private val activity: AppCompatActivity, + private var dataSet: List? ) : RecyclerView.Adapter() { fun swapDataSet(dataSet: MutableList) { @@ -39,7 +40,13 @@ class SearchAdapter( } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - return if (viewType == HEADER) ViewHolder(LayoutInflater.from(activity).inflate(R.layout.sub_header, parent, false), viewType) + return if (viewType == HEADER) ViewHolder( + LayoutInflater.from(activity).inflate( + R.layout.sub_header, + parent, + false + ), viewType + ) else ViewHolder(LayoutInflater.from(activity).inflate(R.layout.item_list, parent, false), viewType) } @@ -51,14 +58,14 @@ class SearchAdapter( holder.title?.text = album.title holder.text?.text = album.artistName SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) - .checkIgnoreMediaStore(activity).build().into(holder.image) + .checkIgnoreMediaStore(activity).build().into(holder.image) } ARTIST -> { val artist = dataSet?.get(position) as Artist holder.title?.text = artist.name holder.text?.text = MusicUtil.getArtistInfoString(activity, artist) ArtistGlideRequest.Builder.from(Glide.with(activity), artist).build() - .into(holder.image) + .into(holder.image) } SONG -> { val song = dataSet?.get(position) as Song @@ -108,11 +115,17 @@ class SearchAdapter( val item = dataSet!![adapterPosition] when (itemViewType) { ALBUM -> { - val options = ActivityOptions.makeSceneTransitionAnimation(activity, UtilPair.create(image, activity.getString(R.string.transition_album_art))) + val options = ActivityOptions.makeSceneTransitionAnimation( + activity, + UtilPair.create(image, activity.getString(R.string.transition_album_art)) + ) NavigationUtil.goToAlbumOptions(activity, (item as Album).id, options) } ARTIST -> { - val options = ActivityOptions.makeSceneTransitionAnimation(activity, UtilPair.create(image, activity.getString(R.string.transition_artist_image))) + val options = ActivityOptions.makeSceneTransitionAnimation( + activity, + UtilPair.create(image, activity.getString(R.string.transition_artist_image)) + ) NavigationUtil.goToArtistOptions(activity, (item as Artist).id, options) } GENRE -> { diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/SongFileAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/SongFileAdapter.kt index 60d2d855..9bcb3c8c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/SongFileAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/SongFileAdapter.kt @@ -12,37 +12,38 @@ import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import code.name.monkey.retromusic.glide.audiocover.AudioFileCover import code.name.monkey.retromusic.interfaces.CabHolder +import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.RetroUtil import com.bumptech.glide.Glide import com.bumptech.glide.load.engine.DiskCacheStrategy import com.bumptech.glide.signature.MediaStoreSignature -import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView +import me.zhanghai.android.fastscroll.PopupTextProvider import java.io.File import java.text.DecimalFormat -import java.util.* +import java.util.ArrayList import kotlin.math.log10 import kotlin.math.pow class SongFileAdapter( - private val activity: AppCompatActivity, - private var dataSet: List?, - private val itemLayoutRes: Int, - private val callbacks: Callbacks?, - cabHolder: CabHolder? + private val activity: AppCompatActivity, + private var dataSet: List, + private val itemLayoutRes: Int, + private val callbacks: Callbacks?, + cabHolder: CabHolder? ) : AbsMultiSelectAdapter( - activity, cabHolder, R.menu.menu_media_selection -), FastScrollRecyclerView.SectionedAdapter { + activity, cabHolder, R.menu.menu_media_selection +), PopupTextProvider { init { this.setHasStableIds(true) } override fun getItemViewType(position: Int): Int { - return if (dataSet!![position].isDirectory) FOLDER else FILE + return if (dataSet[position].isDirectory) FOLDER else FILE } override fun getItemId(position: Int): Long { - return dataSet!![position].hashCode().toLong() + return dataSet[position].hashCode().toLong() } fun swapDataSet(songFiles: List) { @@ -55,7 +56,7 @@ class SongFileAdapter( } override fun onBindViewHolder(holder: ViewHolder, index: Int) { - val file = dataSet!![index] + val file = dataSet[index] holder.itemView.isActivated = isChecked(file) holder.title?.text = getFileTitle(file) if (holder.text != null) { @@ -87,24 +88,23 @@ class SongFileAdapter( it.setImageResource(R.drawable.ic_folder_white_24dp) } holder.imageTextContainer?.setCardBackgroundColor(ATHUtil.resolveColor(activity, R.attr.colorSurface)) - } else { val error = RetroUtil.getTintedVectorDrawable( - activity, R.drawable.ic_file_music_white_24dp, iconColor + activity, R.drawable.ic_file_music_white_24dp, iconColor ) Glide.with(activity).load(AudioFileCover(file.path)) - .diskCacheStrategy(DiskCacheStrategy.NONE).error(error).placeholder(error) - .animate(android.R.anim.fade_in) - .signature(MediaStoreSignature("", file.lastModified(), 0)).into(holder.image) + .diskCacheStrategy(DiskCacheStrategy.NONE).error(error).placeholder(error) + .animate(android.R.anim.fade_in) + .signature(MediaStoreSignature("", file.lastModified(), 0)).into(holder.image) } } override fun getItemCount(): Int { - return dataSet!!.size + return dataSet.size } override fun getIdentifier(position: Int): File? { - return dataSet!![position] + return dataSet[position] } override fun getName(`object`: File): String { @@ -116,8 +116,12 @@ class SongFileAdapter( callbacks.onMultipleItemAction(menuItem, selection) } - override fun getSectionName(position: Int): String { - return dataSet!![position].name[0].toString().toUpperCase() + override fun getPopupText(position: Int): String { + return getSectionName(position) + } + + private fun getSectionName(position: Int): String { + return MusicUtil.getSectionName(dataSet[position].name) } interface Callbacks { @@ -135,7 +139,7 @@ class SongFileAdapter( menu?.setOnClickListener { v -> val position = adapterPosition if (isPositionInRange(position)) { - callbacks.onFileMenuClicked(dataSet!![position], v) + callbacks.onFileMenuClicked(dataSet[position], v) } } } @@ -150,7 +154,7 @@ class SongFileAdapter( if (isInQuickSelectMode) { toggleChecked(position) } else { - callbacks?.onFileSelected(dataSet!![position]) + callbacks?.onFileSelected(dataSet[position]) } } } @@ -161,7 +165,7 @@ class SongFileAdapter( } private fun isPositionInRange(position: Int): Boolean { - return position >= 0 && position < dataSet!!.size + return position >= 0 && position < dataSet.size } } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt index 8de57eb4..13f2fc89 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt @@ -25,7 +25,7 @@ import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.PreferenceUtil import com.bumptech.glide.Glide -import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView +import me.zhanghai.android.fastscroll.PopupTextProvider open class AlbumAdapter( protected val activity: AppCompatActivity, @@ -37,7 +37,7 @@ open class AlbumAdapter( activity, cabHolder, R.menu.menu_media_selection -), FastScrollRecyclerView.SectionedAdapter { +), PopupTextProvider { var dataSet: ArrayList protected set @@ -168,7 +168,11 @@ open class AlbumAdapter( return songs } - override fun getSectionName(position: Int): String { + override fun getPopupText(position: Int): String { + return getSectionName(position) + } + + private fun getSectionName(position: Int): String { var sectionName: String? = null when (PreferenceUtil.getInstance(activity).albumSortOrder) { SortOrder.AlbumSortOrder.ALBUM_A_Z, SortOrder.AlbumSortOrder.ALBUM_Z_A -> sectionName = diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt index 88283c9d..722baac8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt @@ -70,7 +70,7 @@ class AlbumCoverPagerAdapter( private val layout: Int get() { - return when (PreferenceUtil.getInstance(activity).albumCoverStyle) { + return when (PreferenceUtil.getInstance(requireContext()).albumCoverStyle) { AlbumCoverStyle.NORMAL -> R.layout.fragment_album_cover AlbumCoverStyle.FLAT -> R.layout.fragment_album_flat_cover AlbumCoverStyle.CIRCLE -> R.layout.fragment_album_circle_cover @@ -95,7 +95,7 @@ class AlbumCoverPagerAdapter( savedInstanceState: Bundle? ): View? { val finalLayout = when { - PreferenceUtil.getInstance(activity).carouselEffect() -> R.layout.fragment_album_carousel_cover + PreferenceUtil.getInstance(requireContext()).carouselEffect() -> R.layout.fragment_album_carousel_cover else -> layout } val view = inflater.inflate(finalLayout, container, false) diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/HorizontalAlbumAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/HorizontalAlbumAdapter.kt index 1a85231f..644666ac 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/HorizontalAlbumAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/album/HorizontalAlbumAdapter.kt @@ -13,59 +13,59 @@ import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.model.Album import code.name.monkey.retromusic.util.MusicUtil import com.bumptech.glide.Glide -import java.util.* +import java.util.ArrayList class HorizontalAlbumAdapter( - activity: AppCompatActivity, - dataSet: ArrayList, - usePalette: Boolean, - cabHolder: CabHolder? + activity: AppCompatActivity, + dataSet: ArrayList, + usePalette: Boolean, + cabHolder: CabHolder? ) : AlbumAdapter( - activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, usePalette, cabHolder + activity, dataSet, HorizontalAdapterHelper.LAYOUT_RES, usePalette, cabHolder ) { - override fun createViewHolder(view: View, viewType: Int): ViewHolder { - val params = view.layoutParams as ViewGroup.MarginLayoutParams - HorizontalAdapterHelper.applyMarginToLayoutParams(activity, params, viewType) - return ViewHolder(view) - } + override fun createViewHolder(view: View, viewType: Int): ViewHolder { + val params = view.layoutParams as ViewGroup.MarginLayoutParams + HorizontalAdapterHelper.applyMarginToLayoutParams(activity, params, viewType) + return ViewHolder(view) + } - override fun setColors(color: Int, holder: ViewHolder) { - holder.title?.setTextColor(MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color))) - holder.text?.setTextColor(MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color))) - } + override fun setColors(color: Int, holder: ViewHolder) { + holder.title?.setTextColor(MaterialValueHelper.getPrimaryTextColor(activity, ColorUtil.isColorLight(color))) + holder.text?.setTextColor(MaterialValueHelper.getSecondaryTextColor(activity, ColorUtil.isColorLight(color))) + } - override fun loadAlbumCover(album: Album, holder: ViewHolder) { - if (holder.image == null) return + override fun loadAlbumCover(album: Album, holder: ViewHolder) { + if (holder.image == null) return - SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) - .checkIgnoreMediaStore(activity).generatePalette(activity).build() - .into(object : RetroMusicColoredTarget(holder.image!!) { - override fun onLoadCleared(placeholder: Drawable?) { - super.onLoadCleared(placeholder) - setColors(albumArtistFooterColor, holder) - } + SongGlideRequest.Builder.from(Glide.with(activity), album.safeGetFirstSong()) + .checkIgnoreMediaStore(activity).generatePalette(activity).build() + .into(object : RetroMusicColoredTarget(holder.image!!) { + override fun onLoadCleared(placeholder: Drawable?) { + super.onLoadCleared(placeholder) + setColors(albumArtistFooterColor, holder) + } - override fun onColorReady(color: Int) { - if (usePalette) setColors(color, holder) - else setColors(albumArtistFooterColor, holder) - } - }) - } + override fun onColorReady(color: Int) { + if (usePalette) setColors(color, holder) + else setColors(albumArtistFooterColor, holder) + } + }) + } - override fun getAlbumText(album: Album): String? { - return MusicUtil.getYearString(album.year) - } + override fun getAlbumText(album: Album): String? { + return MusicUtil.getYearString(album.year) + } - override fun getItemViewType(position: Int): Int { - return HorizontalAdapterHelper.getItemViewtype(position, itemCount) - } + override fun getItemViewType(position: Int): Int { + return HorizontalAdapterHelper.getItemViewtype(position, itemCount) + } - override fun getItemCount(): Int { - return dataSet.size - } + override fun getItemCount(): Int { + return dataSet.size + } - companion object { - val TAG: String = AlbumAdapter::class.java.simpleName - } + companion object { + val TAG: String = AlbumAdapter::class.java.simpleName + } } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/artist/ArtistAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/artist/ArtistAdapter.kt index 796bb148..362299e3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/artist/ArtistAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/artist/ArtistAdapter.kt @@ -23,7 +23,7 @@ import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.NavigationUtil import com.bumptech.glide.Glide -import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView +import me.zhanghai.android.fastscroll.PopupTextProvider import java.util.ArrayList class ArtistAdapter( @@ -34,7 +34,7 @@ class ArtistAdapter( cabHolder: CabHolder? ) : AbsMultiSelectAdapter( activity, cabHolder, R.menu.menu_media_selection -), FastScrollRecyclerView.SectionedAdapter { +), PopupTextProvider { fun swapDataSet(dataSet: ArrayList) { this.dataSet = dataSet @@ -70,7 +70,7 @@ class ArtistAdapter( fun setColors(color: Int, holder: ViewHolder) { if (holder.paletteColorContainer != null) { - holder.paletteColorContainer?.backgroundTintList = ColorStateList.valueOf(color) + holder.paletteColorContainer?.setBackgroundColor(color) holder.title?.setTextColor( MaterialValueHelper.getPrimaryTextColor( activity, ColorUtil.isColorLight( @@ -126,7 +126,11 @@ class ArtistAdapter( return songs } - override fun getSectionName(position: Int): String { + override fun getPopupText(position: Int): String { + return getSectionName(position) + } + + private fun getSectionName(position: Int): String { return MusicUtil.getSectionName(dataSet[position].name) } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.java b/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.java index 36bbe6bd..e8bf2e4b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.java +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.java @@ -3,26 +3,28 @@ package code.name.monkey.retromusic.adapter.base; import android.content.Context; import android.view.Menu; import android.view.MenuItem; - import androidx.annotation.MenuRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.RecyclerView; - -import com.afollestad.materialcab.MaterialCab; - -import java.util.ArrayList; - import code.name.monkey.retromusic.R; import code.name.monkey.retromusic.interfaces.CabHolder; +import com.afollestad.materialcab.MaterialCab; +import java.util.ArrayList; -public abstract class AbsMultiSelectAdapter extends RecyclerView.Adapter implements MaterialCab.Callback { +public abstract class AbsMultiSelectAdapter extends RecyclerView.Adapter + implements MaterialCab.Callback { + + private MaterialCab cab; + @Nullable private final CabHolder cabHolder; - private final Context context; - private MaterialCab cab; + private ArrayList checked; + + private final Context context; + private int menuRes; public AbsMultiSelectAdapter(@NonNull Context context, @Nullable CabHolder cabHolder, @MenuRes int menuRes) { @@ -32,22 +34,27 @@ public abstract class AbsMultiSelectAdapter(checked)); + cab.finish(); + clearChecked(); } - return false; + return true; } protected void checkAll() { @@ -64,21 +71,11 @@ public abstract class AbsMultiSelectAdapter(checked)); - cab.finish(); - clearChecked(); - } - return true; - } - - @Override - public boolean onCabFinished(MaterialCab materialCab) { - clearChecked(); - return true; - } - - protected String getName(I object) { - return object.toString(); - } - - @Nullable - protected abstract I getIdentifier(int position); - protected abstract void onMultipleItemAction(MenuItem menuItem, ArrayList selection); + + protected void setMultiSelectMenuRes(@MenuRes int menuRes) { + this.menuRes = menuRes; + } + + protected boolean toggleChecked(final int position) { + if (cabHolder != null) { + I identifier = getIdentifier(position); + if (identifier == null) { + return false; + } + + if (!checked.remove(identifier)) { + checked.add(identifier); + } + + notifyItemChanged(position); + updateCab(); + return true; + } + return false; + } + + private void clearChecked() { + checked.clear(); + notifyDataSetChanged(); + } + + private void updateCab() { + if (cabHolder != null) { + if (cab == null || !cab.isActive()) { + cab = cabHolder.openCab(menuRes, this); + } + final int size = checked.size(); + if (size <= 0) { + cab.finish(); + } else if (size == 1) { + cab.setTitle(getName(checked.get(0))); + } else { + cab.setTitle(context.getString(R.string.x_selected, size)); + } + } + } } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/base/MediaEntryViewHolder.java b/app/src/main/java/code/name/monkey/retromusic/adapter/base/MediaEntryViewHolder.java index d73be731..014d7ea1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/base/MediaEntryViewHolder.java +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/base/MediaEntryViewHolder.java @@ -14,6 +14,7 @@ package code.name.monkey.retromusic.adapter.base; +import android.graphics.Color; import android.view.View; import android.view.ViewGroup; import android.widget.ImageButton; @@ -22,7 +23,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.RecyclerView; -import code.name.monkey.appthemehelper.util.ATHUtil; import code.name.monkey.retromusic.R; import com.google.android.material.card.MaterialCardView; import com.h6ah4i.android.widget.advrecyclerview.utils.AbstractDraggableSwipeableItemViewHolder; @@ -97,8 +97,7 @@ public class MediaEntryViewHolder extends AbstractDraggableSwipeableItemViewHold dummyContainer = itemView.findViewById(R.id.dummy_view); if (imageContainerCard != null) { - imageContainerCard.setCardBackgroundColor( - ATHUtil.INSTANCE.resolveColor(itemView.getContext(), R.attr.colorSurface)); + imageContainerCard.setCardBackgroundColor(Color.TRANSPARENT); } itemView.setOnClickListener(this); itemView.setOnLongClickListener(this); diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt index f448f3d6..70395660 100755 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt @@ -1,5 +1,6 @@ package code.name.monkey.retromusic.adapter.playlist +import android.graphics.Color import android.graphics.drawable.Drawable import android.view.LayoutInflater import android.view.MenuItem @@ -15,6 +16,8 @@ import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder import code.name.monkey.retromusic.dialogs.ClearSmartPlaylistDialog import code.name.monkey.retromusic.dialogs.DeletePlaylistDialog +import code.name.monkey.retromusic.extensions.hide +import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper import code.name.monkey.retromusic.helper.menu.SongsMenuHelper import code.name.monkey.retromusic.interfaces.CabHolder @@ -26,17 +29,17 @@ import code.name.monkey.retromusic.model.smartplaylist.AbsSmartPlaylist import code.name.monkey.retromusic.model.smartplaylist.LastAddedPlaylist import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.NavigationUtil -import java.util.* +import java.util.ArrayList class PlaylistAdapter( - private val activity: AppCompatActivity, - var dataSet: ArrayList, - private var itemLayoutRes: Int, - cabHolder: CabHolder? + private val activity: AppCompatActivity, + var dataSet: ArrayList, + private var itemLayoutRes: Int, + cabHolder: CabHolder? ) : AbsMultiSelectAdapter( - activity, - cabHolder, - R.menu.menu_playlists_selection + activity, + cabHolder, + R.menu.menu_playlists_selection ) { var songs = ArrayList() @@ -77,12 +80,26 @@ class PlaylistAdapter( holder.title?.text = getPlaylistTitle(playlist) holder.text?.text = getPlaylistText(playlist) holder.image?.setImageDrawable(getIconRes(playlist)) + val isChecked = isChecked(playlist) + if (isChecked) { + holder.menu?.hide() + } else { + holder.menu?.show() + } } private fun getIconRes(playlist: Playlist): Drawable { return if (MusicUtil.isFavoritePlaylist(activity, playlist)) - TintHelper.createTintedDrawable(activity, R.drawable.ic_favorite_white_24dp, ThemeStore.accentColor(activity))!! - else TintHelper.createTintedDrawable(activity, R.drawable.ic_playlist_play_white_24dp, ATHUtil.resolveColor(activity, R.attr.colorControlNormal))!! + TintHelper.createTintedDrawable( + activity, + R.drawable.ic_favorite_white_24dp, + ThemeStore.accentColor(activity) + ) + else TintHelper.createTintedDrawable( + activity, + R.drawable.ic_playlist_play_white_24dp, + ATHUtil.resolveColor(activity, R.attr.colorControlNormal) + ) } override fun getItemViewType(position: Int): Int { @@ -109,7 +126,7 @@ class PlaylistAdapter( val playlist = selection[i] if (playlist is AbsSmartPlaylist) { ClearSmartPlaylistDialog.create(playlist).show( - activity.supportFragmentManager, "CLEAR_PLAYLIST_" + playlist.name + activity.supportFragmentManager, "CLEAR_PLAYLIST_" + playlist.name ) selection.remove(playlist) i-- @@ -118,13 +135,13 @@ class PlaylistAdapter( } if (selection.size > 0) { DeletePlaylistDialog.create(selection) - .show(activity.supportFragmentManager, "DELETE_PLAYLIST") + .show(activity.supportFragmentManager, "DELETE_PLAYLIST") } } else -> SongsMenuHelper.handleMenuClick( - activity, - getSongList(selection), - menuItem.itemId + activity, + getSongList(selection), + menuItem.itemId ) } } @@ -157,15 +174,14 @@ class PlaylistAdapter( image?.apply { val iconPadding = activity.resources.getDimensionPixelSize(R.dimen.list_item_image_icon_padding) setPadding(iconPadding, iconPadding, iconPadding, iconPadding) - //setColorFilter(ATHUtil.resolveColor(activity, R.attr.iconColor), PorterDuff.Mode.SRC_IN) } menu?.setOnClickListener { view -> val playlist = dataSet[adapterPosition] val popupMenu = PopupMenu(activity, view) popupMenu.inflate( - if (itemViewType == SMART_PLAYLIST) R.menu.menu_item_smart_playlist - else R.menu.menu_item_playlist + if (itemViewType == SMART_PLAYLIST) R.menu.menu_item_smart_playlist + else R.menu.menu_item_playlist ) if (playlist is LastAddedPlaylist) { popupMenu.menu.findItem(R.id.action_clear_playlist).isVisible = false @@ -174,14 +190,14 @@ class PlaylistAdapter( if (item.itemId == R.id.action_clear_playlist) { if (playlist is AbsSmartPlaylist) { ClearSmartPlaylistDialog.create(playlist).show( - activity.supportFragmentManager, - "CLEAR_SMART_PLAYLIST_" + playlist.name + activity.supportFragmentManager, + "CLEAR_SMART_PLAYLIST_" + playlist.name ) return@setOnMenuItemClickListener true } } PlaylistMenuHelper.handleMenuClick( - activity, dataSet[adapterPosition], item + activity, dataSet[adapterPosition], item ) } popupMenu.show() @@ -189,7 +205,7 @@ class PlaylistAdapter( imageTextContainer?.apply { cardElevation = 0f - setCardBackgroundColor(ATHUtil.resolveColor(activity, R.attr.colorSurface)) + setCardBackgroundColor(Color.TRANSPARENT) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/AbsOffsetSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/AbsOffsetSongAdapter.kt index 9cf2aaf1..b3427584 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/AbsOffsetSongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/AbsOffsetSongAdapter.kt @@ -1,95 +1,80 @@ package code.name.monkey.retromusic.adapter.song -import android.view.* +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup import androidx.annotation.LayoutRes import androidx.appcompat.app.AppCompatActivity import code.name.monkey.retromusic.R import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.model.Song -import java.util.* +import java.util.ArrayList -abstract class AbsOffsetSongAdapter : SongAdapter { +abstract class AbsOffsetSongAdapter( + activity: AppCompatActivity, + dataSet: ArrayList, + @LayoutRes itemLayoutRes: Int, + cabHolder: CabHolder? +) : SongAdapter(activity, dataSet, itemLayoutRes, cabHolder) { - constructor( - activity: AppCompatActivity, - dataSet: ArrayList, @LayoutRes itemLayoutRes: Int, - usePalette: Boolean, - cabHolder: CabHolder? - ) : super(activity, dataSet, itemLayoutRes, usePalette, cabHolder) + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongAdapter.ViewHolder { + if (viewType == OFFSET_ITEM) { + val view = LayoutInflater.from(activity) + .inflate(R.layout.item_list_quick_actions, parent, false) + return createViewHolder(view) + } + return super.onCreateViewHolder(parent, viewType) + } - constructor( - activity: AppCompatActivity, - dataSet: ArrayList, @LayoutRes itemLayoutRes: Int, - usePalette: Boolean, - cabHolder: CabHolder?, - showSectionName: Boolean - ) : super(activity, dataSet, itemLayoutRes, usePalette, cabHolder, showSectionName) { - } + override fun createViewHolder(view: View): SongAdapter.ViewHolder { + return ViewHolder(view) + } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SongAdapter.ViewHolder { - if (viewType == OFFSET_ITEM) { - val view = LayoutInflater.from(activity) - .inflate(R.layout.item_list_quick_actions, parent, false) - return createViewHolder(view) - } - return super.onCreateViewHolder(parent, viewType) - } + override fun getItemId(position: Int): Long { + var positionFinal = position + positionFinal-- + return if (positionFinal < 0) -2 else super.getItemId(positionFinal) + } - override fun createViewHolder(view: View): SongAdapter.ViewHolder { - return ViewHolder(view) - } + override fun getIdentifier(position: Int): Song? { + var positionFinal = position + positionFinal-- + return if (positionFinal < 0) null else super.getIdentifier(positionFinal) + } - override fun getItemId(position: Int): Long { - var positionFinal = position - positionFinal-- - return if (positionFinal < 0) -2 else super.getItemId(positionFinal) - } + override fun getItemCount(): Int { + val superItemCount = super.getItemCount() + return if (superItemCount == 0) 0 else superItemCount + 1 + } - override fun getIdentifier(position: Int): Song? { - var positionFinal = position - positionFinal-- - return if (positionFinal < 0) null else super.getIdentifier(positionFinal) - } + override fun getItemViewType(position: Int): Int { + return if (position == 0) OFFSET_ITEM else SONG + } - override fun getItemCount(): Int { - val superItemCount = super.getItemCount() - return if (superItemCount == 0) 0 else superItemCount + 1 - } + open inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView) { - override fun getItemViewType(position: Int): Int { - return if (position == 0) OFFSET_ITEM else SONG - } + override // could also return null, just to be safe return empty song + val song: Song + get() = if (itemViewType == OFFSET_ITEM) Song.emptySong else dataSet[adapterPosition - 1] - override fun getSectionName(position: Int): String { - var positionF = position - positionF-- - return if (positionF < 0) "" else super.getSectionName(positionF) - } + override fun onClick(v: View?) { + if (isInQuickSelectMode && itemViewType != OFFSET_ITEM) { + toggleChecked(adapterPosition) + } else { + MusicPlayerRemote.openQueue(dataSet, adapterPosition - 1, true) + } + } - open inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView) { + override fun onLongClick(v: View?): Boolean { + if (itemViewType == OFFSET_ITEM) return false + toggleChecked(adapterPosition) + return true + } + } - override // could also return null, just to be safe return empty song - val song: Song - get() = if (itemViewType == OFFSET_ITEM) Song.emptySong else dataSet[adapterPosition - 1] - - override fun onClick(v: View?) { - if (isInQuickSelectMode && itemViewType != OFFSET_ITEM) { - toggleChecked(adapterPosition) - } else { - MusicPlayerRemote.openQueue(dataSet, adapterPosition - 1, true) - } - } - - override fun onLongClick(v: View?): Boolean { - if (itemViewType == OFFSET_ITEM) return false - toggleChecked(adapterPosition) - return true - } - } - - companion object { - const val OFFSET_ITEM = 0 - const val SONG = 1 - } + companion object { + const val OFFSET_ITEM = 0 + const val SONG = 1 + } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt index 5095a440..01879bb9 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt @@ -1,134 +1,138 @@ package code.name.monkey.retromusic.adapter.song -import android.view.* +import android.view.MenuItem +import android.view.View import androidx.appcompat.app.AppCompatActivity import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.R.menu import code.name.monkey.retromusic.dialogs.RemoveFromPlaylistDialog import code.name.monkey.retromusic.interfaces.CabHolder -import code.name.monkey.retromusic.model.* +import code.name.monkey.retromusic.model.PlaylistSong +import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.ViewUtil -import com.h6ah4i.android.widget.advrecyclerview.draggable.* +import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter +import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemViewHolder +import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange import com.h6ah4i.android.widget.advrecyclerview.draggable.annotation.DraggableItemStateFlags class OrderablePlaylistSongAdapter( - activity: AppCompatActivity, - dataSet: ArrayList, - itemLayoutRes: Int, - usePalette: Boolean, - cabHolder: CabHolder?, - private val onMoveItemListener: OnMoveItemListener? + activity: AppCompatActivity, + dataSet: ArrayList, + itemLayoutRes: Int, + cabHolder: CabHolder?, + private val onMoveItemListener: OnMoveItemListener? ) : PlaylistSongAdapter( - activity, dataSet, itemLayoutRes, usePalette, cabHolder + activity, dataSet, itemLayoutRes, cabHolder ), DraggableItemAdapter { - init { - setMultiSelectMenuRes(code.name.monkey.retromusic.R.menu.menu_playlists_songs_selection) - } + init { + setMultiSelectMenuRes(menu.menu_playlists_songs_selection) + } - override fun createViewHolder(view: View): SongAdapter.ViewHolder { - return ViewHolder(view) - } + override fun createViewHolder(view: View): SongAdapter.ViewHolder { + return ViewHolder(view) + } - override fun getItemId(position: Int): Long { - var positionFinal = position - positionFinal-- + override fun getItemId(position: Int): Long { + var positionFinal = position + positionFinal-- - var long: Long = 0 - if (positionFinal < 0) { - long = -2 - } else { - if (dataSet[positionFinal] is PlaylistSong) { - long = (dataSet[positionFinal] as PlaylistSong).idInPlayList.toLong() - } - } - return long - } + var long: Long = 0 + if (positionFinal < 0) { + long = -2 + } else { + if (dataSet[positionFinal] is PlaylistSong) { + long = (dataSet[positionFinal] as PlaylistSong).idInPlayList.toLong() + } + } + return long + } - override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList) { - when (menuItem.itemId) { - R.id.action_remove_from_playlist -> { - RemoveFromPlaylistDialog.create(selection as ArrayList) - .show(activity.supportFragmentManager, "ADD_PLAYLIST") - return - } - } - super.onMultipleItemAction(menuItem, selection) - } + override fun onMultipleItemAction(menuItem: MenuItem, selection: ArrayList) { + when (menuItem.itemId) { + R.id.action_remove_from_playlist -> { + RemoveFromPlaylistDialog.create(selection as ArrayList) + .show(activity.supportFragmentManager, "ADD_PLAYLIST") + return + } + } + super.onMultipleItemAction(menuItem, selection) + } - override fun onCheckCanStartDrag(holder: ViewHolder, position: Int, x: Int, y: Int): Boolean { - return onMoveItemListener != null && position > 0 && (ViewUtil.hitTest( - holder.dragView!!, x, y - ) || ViewUtil.hitTest(holder.image!!, x, y)) - } + override fun onCheckCanStartDrag(holder: ViewHolder, position: Int, x: Int, y: Int): Boolean { + return onMoveItemListener != null && position > 0 && (ViewUtil.hitTest( + holder.dragView!!, x, y + ) || ViewUtil.hitTest(holder.image!!, x, y)) + } - override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange { - return ItemDraggableRange(1, dataSet.size) - } + override fun onGetItemDraggableRange(holder: ViewHolder, position: Int): ItemDraggableRange { + return ItemDraggableRange(1, dataSet.size) + } - override fun onMoveItem(fromPosition: Int, toPosition: Int) { - if (onMoveItemListener != null && fromPosition != toPosition) { - onMoveItemListener.onMoveItem(fromPosition - 1, toPosition - 1) - } - } + override fun onMoveItem(fromPosition: Int, toPosition: Int) { + if (onMoveItemListener != null && fromPosition != toPosition) { + onMoveItemListener.onMoveItem(fromPosition - 1, toPosition - 1) + } + } - override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean { - return dropPosition > 0 - } + override fun onCheckCanDrop(draggingPosition: Int, dropPosition: Int): Boolean { + return dropPosition > 0 + } - override fun onItemDragStarted(position: Int) { - notifyDataSetChanged() - } + override fun onItemDragStarted(position: Int) { + notifyDataSetChanged() + } - override fun onItemDragFinished(fromPosition: Int, toPosition: Int, result: Boolean) { - notifyDataSetChanged() - } + override fun onItemDragFinished(fromPosition: Int, toPosition: Int, result: Boolean) { + notifyDataSetChanged() + } - interface OnMoveItemListener { - fun onMoveItem(fromPosition: Int, toPosition: Int) - } + interface OnMoveItemListener { + fun onMoveItem(fromPosition: Int, toPosition: Int) + } - inner class ViewHolder(itemView: View) : PlaylistSongAdapter.ViewHolder(itemView), DraggableItemViewHolder { - @DraggableItemStateFlags - private var mDragStateFlags: Int = 0 + inner class ViewHolder(itemView: View) : PlaylistSongAdapter.ViewHolder(itemView), DraggableItemViewHolder { + @DraggableItemStateFlags + private var mDragStateFlags: Int = 0 - override var songMenuRes: Int - get() = code.name.monkey.retromusic.R.menu.menu_item_playlist_song - set(value) { - super.songMenuRes = value - } + override var songMenuRes: Int + get() = code.name.monkey.retromusic.R.menu.menu_item_playlist_song + set(value) { + super.songMenuRes = value + } - init { - if (dragView != null) { - if (onMoveItemListener != null) { - dragView?.visibility = View.VISIBLE - } else { - dragView?.visibility = View.GONE - } - } - } + init { + if (dragView != null) { + if (onMoveItemListener != null) { + dragView?.visibility = View.VISIBLE + } else { + dragView?.visibility = View.GONE + } + } + } - override fun onSongMenuItemClick(item: MenuItem): Boolean { - when (item.itemId) { - code.name.monkey.retromusic.R.id.action_remove_from_playlist -> { - RemoveFromPlaylistDialog.create(song as PlaylistSong) - .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST") - return true - } - } - return super.onSongMenuItemClick(item) - } + override fun onSongMenuItemClick(item: MenuItem): Boolean { + when (item.itemId) { + code.name.monkey.retromusic.R.id.action_remove_from_playlist -> { + RemoveFromPlaylistDialog.create(song as PlaylistSong) + .show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST") + return true + } + } + return super.onSongMenuItemClick(item) + } - @DraggableItemStateFlags - override fun getDragStateFlags(): Int { - return mDragStateFlags - } + @DraggableItemStateFlags + override fun getDragStateFlags(): Int { + return mDragStateFlags + } - override fun setDragStateFlags(@DraggableItemStateFlags flags: Int) { - mDragStateFlags = flags - } - } + override fun setDragStateFlags(@DraggableItemStateFlags flags: Int) { + mDragStateFlags = flags + } + } - companion object { - val TAG: String = OrderablePlaylistSongAdapter::class.java.simpleName - } + companion object { + val TAG: String = OrderablePlaylistSongAdapter::class.java.simpleName + } } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt index 62df7bc9..a0970bcf 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt @@ -1,6 +1,5 @@ package code.name.monkey.retromusic.adapter.song -import android.graphics.Color import android.graphics.PorterDuff.Mode import android.view.MenuItem import android.view.View @@ -31,7 +30,7 @@ class PlayingQueueAdapter( private var current: Int, itemLayoutRes: Int ) : SongAdapter( - activity, dataSet, itemLayoutRes, false, null + activity, dataSet, itemLayoutRes, null ), DraggableItemAdapter, SwipeableItemAdapter { private var color = -1 @@ -48,9 +47,6 @@ class PlayingQueueAdapter( if (holder.itemViewType == HISTORY || holder.itemViewType == CURRENT) { setAlpha(holder, 0.5f) } - if (usePalette) { - setColor(holder, Color.WHITE) - } } private fun setColor(holder: SongAdapter.ViewHolder, white: Int) { @@ -70,12 +66,6 @@ class PlayingQueueAdapter( } } - override fun usePalette(usePalette: Boolean) { - super.usePalette(usePalette) - this.usePalette = usePalette - notifyDataSetChanged() - } - override fun getItemViewType(position: Int): Int { if (position < current) { return HISTORY diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlaylistSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlaylistSongAdapter.kt index 31ac5268..44a29b28 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlaylistSongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlaylistSongAdapter.kt @@ -16,9 +16,8 @@ open class PlaylistSongAdapter( activity: AppCompatActivity, dataSet: ArrayList, itemLayoutRes: Int, - usePalette: Boolean, cabHolder: CabHolder? -) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, usePalette, cabHolder, false) { +) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, cabHolder) { init { this.setMultiSelectMenuRes(R.menu.menu_cannot_delete_single_songs_playlist_songs_selection) diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt index a0e63ae7..785a6925 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt @@ -7,48 +7,47 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.model.Song import com.google.android.material.button.MaterialButton -import java.util.* +import java.util.ArrayList class ShuffleButtonSongAdapter( - activity: AppCompatActivity, - dataSet: ArrayList, - itemLayoutRes: Int, - usePalette: Boolean, - cabHolder: CabHolder? -) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, usePalette, cabHolder) { + activity: AppCompatActivity, + dataSet: ArrayList, + itemLayoutRes: Int, + cabHolder: CabHolder? +) : AbsOffsetSongAdapter(activity, dataSet, itemLayoutRes, cabHolder) { - override fun createViewHolder(view: View): SongAdapter.ViewHolder { - return ViewHolder(view) - } + override fun createViewHolder(view: View): SongAdapter.ViewHolder { + return ViewHolder(view) + } - override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) { - if (holder.itemViewType == OFFSET_ITEM) { - val viewHolder = holder as ViewHolder - viewHolder.playAction?.let { - it.setOnClickListener { - MusicPlayerRemote.openQueue(dataSet, 0, true) - } - } - viewHolder.shuffleAction?.let { - it.setOnClickListener { - MusicPlayerRemote.openAndShuffleQueue(dataSet, true) - } - } - } else { - super.onBindViewHolder(holder, position - 1) - } - } + override fun onBindViewHolder(holder: SongAdapter.ViewHolder, position: Int) { + if (holder.itemViewType == OFFSET_ITEM) { + val viewHolder = holder as ViewHolder + viewHolder.playAction?.let { + it.setOnClickListener { + MusicPlayerRemote.openQueue(dataSet, 0, true) + } + } + viewHolder.shuffleAction?.let { + it.setOnClickListener { + MusicPlayerRemote.openAndShuffleQueue(dataSet, true) + } + } + } else { + super.onBindViewHolder(holder, position - 1) + } + } - inner class ViewHolder(itemView: View) : AbsOffsetSongAdapter.ViewHolder(itemView) { - val playAction: MaterialButton? = itemView.findViewById(R.id.playAction) - val shuffleAction: MaterialButton? = itemView.findViewById(R.id.shuffleAction) + inner class ViewHolder(itemView: View) : AbsOffsetSongAdapter.ViewHolder(itemView) { + val playAction: MaterialButton? = itemView.findViewById(R.id.playAction) + val shuffleAction: MaterialButton? = itemView.findViewById(R.id.shuffleAction) - override fun onClick(v: View?) { - if (itemViewType == OFFSET_ITEM) { - MusicPlayerRemote.openAndShuffleQueue(dataSet, true) - return - } - super.onClick(v) - } - } + override fun onClick(v: View?) { + if (itemViewType == OFFSET_ITEM) { + MusicPlayerRemote.openAndShuffleQueue(dataSet, true) + return + } + super.onClick(v) + } + } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/SimpleSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/SimpleSongAdapter.kt index c2d40a27..7bc79e95 100755 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/SimpleSongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/SimpleSongAdapter.kt @@ -6,14 +6,14 @@ import androidx.appcompat.app.AppCompatActivity import code.name.monkey.retromusic.interfaces.CabHolder import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.MusicUtil -import java.util.* +import java.util.ArrayList class SimpleSongAdapter( - context: AppCompatActivity, - songs: ArrayList, - i: Int, - cabHolder: CabHolder? -) : SongAdapter(context, songs, i, false, cabHolder) { + context: AppCompatActivity, + songs: ArrayList, + layoutRes: Int, + cabHolder: CabHolder? +) : SongAdapter(context, songs, layoutRes, cabHolder) { override fun swapDataSet(dataSet: ArrayList) { this.dataSet.clear() diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt index 3ec4b293..35d55ab0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt @@ -25,7 +25,7 @@ import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.PreferenceUtil import com.afollestad.materialcab.MaterialCab import com.bumptech.glide.Glide -import com.simplecityapps.recyclerview_fastscroll.views.FastScrollRecyclerView +import me.zhanghai.android.fastscroll.PopupTextProvider import java.util.ArrayList /** @@ -36,21 +36,17 @@ open class SongAdapter( protected val activity: AppCompatActivity, dataSet: ArrayList, protected var itemLayoutRes: Int, - usePalette: Boolean, cabHolder: CabHolder?, showSectionName: Boolean = true ) : AbsMultiSelectAdapter( activity, cabHolder, R.menu.menu_media_selection -), MaterialCab.Callback, FastScrollRecyclerView.SectionedAdapter { +), MaterialCab.Callback, PopupTextProvider { var dataSet: ArrayList - - protected var usePalette = false private var showSectionName = true init { this.dataSet = dataSet - this.usePalette = usePalette this.showSectionName = showSectionName this.setHasStableIds(true) } @@ -60,11 +56,6 @@ open class SongAdapter( notifyDataSetChanged() } - open fun usePalette(usePalette: Boolean) { - this.usePalette = usePalette - notifyDataSetChanged() - } - override fun getItemId(position: Int): Long { return dataSet[position].id.toLong() } @@ -113,8 +104,7 @@ open class SongAdapter( } override fun onColorReady(color: Int) { - if (usePalette) setColors(color, holder) - else setColors(defaultFooterColor, holder) + setColors(color, holder) } }) } @@ -143,10 +133,7 @@ open class SongAdapter( SongsMenuHelper.handleMenuClick(activity, selection, menuItem.itemId) } - override fun getSectionName(position: Int): String { - if (!showSectionName) { - return "" - } + override fun getPopupText(position: Int): String { val sectionName: String? = when (PreferenceUtil.getInstance(activity).songSortOrder) { SortOrder.SongSortOrder.SONG_A_Z, SortOrder.SongSortOrder.SONG_Z_A -> dataSet[position].title SortOrder.SongSortOrder.SONG_ALBUM -> dataSet[position].albumName @@ -157,6 +144,7 @@ open class SongAdapter( return "" } } + println("File name -> $sectionName") return MusicUtil.getSectionName(sectionName) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsLibraryPagerRecyclerViewCustomGridSizeFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsLibraryPagerRecyclerViewCustomGridSizeFragment.kt index 267b9b07..99ad3294 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsLibraryPagerRecyclerViewCustomGridSizeFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsLibraryPagerRecyclerViewCustomGridSizeFragment.kt @@ -12,10 +12,9 @@ abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment maxGridSizeForList) { - R.layout.item_grid + fun itemLayoutRes(): Int { + return if (getGridSize() > maxGridSizeForList) { + loadLayoutRes() } else R.layout.item_list + } - protected val maxGridSizeForList: Int + protected abstract fun setLayoutRes(layoutRes: Int) + + fun setAndSaveLayoutRes(layoutRes: Int) { + saveLayoutRes(layoutRes) + setLayoutRes(layoutRes) + } + + private val maxGridSizeForList: Int get() = if (isLandscape) { activity!!.resources.getInteger(R.integer.default_list_columns_land) } else activity!!.resources.getInteger(R.integer.default_list_columns) - private val isLandscape: Boolean - get() = RetroUtil.isLandscape() - fun getGridSize(): Int { if (gridSize == 0) { gridSize = if (isLandscape) { @@ -71,19 +69,8 @@ abstract class AbsLibraryPagerRecyclerViewCustomGridSizeFragment, LM : RecyclerView.LayoutManager> : AbsLibraryPagerFragment(), AppBarLayout.OnOffsetChangedListener { @@ -41,13 +42,21 @@ abstract class AbsLibraryPagerRecyclerViewFragment, } private fun setUpRecyclerView() { - if (recyclerView is FastScrollRecyclerView) { - ViewUtil.setUpFastScrollRecyclerViewColor(requireActivity(), recyclerView as FastScrollRecyclerView) - } + recyclerView.layoutManager = layoutManager recyclerView.adapter = adapter + val fastScroller = create(recyclerView) + recyclerView.setOnApplyWindowInsetsListener( + ScrollingViewOnApplyWindowInsetsListener( + recyclerView, + fastScroller + ) + ) + //OverScrollDecoratorHelper.setUpOverScroll(recyclerView, OverScrollDecoratorHelper.ORIENTATION_VERTICAL) + } - OverScrollDecoratorHelper.setUpOverScroll(recyclerView, OverScrollDecoratorHelper.ORIENTATION_VERTICAL) + protected open fun createFastScroller(recyclerView: RecyclerView): FastScroller { + return FastScrollerBuilder(recyclerView).useMd2Style().build() } private fun initAdapter() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/mainactivity/AlbumsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/mainactivity/AlbumsFragment.kt index ec1bd229..c1f976d1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/mainactivity/AlbumsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/mainactivity/AlbumsFragment.kt @@ -53,13 +53,13 @@ open class AlbumsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment showMainMenu(OptionsSheetDialogFragment.LIBRARY)); ToolbarContentTintHelper.colorBackButton(toolbar); - //toolbar.setTitleTextColor(ATHUtil.INSTANCE.resolveColor(requireContext(), R.attr.colorOnSecondary)); } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/mainactivity/SongsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/mainactivity/SongsFragment.kt index 6551f194..d58e0365 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/mainactivity/SongsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/mainactivity/SongsFragment.kt @@ -2,7 +2,8 @@ package code.name.monkey.retromusic.fragments.mainactivity import android.os.Bundle import android.view.View -import androidx.recyclerview.widget.GridLayoutManager +import androidx.annotation.LayoutRes +import androidx.recyclerview.widget.LinearLayoutManager import code.name.monkey.retromusic.App import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.song.ShuffleButtonSongAdapter @@ -12,15 +13,15 @@ import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.mvp.presenter.SongPresenter import code.name.monkey.retromusic.mvp.presenter.SongView import code.name.monkey.retromusic.util.PreferenceUtil -import java.util.* +import java.util.ArrayList import javax.inject.Inject -class SongsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment(), SongView { +class SongsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment(), + SongView { @Inject lateinit var songPresenter: SongPresenter - override val emptyMessage: Int get() = R.string.no_songs @@ -34,20 +35,18 @@ class SongsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment) { @@ -83,11 +82,9 @@ class SongsFragment : AbsLibraryPagerRecyclerViewCustomGridSizeFragment> { - public static final String TAG = FoldersFragment.class.getSimpleName(); - public static final FileFilter AUDIO_FILE_FILTER = file -> !file.isHidden() && (file.isDirectory() || - FileUtil.fileIsMimeType(file, "audio/*", MimeTypeMap.getSingleton()) || - FileUtil.fileIsMimeType(file, "application/opus", MimeTypeMap.getSingleton()) || - FileUtil.fileIsMimeType(file, "application/ogg", MimeTypeMap.getSingleton())); - - private static final String PATH = "path"; - private static final String CRUMBS = "crumbs"; - private static final int LOADER_ID = LoaderIds.Companion.getFOLDERS_FRAGMENT(); - - private View coordinatorLayout, empty; - private TextView emojiText; - private MaterialCardView toolbarContainer; - private Toolbar toolbar; - private BreadCrumbLayout breadCrumbs; - private AppBarLayout appBarLayout; - private FastScrollRecyclerView recyclerView; - - private Comparator fileComparator = (lhs, rhs) -> { - if (lhs.isDirectory() && !rhs.isDirectory()) { - return -1; - } else if (!lhs.isDirectory() && rhs.isDirectory()) { - return 1; - } else { - return lhs.getName().compareToIgnoreCase - (rhs.getName()); - } - }; - private SongFileAdapter adapter; - private MaterialCab cab; - - public FoldersFragment() { - } - - public static FoldersFragment newInstance(Context context) { - return newInstance(PreferenceUtil.getInstance(context).getStartDirectory()); - } - - public static FoldersFragment newInstance(File directory) { - FoldersFragment frag = new FoldersFragment(); - Bundle b = new Bundle(); - b.putSerializable(PATH, directory); - frag.setArguments(b); - return frag; - } - - public static File getDefaultStartDirectory() { - File musicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC); - File startFolder; - if (musicDir.exists() && musicDir.isDirectory()) { - startFolder = musicDir; - } else { - File externalStorage = Environment.getExternalStorageDirectory(); - if (externalStorage.exists() && externalStorage.isDirectory()) { - startFolder = externalStorage; - } else { - startFolder = new File("/"); // root - } - } - return startFolder; - } - - private static File tryGetCanonicalFile(File file) { - try { - return file.getCanonicalFile(); - } catch (IOException e) { - e.printStackTrace(); - return file; - } - } - - private String getEmojiByUnicode(int unicode) { - return new String(Character.toChars(unicode)); - } - - private void initViews(View view) { - coordinatorLayout = view.findViewById(R.id.coordinatorLayout); - toolbarContainer = view.findViewById(R.id.toolbarContainer); - recyclerView = view.findViewById(R.id.recyclerView); - appBarLayout = view.findViewById(R.id.appBarLayout); - breadCrumbs = view.findViewById(R.id.breadCrumbs); - toolbar = view.findViewById(R.id.toolbar); - empty = view.findViewById(android.R.id.empty); - emojiText = view.findViewById(R.id.emptyEmoji); - } - - private void setCrumb(BreadCrumbLayout.Crumb crumb, boolean addToHistory) { - if (crumb == null) { - return; - } - saveScrollPosition(); - breadCrumbs.setActiveOrAdd(crumb, false); - if (addToHistory) { - breadCrumbs.addHistory(crumb); - } - getLoaderManager().restartLoader(LOADER_ID, null, this); - } - - private void saveScrollPosition() { - BreadCrumbLayout.Crumb crumb = getActiveCrumb(); - if (crumb != null) { - crumb.setScrollPosition(((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition()); - } - } - - @Nullable - private BreadCrumbLayout.Crumb getActiveCrumb() { - return breadCrumbs != null && breadCrumbs.size() > 0 ? breadCrumbs - .getCrumb(breadCrumbs.getActiveIndex()) : null; - } - - @Override - public void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - if (breadCrumbs != null) { - outState.putParcelable(CRUMBS, breadCrumbs.getStateWrapper()); - } - - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - getMainActivity().setBottomBarVisibility(View.GONE); - - if (savedInstanceState == null) { - //noinspection ConstantConditions - setCrumb(new BreadCrumbLayout.Crumb( - FileUtil.safeGetCanonicalFile((File) getArguments().getSerializable(PATH))), true); - } else { - breadCrumbs.restoreFromStateWrapper(savedInstanceState.getParcelable(CRUMBS)); - getLoaderManager().initLoader(LOADER_ID, null, this); - } - } - - @NonNull - @Override - public View onCreateView(@NonNull LayoutInflater inflater, - ViewGroup container, - Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_folder, container, false); - initViews(view); - return view; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - setStatusBarColorAuto(view); - setUpAppbarColor(); - setUpBreadCrumbs(); - setUpRecyclerView(); - setUpAdapter(); - } - - private void setUpAppbarColor() { - int primaryColor = ATHUtil.INSTANCE.resolveColor(requireContext(), R.attr.colorSurface); - getMainActivity().setSupportActionBar(toolbar); - toolbar.setBackgroundTintList(ColorStateList.valueOf(primaryColor)); - toolbarContainer.setCardBackgroundColor(ColorStateList.valueOf(primaryColor)); - toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp); - toolbar.setNavigationOnClickListener(v -> { - showMainMenu(OptionsSheetDialogFragment.FOLDER); - }); - breadCrumbs.setActivatedContentColor(ATHUtil.INSTANCE.resolveColor(requireContext(), android.R.attr.textColorPrimary)); - breadCrumbs.setDeactivatedContentColor(ATHUtil.INSTANCE.resolveColor(requireContext(), android.R.attr.textColorSecondary)); - appBarLayout.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> getMainActivity().setLightStatusbar(!ATHUtil.INSTANCE.isWindowBackgroundDark(requireContext()))); - toolbar.setOnClickListener(v -> { - ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(getMainActivity(), toolbarContainer, getString(R.string.transition_toolbar)); - NavigationUtil.goToSearch(getMainActivity(), options); - }); - } - - private void setUpBreadCrumbs() { - breadCrumbs.setCallback(this); - } - - private void setUpRecyclerView() { - //noinspection ConstantConditions - ViewUtil.INSTANCE.setUpFastScrollRecyclerViewColor(getActivity(), recyclerView, - ThemeStore.Companion.accentColor(getActivity())); - recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); - appBarLayout.addOnOffsetChangedListener(this); - } - - private void setUpAdapter() { - adapter = new SongFileAdapter(getMainActivity(), new LinkedList(), R.layout.item_list, - this, this); - adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { - @Override - public void onChanged() { - super.onChanged(); - checkIsEmpty(); - } - }); - recyclerView.setAdapter(adapter); - checkIsEmpty(); - } - - @Override - public void onPause() { - super.onPause(); - saveScrollPosition(); - } - - @Override - public void onDestroyView() { - appBarLayout.removeOnOffsetChangedListener(this); - super.onDestroyView(); - } - - @Override - public boolean handleBackPress() { - if (cab != null && cab.isActive()) { - cab.finish(); - return true; - } - if (breadCrumbs != null && breadCrumbs.popHistory()) { - setCrumb(breadCrumbs.lastHistory(), false); - return true; - } - return false; - } - - @NonNull - @Override - public MaterialCab openCab(int menuRes, MaterialCab.Callback callback) { - if (cab != null && cab.isActive()) { - cab.finish(); - } - cab = new MaterialCab(getMainActivity(), R.id.cab_stub) - .setMenu(menuRes) - .setCloseDrawableRes(R.drawable.ic_close_white_24dp) - .setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText(ATHUtil.INSTANCE.resolveColor(requireContext(), R.attr.colorSurface))) - .start(callback); - return cab; - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - super.onCreateOptionsMenu(menu, inflater); - inflater.inflate(R.menu.menu_folders, menu); - ToolbarContentTintHelper.handleOnCreateOptionsMenu(getActivity(), toolbar, menu, - ATHToolbarActivity.getToolbarBackgroundColor(toolbar)); - } - - @Override - public void onPrepareOptionsMenu(Menu menu) { - super.onPrepareOptionsMenu(menu); - ToolbarContentTintHelper.handleOnPrepareOptionsMenu(getActivity(), toolbar); - } - - @Override - public void onCrumbSelection(BreadCrumbLayout.Crumb crumb, int index) { - setCrumb(crumb, true); - } - - @Override - public boolean onOptionsItemSelected(@NonNull MenuItem item) { - switch (item.getItemId()) { - case R.id.action_go_to_start_directory: - setCrumb(new BreadCrumbLayout.Crumb(tryGetCanonicalFile(PreferenceUtil.getInstance(requireContext()).getStartDirectory())), true); - return true; - case R.id.action_scan: - BreadCrumbLayout.Crumb crumb = getActiveCrumb(); - if (crumb != null) { - //noinspection Convert2MethodRef - new ListPathsAsyncTask(getActivity(), paths -> scanPaths(paths)).execute(new ListPathsAsyncTask.LoadingInfo(crumb.getFile(), - AUDIO_FILE_FILTER)); - } - return true; - } - return super.onOptionsItemSelected(item); - } - - @Override - public void onFileSelected(File file) { - file = tryGetCanonicalFile(file); // important as we compare the path value later - if (file.isDirectory()) { - setCrumb(new BreadCrumbLayout.Crumb(file), true); - } else { - FileFilter fileFilter = pathname -> !pathname.isDirectory() && AUDIO_FILE_FILTER - .accept(pathname); - new ListSongsAsyncTask(getActivity(), file, (songs, extra) -> { - File file1 = (File) extra; - int startIndex = -1; - for (int i = 0; i < songs.size(); i++) { - if (file1.getPath().equals(songs.get(i).getData())) { // path is already canonical here - startIndex = i; - break; - } - } - if (startIndex > -1) { - MusicPlayerRemote.INSTANCE.openQueue(songs, startIndex, true); - } else { - final File finalFile = file1; - Snackbar.make(coordinatorLayout, Html.fromHtml( - String.format(getString(R.string.not_listed_in_media_store), file1.getName())), - Snackbar.LENGTH_LONG) - .setAction(R.string.action_scan, - v -> new ListPathsAsyncTask(getActivity(), this::scanPaths) - .execute(new ListPathsAsyncTask.LoadingInfo(finalFile, AUDIO_FILE_FILTER))) - .setActionTextColor(ThemeStore.Companion.accentColor(getActivity())) - .show(); - } - }).execute(new ListSongsAsyncTask.LoadingInfo(toList(file.getParentFile()), fileFilter, - getFileComparator())); - } - } - - @Override - public void onMultipleItemAction(MenuItem item, ArrayList files) { - final int itemId = item.getItemId(); - new ListSongsAsyncTask(getActivity(), null, - (songs, extra) -> SongsMenuHelper.INSTANCE.handleMenuClick(getActivity(), songs, itemId)) - .execute(new ListSongsAsyncTask.LoadingInfo(files, AUDIO_FILE_FILTER, getFileComparator())); - } - - private ArrayList toList(File file) { - ArrayList files = new ArrayList<>(1); - files.add(file); - return files; - } - - private Comparator getFileComparator() { - return fileComparator; - } - - @Override - public void onFileMenuClicked(final File file, View view) { - PopupMenu popupMenu = new PopupMenu(getActivity(), view); - if (file.isDirectory()) { - popupMenu.inflate(R.menu.menu_item_directory); - popupMenu.setOnMenuItemClickListener(item -> { - final int itemId = item.getItemId(); - switch (itemId) { - case R.id.action_play_next: - case R.id.action_add_to_current_playing: - case R.id.action_add_to_playlist: - case R.id.action_delete_from_device: - new ListSongsAsyncTask(getActivity(), null, (songs, extra) -> { - if (!songs.isEmpty()) { - SongsMenuHelper.INSTANCE.handleMenuClick(getActivity(), songs, itemId); - } - }).execute(new ListSongsAsyncTask.LoadingInfo(toList(file), AUDIO_FILE_FILTER, - getFileComparator())); - return true; - case R.id.action_set_as_start_directory: - PreferenceUtil.getInstance(requireContext()).setStartDirectory(file); - Toast.makeText(getActivity(), - String.format(getString(R.string.new_start_directory), file.getPath()), - Toast.LENGTH_SHORT).show(); - return true; - case R.id.action_scan: - new ListPathsAsyncTask(getActivity(), this::scanPaths) - .execute(new ListPathsAsyncTask.LoadingInfo(file, AUDIO_FILE_FILTER)); - return true; - } - return false; - }); - } else { - popupMenu.inflate(R.menu.menu_item_file); - popupMenu.setOnMenuItemClickListener(item -> { - final int itemId = item.getItemId(); - switch (itemId) { - case R.id.action_play_next: - case R.id.action_add_to_current_playing: - case R.id.action_add_to_playlist: - case R.id.action_go_to_album: - case R.id.action_go_to_artist: - case R.id.action_share: - case R.id.action_tag_editor: - case R.id.action_details: - case R.id.action_set_as_ringtone: - case R.id.action_delete_from_device: - new ListSongsAsyncTask(getActivity(), null, (songs, extra) -> SongMenuHelper.INSTANCE.handleMenuClick(getActivity(), - songs.get(0), itemId)).execute(new ListSongsAsyncTask.LoadingInfo(toList(file), AUDIO_FILE_FILTER, - getFileComparator())); - return true; - case R.id.action_scan: - new ListPathsAsyncTask(getActivity(), this::scanPaths).execute(new ListPathsAsyncTask.LoadingInfo(file, AUDIO_FILE_FILTER)); - return true; - } - return false; - }); - } - popupMenu.show(); - } - - @Override - public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { - recyclerView.setPadding(recyclerView.getPaddingLeft(), recyclerView.getPaddingTop(), - recyclerView.getPaddingRight(), DensityUtil.dip2px(requireContext(), 52f) + - this.appBarLayout.getTotalScrollRange() + verticalOffset); - } - - private void checkIsEmpty() { - emojiText.setText(getEmojiByUnicode(0x1F631)); - if (empty != null) { - empty.setVisibility(adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); - } - } - - private void scanPaths(@Nullable String[] toBeScanned) { - if (getActivity() == null) { - return; - } - if (toBeScanned == null || toBeScanned.length < 1) { - Toast.makeText(getActivity(), R.string.nothing_to_scan, Toast.LENGTH_SHORT).show(); - } else { - MediaScannerConnection.scanFile(getActivity().getApplicationContext(), toBeScanned, null, - new UpdateToastMediaScannerCompletionListener(getActivity(), toBeScanned)); - } - } - - private void updateAdapter(@NonNull List files) { - adapter.swapDataSet(files); - BreadCrumbLayout.Crumb crumb = getActiveCrumb(); - if (crumb != null && recyclerView != null) { - ((LinearLayoutManager) recyclerView.getLayoutManager()).scrollToPositionWithOffset(crumb.getScrollPosition(), 0); - } - } - - @NonNull - @Override - public Loader> onCreateLoader(int id, Bundle args) { - return new AsyncFileLoader(this); - } - - @Override - public void onLoadFinished(@NonNull Loader> loader, List data) { - updateAdapter(data); - } - - @Override - public void onLoaderReset(@NonNull Loader> loader) { - updateAdapter(new LinkedList()); - } - - private static class AsyncFileLoader extends WrappedAsyncTaskLoader> { - - private WeakReference fragmentWeakReference; - - AsyncFileLoader(FoldersFragment foldersFragment) { - super(Objects.requireNonNull(foldersFragment.getActivity())); - fragmentWeakReference = new WeakReference<>(foldersFragment); - } - - @Override - public List loadInBackground() { - FoldersFragment foldersFragment = fragmentWeakReference.get(); - File directory = null; - if (foldersFragment != null) { - BreadCrumbLayout.Crumb crumb = foldersFragment.getActiveCrumb(); - if (crumb != null) { - directory = crumb.getFile(); - } - } - if (directory != null) { - List files = FileUtil.listFiles(directory, AUDIO_FILE_FILTER); - Collections.sort(files, foldersFragment.getFileComparator()); - return files; - } else { - return new LinkedList<>(); - } - } - } - - private static class ListSongsAsyncTask extends ListingFilesDialogAsyncTask> { - - private final Object extra; - private WeakReference contextWeakReference; - private WeakReference callbackWeakReference; - - ListSongsAsyncTask(Context context, Object extra, OnSongsListedCallback callback) { - super(context); - this.extra = extra; - contextWeakReference = new WeakReference<>(context); - callbackWeakReference = new WeakReference<>(callback); - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - checkCallbackReference(); - checkContextReference(); - } - - @Override - protected ArrayList doInBackground(LoadingInfo... params) { - try { - LoadingInfo info = params[0]; - List files = FileUtil.listFilesDeep(info.files, info.fileFilter); - - if (isCancelled() || checkContextReference() == null - || checkCallbackReference() == null) { - return null; - } - - Collections.sort(files, info.fileComparator); - - Context context = checkContextReference(); - if (isCancelled() || context == null || checkCallbackReference() == null) { - return null; - } - - return FileUtil.matchFilesWithMediaStore(context, files); - } catch (Exception e) { - e.printStackTrace(); - cancel(false); - return null; - } - } - - @Override - protected void onPostExecute(ArrayList songs) { - super.onPostExecute(songs); - OnSongsListedCallback callback = checkCallbackReference(); - if (songs != null && callback != null) { - callback.onSongsListed(songs, extra); - } - } - - private Context checkContextReference() { - Context context = contextWeakReference.get(); - if (context == null) { - cancel(false); - } - return context; - } - - private OnSongsListedCallback checkCallbackReference() { - OnSongsListedCallback callback = callbackWeakReference.get(); - if (callback == null) { - cancel(false); - } - return callback; - } - - public interface OnSongsListedCallback { - - void onSongsListed(@NonNull ArrayList songs, Object extra); - } - - static class LoadingInfo { - - final Comparator fileComparator; - final FileFilter fileFilter; - final List files; - - LoadingInfo(@NonNull List files, @NonNull FileFilter fileFilter, - @NonNull Comparator fileComparator) { - this.fileComparator = fileComparator; - this.fileFilter = fileFilter; - this.files = files; - } - } - } - public static class ListPathsAsyncTask extends ListingFilesDialogAsyncTask { + public static class LoadingInfo { + + public final File file; + + final FileFilter fileFilter; + + public LoadingInfo(File file, FileFilter fileFilter) { + this.file = file; + this.fileFilter = fileFilter; + } + } + + public interface OnPathsListedCallback { + + void onPathsListed(@NonNull String[] paths); + } + private WeakReference onPathsListedCallbackWeakReference; public ListPathsAsyncTask(Context context, OnPathsListedCallback callback) { @@ -644,12 +100,6 @@ public class FoldersFragment extends AbsMainActivityFragment implements onPathsListedCallbackWeakReference = new WeakReference<>(callback); } - @Override - protected void onPreExecute() { - super.onPreExecute(); - checkCallbackReference(); - } - @Override protected String[] doInBackground(LoadingInfo... params) { try { @@ -699,6 +149,12 @@ public class FoldersFragment extends AbsMainActivityFragment implements } } + @Override + protected void onPreExecute() { + super.onPreExecute(); + checkCallbackReference(); + } + private OnPathsListedCallback checkCallbackReference() { OnPathsListedCallback callback = onPathsListedCallbackWeakReference.get(); if (callback == null) { @@ -706,22 +162,131 @@ public class FoldersFragment extends AbsMainActivityFragment implements } return callback; } + } - public interface OnPathsListedCallback { + private static class AsyncFileLoader extends WrappedAsyncTaskLoader> { - void onPathsListed(@NonNull String[] paths); + private WeakReference fragmentWeakReference; + + AsyncFileLoader(FoldersFragment foldersFragment) { + super(Objects.requireNonNull(foldersFragment.getActivity())); + fragmentWeakReference = new WeakReference<>(foldersFragment); } - public static class LoadingInfo { + @Override + public List loadInBackground() { + FoldersFragment foldersFragment = fragmentWeakReference.get(); + File directory = null; + if (foldersFragment != null) { + BreadCrumbLayout.Crumb crumb = foldersFragment.getActiveCrumb(); + if (crumb != null) { + directory = crumb.getFile(); + } + } + if (directory != null) { + List files = FileUtil.listFiles(directory, AUDIO_FILE_FILTER); + Collections.sort(files, foldersFragment.getFileComparator()); + return files; + } else { + return new LinkedList<>(); + } + } + } + + private static class ListSongsAsyncTask + extends ListingFilesDialogAsyncTask> { + + static class LoadingInfo { + + final Comparator fileComparator; - public final File file; final FileFilter fileFilter; - public LoadingInfo(File file, FileFilter fileFilter) { - this.file = file; + final List files; + + LoadingInfo(@NonNull List files, @NonNull FileFilter fileFilter, + @NonNull Comparator fileComparator) { + this.fileComparator = fileComparator; this.fileFilter = fileFilter; + this.files = files; } } + + public interface OnSongsListedCallback { + + void onSongsListed(@NonNull ArrayList songs, Object extra); + } + + private WeakReference callbackWeakReference; + + private WeakReference contextWeakReference; + + private final Object extra; + + ListSongsAsyncTask(Context context, Object extra, OnSongsListedCallback callback) { + super(context); + this.extra = extra; + contextWeakReference = new WeakReference<>(context); + callbackWeakReference = new WeakReference<>(callback); + } + + @Override + protected ArrayList doInBackground(LoadingInfo... params) { + try { + LoadingInfo info = params[0]; + List files = FileUtil.listFilesDeep(info.files, info.fileFilter); + + if (isCancelled() || checkContextReference() == null + || checkCallbackReference() == null) { + return null; + } + + Collections.sort(files, info.fileComparator); + + Context context = checkContextReference(); + if (isCancelled() || context == null || checkCallbackReference() == null) { + return null; + } + + return FileUtil.matchFilesWithMediaStore(context, files); + } catch (Exception e) { + e.printStackTrace(); + cancel(false); + return null; + } + } + + @Override + protected void onPostExecute(ArrayList songs) { + super.onPostExecute(songs); + OnSongsListedCallback callback = checkCallbackReference(); + if (songs != null && callback != null) { + callback.onSongsListed(songs, extra); + } + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + checkCallbackReference(); + checkContextReference(); + } + + private OnSongsListedCallback checkCallbackReference() { + OnSongsListedCallback callback = callbackWeakReference.get(); + if (callback == null) { + cancel(false); + } + return callback; + } + + private Context checkContextReference() { + Context context = contextWeakReference.get(); + if (context == null) { + cancel(false); + } + return context; + } } private static abstract class ListingFilesDialogAsyncTask extends @@ -746,4 +311,467 @@ public class FoldersFragment extends AbsMainActivityFragment implements .create(); } } + + public static final String TAG = FoldersFragment.class.getSimpleName(); + + public static final FileFilter AUDIO_FILE_FILTER = file -> !file.isHidden() && (file.isDirectory() || + FileUtil.fileIsMimeType(file, "audio/*", MimeTypeMap.getSingleton()) || + FileUtil.fileIsMimeType(file, "application/opus", MimeTypeMap.getSingleton()) || + FileUtil.fileIsMimeType(file, "application/ogg", MimeTypeMap.getSingleton())); + + private static final String PATH = "path"; + + private static final String CRUMBS = "crumbs"; + + private static final int LOADER_ID = LoaderIds.Companion.getFOLDERS_FRAGMENT(); + + private SongFileAdapter adapter; + + private AppBarLayout appBarLayout; + + private BreadCrumbLayout breadCrumbs; + + private MaterialCab cab; + + private View coordinatorLayout, empty; + + private TextView emojiText; + + private Comparator fileComparator = (lhs, rhs) -> { + if (lhs.isDirectory() && !rhs.isDirectory()) { + return -1; + } else if (!lhs.isDirectory() && rhs.isDirectory()) { + return 1; + } else { + return lhs.getName().compareToIgnoreCase + (rhs.getName()); + } + }; + + private RecyclerView recyclerView; + + private Toolbar toolbar; + + private MaterialCardView toolbarContainer; + + public static File getDefaultStartDirectory() { + File musicDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC); + File startFolder; + if (musicDir.exists() && musicDir.isDirectory()) { + startFolder = musicDir; + } else { + File externalStorage = Environment.getExternalStorageDirectory(); + if (externalStorage.exists() && externalStorage.isDirectory()) { + startFolder = externalStorage; + } else { + startFolder = new File("/"); // root + } + } + return startFolder; + } + + public static FoldersFragment newInstance(File directory) { + FoldersFragment frag = new FoldersFragment(); + Bundle b = new Bundle(); + b.putSerializable(PATH, directory); + frag.setArguments(b); + return frag; + } + + public static FoldersFragment newInstance(Context context) { + return newInstance(PreferenceUtil.getInstance(context).getStartDirectory()); + } + + public FoldersFragment() { + } + + @NonNull + @Override + public View onCreateView(@NonNull LayoutInflater inflater, + ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_folder, container, false); + initViews(view); + return view; + } + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + setStatusBarColorAuto(view); + setUpAppbarColor(); + setUpBreadCrumbs(); + setUpRecyclerView(); + setUpAdapter(); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + getMainActivity().setBottomBarVisibility(View.GONE); + + if (savedInstanceState == null) { + //noinspection ConstantConditions + setCrumb(new BreadCrumbLayout.Crumb( + FileUtil.safeGetCanonicalFile((File) getArguments().getSerializable(PATH))), true); + } else { + breadCrumbs.restoreFromStateWrapper(savedInstanceState.getParcelable(CRUMBS)); + getLoaderManager().initLoader(LOADER_ID, null, this); + } + } + + @Override + public void onPause() { + super.onPause(); + saveScrollPosition(); + } + + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + if (breadCrumbs != null) { + outState.putParcelable(CRUMBS, breadCrumbs.getStateWrapper()); + } + + } + + @Override + public void onDestroyView() { + appBarLayout.removeOnOffsetChangedListener(this); + super.onDestroyView(); + } + + @Override + public boolean handleBackPress() { + if (cab != null && cab.isActive()) { + cab.finish(); + return true; + } + if (breadCrumbs != null && breadCrumbs.popHistory()) { + setCrumb(breadCrumbs.lastHistory(), false); + return true; + } + return false; + } + + @NonNull + @Override + public Loader> onCreateLoader(int id, Bundle args) { + return new AsyncFileLoader(this); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + inflater.inflate(R.menu.menu_folders, menu); + ToolbarContentTintHelper.handleOnCreateOptionsMenu(getActivity(), toolbar, menu, + ATHToolbarActivity.getToolbarBackgroundColor(toolbar)); + } + + @Override + public void onCrumbSelection(BreadCrumbLayout.Crumb crumb, int index) { + setCrumb(crumb, true); + } + + @Override + public void onFileMenuClicked(final File file, View view) { + PopupMenu popupMenu = new PopupMenu(getActivity(), view); + if (file.isDirectory()) { + popupMenu.inflate(R.menu.menu_item_directory); + popupMenu.setOnMenuItemClickListener(item -> { + final int itemId = item.getItemId(); + switch (itemId) { + case R.id.action_play_next: + case R.id.action_add_to_current_playing: + case R.id.action_add_to_playlist: + case R.id.action_delete_from_device: + new ListSongsAsyncTask(getActivity(), null, (songs, extra) -> { + if (!songs.isEmpty()) { + SongsMenuHelper.INSTANCE.handleMenuClick(getActivity(), songs, itemId); + } + }).execute(new ListSongsAsyncTask.LoadingInfo(toList(file), AUDIO_FILE_FILTER, + getFileComparator())); + return true; + case R.id.action_set_as_start_directory: + PreferenceUtil.getInstance(requireContext()).setStartDirectory(file); + Toast.makeText(getActivity(), + String.format(getString(R.string.new_start_directory), file.getPath()), + Toast.LENGTH_SHORT).show(); + return true; + case R.id.action_scan: + new ListPathsAsyncTask(getActivity(), this::scanPaths) + .execute(new ListPathsAsyncTask.LoadingInfo(file, AUDIO_FILE_FILTER)); + return true; + } + return false; + }); + } else { + popupMenu.inflate(R.menu.menu_item_file); + popupMenu.setOnMenuItemClickListener(item -> { + final int itemId = item.getItemId(); + switch (itemId) { + case R.id.action_play_next: + case R.id.action_add_to_current_playing: + case R.id.action_add_to_playlist: + case R.id.action_go_to_album: + case R.id.action_go_to_artist: + case R.id.action_share: + case R.id.action_tag_editor: + case R.id.action_details: + case R.id.action_set_as_ringtone: + case R.id.action_delete_from_device: + new ListSongsAsyncTask(getActivity(), null, + (songs, extra) -> SongMenuHelper.INSTANCE.handleMenuClick(getActivity(), + songs.get(0), itemId)) + .execute(new ListSongsAsyncTask.LoadingInfo(toList(file), AUDIO_FILE_FILTER, + getFileComparator())); + return true; + case R.id.action_scan: + new ListPathsAsyncTask(getActivity(), this::scanPaths) + .execute(new ListPathsAsyncTask.LoadingInfo(file, AUDIO_FILE_FILTER)); + return true; + } + return false; + }); + } + popupMenu.show(); + } + + @Override + public void onFileSelected(File file) { + file = tryGetCanonicalFile(file); // important as we compare the path value later + if (file.isDirectory()) { + setCrumb(new BreadCrumbLayout.Crumb(file), true); + } else { + FileFilter fileFilter = pathname -> !pathname.isDirectory() && AUDIO_FILE_FILTER + .accept(pathname); + new ListSongsAsyncTask(getActivity(), file, (songs, extra) -> { + File file1 = (File) extra; + int startIndex = -1; + for (int i = 0; i < songs.size(); i++) { + if (file1.getPath().equals(songs.get(i).getData())) { // path is already canonical here + startIndex = i; + break; + } + } + if (startIndex > -1) { + MusicPlayerRemote.INSTANCE.openQueue(songs, startIndex, true); + } else { + final File finalFile = file1; + Snackbar.make(coordinatorLayout, Html.fromHtml( + String.format(getString(R.string.not_listed_in_media_store), file1.getName())), + Snackbar.LENGTH_LONG) + .setAction(R.string.action_scan, + v -> new ListPathsAsyncTask(getActivity(), this::scanPaths) + .execute( + new ListPathsAsyncTask.LoadingInfo(finalFile, AUDIO_FILE_FILTER))) + .setActionTextColor(ThemeStore.Companion.accentColor(getActivity())) + .show(); + } + }).execute(new ListSongsAsyncTask.LoadingInfo(toList(file.getParentFile()), fileFilter, + getFileComparator())); + } + } + + @Override + public void onLoadFinished(@NonNull Loader> loader, List data) { + updateAdapter(data); + } + + @Override + public void onLoaderReset(@NonNull Loader> loader) { + updateAdapter(new LinkedList()); + } + + @Override + public void onMultipleItemAction(MenuItem item, ArrayList files) { + final int itemId = item.getItemId(); + new ListSongsAsyncTask(getActivity(), null, + (songs, extra) -> SongsMenuHelper.INSTANCE.handleMenuClick(getActivity(), songs, itemId)) + .execute(new ListSongsAsyncTask.LoadingInfo(files, AUDIO_FILE_FILTER, getFileComparator())); + } + + @Override + public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { + recyclerView.setPadding(recyclerView.getPaddingLeft(), recyclerView.getPaddingTop(), + recyclerView.getPaddingRight(), DensityUtil.dip2px(requireContext(), 52f) + + this.appBarLayout.getTotalScrollRange() + verticalOffset); + } + + @Override + public boolean onOptionsItemSelected(@NonNull MenuItem item) { + switch (item.getItemId()) { + case R.id.action_go_to_start_directory: + setCrumb(new BreadCrumbLayout.Crumb( + tryGetCanonicalFile(PreferenceUtil.getInstance(requireContext()).getStartDirectory())), true); + return true; + case R.id.action_scan: + BreadCrumbLayout.Crumb crumb = getActiveCrumb(); + if (crumb != null) { + //noinspection Convert2MethodRef + new ListPathsAsyncTask(getActivity(), paths -> scanPaths(paths)) + .execute(new ListPathsAsyncTask.LoadingInfo(crumb.getFile(), + AUDIO_FILE_FILTER)); + } + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public void onPrepareOptionsMenu(Menu menu) { + super.onPrepareOptionsMenu(menu); + ToolbarContentTintHelper.handleOnPrepareOptionsMenu(getActivity(), toolbar); + } + + @NonNull + @Override + public MaterialCab openCab(int menuRes, MaterialCab.Callback callback) { + if (cab != null && cab.isActive()) { + cab.finish(); + } + cab = new MaterialCab(getMainActivity(), R.id.cab_stub) + .setMenu(menuRes) + .setCloseDrawableRes(R.drawable.ic_close_white_24dp) + .setBackgroundColor(RetroColorUtil.shiftBackgroundColorForLightText( + ATHUtil.INSTANCE.resolveColor(requireContext(), R.attr.colorSurface))) + .start(callback); + return cab; + } + + private void checkIsEmpty() { + emojiText.setText(getEmojiByUnicode(0x1F631)); + if (empty != null) { + empty.setVisibility(adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); + } + } + + @Nullable + private BreadCrumbLayout.Crumb getActiveCrumb() { + return breadCrumbs != null && breadCrumbs.size() > 0 ? breadCrumbs + .getCrumb(breadCrumbs.getActiveIndex()) : null; + } + + private String getEmojiByUnicode(int unicode) { + return new String(Character.toChars(unicode)); + } + + private Comparator getFileComparator() { + return fileComparator; + } + + private void initViews(View view) { + coordinatorLayout = view.findViewById(R.id.coordinatorLayout); + toolbarContainer = view.findViewById(R.id.toolbarContainer); + recyclerView = view.findViewById(R.id.recyclerView); + appBarLayout = view.findViewById(R.id.appBarLayout); + breadCrumbs = view.findViewById(R.id.breadCrumbs); + toolbar = view.findViewById(R.id.toolbar); + empty = view.findViewById(android.R.id.empty); + emojiText = view.findViewById(R.id.emptyEmoji); + } + + private void saveScrollPosition() { + BreadCrumbLayout.Crumb crumb = getActiveCrumb(); + if (crumb != null) { + crumb.setScrollPosition( + ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition()); + } + } + + private void scanPaths(@Nullable String[] toBeScanned) { + if (getActivity() == null) { + return; + } + if (toBeScanned == null || toBeScanned.length < 1) { + Toast.makeText(getActivity(), R.string.nothing_to_scan, Toast.LENGTH_SHORT).show(); + } else { + MediaScannerConnection.scanFile(getActivity().getApplicationContext(), toBeScanned, null, + new UpdateToastMediaScannerCompletionListener(getActivity(), toBeScanned)); + } + } + + private void setCrumb(BreadCrumbLayout.Crumb crumb, boolean addToHistory) { + if (crumb == null) { + return; + } + saveScrollPosition(); + breadCrumbs.setActiveOrAdd(crumb, false); + if (addToHistory) { + breadCrumbs.addHistory(crumb); + } + getLoaderManager().restartLoader(LOADER_ID, null, this); + } + + private void setUpAdapter() { + adapter = new SongFileAdapter(getMainActivity(), new LinkedList(), R.layout.item_list, + this, this); + adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() { + @Override + public void onChanged() { + super.onChanged(); + checkIsEmpty(); + } + }); + recyclerView.setAdapter(adapter); + checkIsEmpty(); + } + + private void setUpAppbarColor() { + int primaryColor = ATHUtil.INSTANCE.resolveColor(requireContext(), R.attr.colorSurface); + getMainActivity().setSupportActionBar(toolbar); + toolbar.setBackgroundTintList(ColorStateList.valueOf(primaryColor)); + toolbarContainer.setCardBackgroundColor(ColorStateList.valueOf(primaryColor)); + toolbar.setNavigationIcon(R.drawable.ic_menu_white_24dp); + toolbar.setNavigationOnClickListener(v -> { + showMainMenu(OptionsSheetDialogFragment.FOLDER); + }); + breadCrumbs.setActivatedContentColor( + ATHUtil.INSTANCE.resolveColor(requireContext(), android.R.attr.textColorPrimary)); + breadCrumbs.setDeactivatedContentColor( + ATHUtil.INSTANCE.resolveColor(requireContext(), android.R.attr.textColorSecondary)); + appBarLayout.addOnOffsetChangedListener((appBarLayout, verticalOffset) -> getMainActivity() + .setLightStatusbar(!ATHUtil.INSTANCE.isWindowBackgroundDark(requireContext()))); + toolbar.setOnClickListener(v -> { + ActivityOptions options = ActivityOptions + .makeSceneTransitionAnimation(getMainActivity(), toolbarContainer, + getString(R.string.transition_toolbar)); + NavigationUtil.goToSearch(getMainActivity(), options); + }); + } + + private void setUpBreadCrumbs() { + breadCrumbs.setCallback(this); + } + + private void setUpRecyclerView() { + recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + appBarLayout.addOnOffsetChangedListener(this); + FastScroller fastScroller = ThemedFastScroller.INSTANCE.create(recyclerView); + recyclerView.setOnApplyWindowInsetsListener( + new ScrollingViewOnApplyWindowInsetsListener(recyclerView, fastScroller)); + } + + private ArrayList toList(File file) { + ArrayList files = new ArrayList<>(1); + files.add(file); + return files; + } + + private void updateAdapter(@NonNull List files) { + adapter.swapDataSet(files); + BreadCrumbLayout.Crumb crumb = getActiveCrumb(); + if (crumb != null && recyclerView != null) { + ((LinearLayoutManager) recyclerView.getLayoutManager()) + .scrollToPositionWithOffset(crumb.getScrollPosition(), 0); + } + } + + private static File tryGetCanonicalFile(File file) { + try { + return file.getCanonicalFile(); + } catch (IOException e) { + e.printStackTrace(); + return file; + } + } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerPlaybackControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerPlaybackControlsFragment.kt index b6f43afe..4be53f6b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerPlaybackControlsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerPlaybackControlsFragment.kt @@ -111,6 +111,7 @@ class PlayerPlaybackControlsFragment : AbsPlayerControlsFragment(), OnSharedPref val song = MusicPlayerRemote.currentSong title.text = song.title text.text = song.artistName + if (PreferenceUtil.getInstance(requireContext()).isSongInfo) { songInfo?.text = getSongInfo(song) } else { @@ -266,7 +267,7 @@ class PlayerPlaybackControlsFragment : AbsPlayerControlsFragment(), OnSharedPref override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { println(key) if (key == PreferenceUtil.EXTRA_SONG_INFO) { - updateSong() + if (activity != null) updateSong() } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/PersonalizeSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/PersonalizeSettingsFragment.kt index e17af8f2..fd49bdb2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/PersonalizeSettingsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/PersonalizeSettingsFragment.kt @@ -41,11 +41,7 @@ class PersonalizeSettingsFragment : AbsSettingsFragment(), SharedPreferences.OnS super.onViewCreated(view, savedInstanceState) PreferenceUtil.getInstance(requireContext()).registerOnSharedPreferenceChangedListener(this) - var preference: Preference? = findPreference("album_grid_style") - setSummary(preference!!) - preference = findPreference("artist_grid_style") - setSummary(preference!!) - preference = findPreference("home_artist_grid_style") + var preference: Preference? = findPreference("home_artist_grid_style") setSummary(preference!!) preference = findPreference("tab_text_mode") setSummary(preference!!) diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt b/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt index 6166e6db..2ca4e444 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt @@ -16,7 +16,12 @@ package code.name.monkey.retromusic.helper import android.annotation.TargetApi import android.app.Activity -import android.content.* +import android.content.ComponentName +import android.content.ContentResolver +import android.content.Context +import android.content.ContextWrapper +import android.content.Intent +import android.content.ServiceConnection import android.database.Cursor import android.net.Uri import android.os.Build @@ -32,8 +37,9 @@ import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.util.PreferenceUtil import java.io.File -import java.util.* - +import java.util.ArrayList +import java.util.Random +import java.util.WeakHashMap object MusicPlayerRemote { val TAG: String = MusicPlayerRemote::class.java.simpleName @@ -116,7 +122,12 @@ object MusicPlayerRemote { } val binder = ServiceBinder(callback) - if (contextWrapper.bindService(Intent().setClass(contextWrapper, MusicService::class.java), binder, Context.BIND_AUTO_CREATE)) { + if (contextWrapper.bindService( + Intent().setClass(contextWrapper, MusicService::class.java), + binder, + Context.BIND_AUTO_CREATE + ) + ) { mConnectionMap[contextWrapper] = binder return ServiceToken(contextWrapper) } @@ -234,7 +245,11 @@ object MusicPlayerRemote { } } - private fun tryToHandleOpenPlayingQueue(queue: ArrayList, startPosition: Int, startPlaying: Boolean): Boolean { + private fun tryToHandleOpenPlayingQueue( + queue: ArrayList, + startPosition: Int, + startPlaying: Boolean + ): Boolean { if (playingQueue === queue) { if (startPlaying) { playSongAt(startPosition) @@ -291,7 +306,11 @@ object MusicPlayerRemote { queue.add(song) openQueue(queue, 0, false) } - Toast.makeText(musicService, musicService!!.resources.getString(code.name.monkey.retromusic.R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show() + Toast.makeText( + musicService, + musicService!!.resources.getString(code.name.monkey.retromusic.R.string.added_title_to_playing_queue), + Toast.LENGTH_SHORT + ).show() return true } return false @@ -304,7 +323,11 @@ object MusicPlayerRemote { } else { openQueue(songs, 0, false) } - val toast = if (songs.size == 1) musicService!!.resources.getString(code.name.monkey.retromusic.R.string.added_title_to_playing_queue) else musicService!!.resources.getString(code.name.monkey.retromusic.R.string.added_x_titles_to_playing_queue, songs.size) + val toast = + if (songs.size == 1) musicService!!.resources.getString(code.name.monkey.retromusic.R.string.added_title_to_playing_queue) else musicService!!.resources.getString( + code.name.monkey.retromusic.R.string.added_x_titles_to_playing_queue, + songs.size + ) Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show() return true } @@ -320,7 +343,11 @@ object MusicPlayerRemote { queue.add(song) openQueue(queue, 0, false) } - Toast.makeText(musicService, musicService!!.resources.getString(code.name.monkey.retromusic.R.string.added_title_to_playing_queue), Toast.LENGTH_SHORT).show() + Toast.makeText( + musicService, + musicService!!.resources.getString(code.name.monkey.retromusic.R.string.added_title_to_playing_queue), + Toast.LENGTH_SHORT + ).show() return true } return false @@ -333,7 +360,11 @@ object MusicPlayerRemote { } else { openQueue(songs, 0, false) } - val toast = if (songs.size == 1) musicService!!.resources.getString(code.name.monkey.retromusic.R.string.added_title_to_playing_queue) else musicService!!.resources.getString(code.name.monkey.retromusic.R.string.added_x_titles_to_playing_queue, songs.size) + val toast = + if (songs.size == 1) musicService!!.resources.getString(code.name.monkey.retromusic.R.string.added_title_to_playing_queue) else musicService!!.resources.getString( + code.name.monkey.retromusic.R.string.added_x_titles_to_playing_queue, + songs.size + ) Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show() return true } @@ -385,18 +416,21 @@ object MusicPlayerRemote { songId = uri.lastPathSegment } if (songId != null) { - songs = SongLoader.getSongs(SongLoader.makeSongCursor( + songs = SongLoader.getSongs( + SongLoader.makeSongCursor( musicService!!, MediaStore.Audio.AudioColumns._ID + "=?", arrayOf(songId) - )) + ) + ) } } } if (songs == null) { var songFile: File? = null if (uri.authority != null && uri.authority == "com.android.externalstorage.documents") { - songFile = File(Environment.getExternalStorageDirectory(), uri.path?.split(":".toRegex(), 2)?.get(1)) + songFile = + File(Environment.getExternalStorageDirectory(), uri.path?.split(":".toRegex(), 2)?.get(1)) } if (songFile == null) { val path = getFilePathFromUri(musicService!!, uri) @@ -407,11 +441,13 @@ object MusicPlayerRemote { songFile = File(uri.path) } if (songFile != null) { - songs = SongLoader.getSongs(SongLoader.makeSongCursor( + songs = SongLoader.getSongs( + SongLoader.makeSongCursor( musicService!!, MediaStore.Audio.AudioColumns.DATA + "=?", arrayOf(songFile.absolutePath) - )) + ) + ) } } if (songs != null && songs.isNotEmpty()) { @@ -442,5 +478,4 @@ object MusicPlayerRemote { } class ServiceToken internal constructor(internal var mWrappedContext: ContextWrapper) - } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.java index 86483e4b..f8d21d58 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.java @@ -112,7 +112,7 @@ public class MusicUtil { @NonNull public static String getPlaylistInfoString(@NonNull final Context context, @NonNull List songs) { - final long duration = getTotalDuration(context, songs); + final long duration = getTotalDuration(songs); return MusicUtil.buildInfoString( MusicUtil.getSongCountString(context, songs.size()), @@ -388,7 +388,7 @@ public class MusicUtil { if (musicMediaTitle.isEmpty()) { return ""; } - return String.valueOf(musicMediaTitle.charAt(0)).toUpperCase(); + return musicMediaTitle.substring(0, 1).toUpperCase(); } @NonNull @@ -400,7 +400,7 @@ public class MusicUtil { MusicUtil.playlist = playlist; } - public static long getTotalDuration(@NonNull final Context context, @NonNull List songs) { + public static long getTotalDuration(@NonNull List songs) { long duration = 0; for (int i = 0; i < songs.size(); i++) { duration += songs.get(i).getDuration(); @@ -408,7 +408,7 @@ public class MusicUtil { return duration; } - public static int indexOfSongInList(List songs, int songId) { + public static int indexOfSongInList(@NonNull List songs, int songId) { for (int i = 0; i < songs.size(); i++) { if (songs.get(i).getId() == songId) { return i; diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.java index ad38af9a..8ca67846 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.java @@ -28,7 +28,6 @@ import androidx.annotation.LayoutRes; import androidx.annotation.NonNull; import androidx.annotation.StyleRes; import androidx.viewpager.widget.ViewPager; -import code.name.monkey.retromusic.App; import code.name.monkey.retromusic.R; import code.name.monkey.retromusic.activities.MainActivity; import code.name.monkey.retromusic.fragments.AlbumCoverStyle; @@ -118,11 +117,11 @@ public final class PreferenceUtil { public static final String TOGGLE_SEPARATE_LINE = "toggle_separate_line"; - public static final String ALBUM_GRID_STYLE = "album_grid_style"; + public static final String ALBUM_GRID_STYLE = "album_grid_style_home"; public static final String HOME_ARTIST_GRID_STYLE = "home_artist_grid_style"; - public static final String ARTIST_GRID_STYLE = "artist_grid_style"; + public static final String ARTIST_GRID_STYLE = "artist_grid_style_home"; public static final String TOGGLE_ADD_CONTROLS = "toggle_add_controls"; @@ -233,7 +232,7 @@ public final class PreferenceUtil { @NonNull public static PreferenceUtil getInstance(Context context) { if (sInstance == null) { - sInstance = new PreferenceUtil(App.Companion.getContext()); + sInstance = new PreferenceUtil(context); } return sInstance; } @@ -249,7 +248,7 @@ public final class PreferenceUtil { } } - public static boolean isAllowedToDownloadMetadata(final Context context) { + public static boolean isAllowedToDownloadMetadata(@NonNull Context context) { switch (getInstance(context).autoDownloadImagesPolicy()) { case "always": return true; @@ -392,26 +391,25 @@ public final class PreferenceUtil { return layoutRes; } - public final int getAlbumGridSize(Context context) { + public final int getAlbumGridSize(@NonNull Context context) { return mPreferences .getInt(ALBUM_GRID_SIZE, context.getResources().getInteger(R.integer.default_grid_columns)); } - public final int getAlbumGridSizeLand(Context context) { - return mPreferences.getInt(ALBUM_GRID_SIZE_LAND, - context.getResources().getInteger(R.integer.default_grid_columns_land)); + public final int getAlbumGridSizeLand(@NonNull Context context) { + return mPreferences + .getInt(ALBUM_GRID_SIZE_LAND, context.getResources().getInteger(R.integer.default_grid_columns_land)); } @LayoutRes - public int getAlbumGridStyle(Context context) { - int pos = Integer.parseInt(mPreferences.getString(ALBUM_GRID_STYLE, "0")); - TypedArray typedArray = context.getResources().obtainTypedArray(R.array.pref_grid_style_layout); - int layoutRes = typedArray.getResourceId(pos, -1); - typedArray.recycle(); - if (layoutRes == -1) { - return R.layout.item_card; - } - return layoutRes; + public int getAlbumGridStyle() { + return mPreferences.getInt(ALBUM_GRID_STYLE, R.layout.item_grid); + } + + public void setAlbumGridStyle(int layoutRes) { + mPreferences.edit() + .putInt(ALBUM_GRID_STYLE, layoutRes) + .apply(); } public final String getAlbumSongSortOrder() { @@ -455,15 +453,12 @@ public final class PreferenceUtil { } @LayoutRes - public int getArtistGridStyle(Context context) { - int pos = Integer.parseInt(Objects.requireNonNull(mPreferences.getString(ARTIST_GRID_STYLE, "0"))); - TypedArray typedArray = context.getResources().obtainTypedArray(R.array.pref_grid_style_layout); - int layoutRes = typedArray.getResourceId(pos, -1); - typedArray.recycle(); - if (layoutRes == -1) { - return R.layout.item_card; - } - return layoutRes; + public int getArtistGridStyle() { + return mPreferences.getInt(ARTIST_GRID_STYLE, R.layout.item_grid); + } + + public void setArtistGridStyle(int viewAs) { + mPreferences.edit().putInt(ARTIST_GRID_STYLE, viewAs).apply(); } public final String getArtistSongSortOrder() { @@ -699,10 +694,6 @@ public final class PreferenceUtil { return mPreferences.getBoolean(SLEEP_TIMER_FINISH_SONG, false); } - public boolean isSongInfo() { - return mPreferences.getBoolean(EXTRA_SONG_INFO, false); - } - public void setSleepTimerFinishMusic(final boolean value) { final SharedPreferences.Editor editor = mPreferences.edit(); editor.putBoolean(SLEEP_TIMER_FINISH_SONG, value); @@ -836,6 +827,10 @@ public final class PreferenceUtil { return mPreferences.getBoolean(SNOW_FALL_EFFECT, false); } + public boolean isSongInfo() { + return mPreferences.getBoolean(EXTRA_SONG_INFO, false); + } + public boolean pauseOnZeroVolume() { return mPreferences.getBoolean(PAUSE_ON_ZERO_VOLUME, false); } @@ -899,10 +894,6 @@ public final class PreferenceUtil { editor.apply(); } - public void setArtistGridStyle(int viewAs) { - mPreferences.edit().putInt(ARTIST_GRID_STYLE, viewAs).apply(); - } - public void setBannerImagePath(String bannerImagePath) { mPreferences.edit().putString(BANNER_IMAGE_PATH, bannerImagePath) .apply(); @@ -980,17 +971,6 @@ public final class PreferenceUtil { return mPreferences.getBoolean(SONG_COLORED_FOOTERS, false); } - public final boolean synchronizedLyricsShow() { - return mPreferences.getBoolean(SYNCHRONIZED_LYRICS_SHOW, true); - } - - public boolean tabTitles() { - return getTabTitleMode() != LabelVisibilityMode.LABEL_VISIBILITY_UNLABELED; - } - - public boolean toggleSeparateLine() { - return mPreferences.getBoolean(TOGGLE_SEPARATE_LINE, false); - } public void unregisterOnSharedPreferenceChangedListener( @NonNull OnSharedPreferenceChangeListener sharedPreferenceChangeListener) { diff --git a/app/src/main/java/code/name/monkey/retromusic/views/BaselineGridTextView.java b/app/src/main/java/code/name/monkey/retromusic/views/BaselineGridTextView.java index a82b38c6..7d82b758 100644 --- a/app/src/main/java/code/name/monkey/retromusic/views/BaselineGridTextView.java +++ b/app/src/main/java/code/name/monkey/retromusic/views/BaselineGridTextView.java @@ -19,25 +19,27 @@ import android.content.res.TypedArray; import android.graphics.Paint; import android.util.AttributeSet; import android.util.TypedValue; - import androidx.annotation.FontRes; - -import com.google.android.material.textview.MaterialTextView; - import code.name.monkey.retromusic.R; +import com.google.android.material.textview.MaterialTextView; public class BaselineGridTextView extends MaterialTextView { private final float FOUR_DIP; - private float lineHeightMultiplierHint = 1f; - private float lineHeightHint = 0f; - private boolean maxLinesByHeight = false; - private int extraTopPadding = 0; private int extraBottomPadding = 0; + + private int extraTopPadding = 0; + private @FontRes int fontResId = 0; + private float lineHeightHint = 0f; + + private float lineHeightMultiplierHint = 1f; + + private boolean maxLinesByHeight = false; + public BaselineGridTextView(Context context) { this(context, null); } @@ -73,13 +75,21 @@ public class BaselineGridTextView extends MaterialTextView { computeLineHeight(); } - public float getLineHeightMultiplierHint() { - return lineHeightMultiplierHint; + @Override + public int getCompoundPaddingBottom() { + // include extra padding to make the height a multiple of 4dp + return super.getCompoundPaddingBottom() + extraBottomPadding; } - public void setLineHeightMultiplierHint(float lineHeightMultiplierHint) { - this.lineHeightMultiplierHint = lineHeightMultiplierHint; - computeLineHeight(); + @Override + public int getCompoundPaddingTop() { + // include extra padding to place the first line's baseline on the grid + return super.getCompoundPaddingTop() + extraTopPadding; + } + + public @FontRes + int getFontResId() { + return fontResId; } public float getLineHeightHint() { @@ -91,6 +101,15 @@ public class BaselineGridTextView extends MaterialTextView { computeLineHeight(); } + public float getLineHeightMultiplierHint() { + return lineHeightMultiplierHint; + } + + public void setLineHeightMultiplierHint(float lineHeightMultiplierHint) { + this.lineHeightMultiplierHint = lineHeightMultiplierHint; + computeLineHeight(); + } + public boolean getMaxLinesByHeight() { return maxLinesByHeight; } @@ -100,23 +119,6 @@ public class BaselineGridTextView extends MaterialTextView { requestLayout(); } - public @FontRes - int getFontResId() { - return fontResId; - } - - @Override - public int getCompoundPaddingTop() { - // include extra padding to place the first line's baseline on the grid - return super.getCompoundPaddingTop() + extraTopPadding; - } - - @Override - public int getCompoundPaddingBottom() { - // include extra padding to make the height a multiple of 4dp - return super.getCompoundPaddingBottom() + extraBottomPadding; - } - @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { extraTopPadding = 0; @@ -129,18 +131,18 @@ public class BaselineGridTextView extends MaterialTextView { checkMaxLines(height, MeasureSpec.getMode(heightMeasureSpec)); } - private void parseTextAttrs(TypedArray a) { - if (a.hasValue(R.styleable.BaselineGridTextView_lineHeightMultiplierHint)) { - lineHeightMultiplierHint = - a.getFloat(R.styleable.BaselineGridTextView_lineHeightMultiplierHint, 1f); - } - if (a.hasValue(R.styleable.BaselineGridTextView_lineHeightHint)) { - lineHeightHint = a.getDimensionPixelSize( - R.styleable.BaselineGridTextView_lineHeightHint, 0); - } - if (a.hasValue(R.styleable.BaselineGridTextView_android_fontFamily)) { - fontResId = a.getResourceId(R.styleable.BaselineGridTextView_android_fontFamily, 0); + /** + * When measured with an exact height, text can be vertically clipped mid-line. Prevent + * this by setting the {@code maxLines} property based on the available space. + */ + private void checkMaxLines(int height, int heightMode) { + if (!maxLinesByHeight || heightMode != MeasureSpec.EXACTLY) { + return; } + + int textHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom(); + int completeLines = (int) Math.floor(textHeight / getLineHeight()); + setMaxLines(completeLines); } /** @@ -181,15 +183,17 @@ public class BaselineGridTextView extends MaterialTextView { return extraBottomPadding; } - /** - * When measured with an exact height, text can be vertically clipped mid-line. Prevent - * this by setting the {@code maxLines} property based on the available space. - */ - private void checkMaxLines(int height, int heightMode) { - if (!maxLinesByHeight || heightMode != MeasureSpec.EXACTLY) return; - - int textHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom(); - int completeLines = (int) Math.floor(textHeight / getLineHeight()); - setMaxLines(completeLines); + private void parseTextAttrs(TypedArray a) { + if (a.hasValue(R.styleable.BaselineGridTextView_lineHeightMultiplierHint)) { + lineHeightMultiplierHint = + a.getFloat(R.styleable.BaselineGridTextView_lineHeightMultiplierHint, 1f); + } + if (a.hasValue(R.styleable.BaselineGridTextView_lineHeightHint)) { + lineHeightHint = a.getDimensionPixelSize( + R.styleable.BaselineGridTextView_lineHeightHint, 0); + } + if (a.hasValue(R.styleable.BaselineGridTextView_android_fontFamily)) { + fontResId = a.getResourceId(R.styleable.BaselineGridTextView_android_fontFamily, 0); + } } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_album.xml b/app/src/main/res/layout/activity_album.xml index c2e026e0..df6fd3ad 100755 --- a/app/src/main/res/layout/activity_album.xml +++ b/app/src/main/res/layout/activity_album.xml @@ -4,6 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="?attr/colorSurface" android:orientation="vertical" tools:ignore="UnusedAttribute"> @@ -16,8 +17,7 @@ + android:layout_height="match_parent"> - - + app:layout_dodgeInsetEdges="bottom" + tools:listitem="@layout/item_list" /> + android:checkableBehavior="single"> @@ -55,12 +54,41 @@ - + + + + + + + + + + + + + app:showAsAction="ifRoom"> diff --git a/app/src/main/res/xml/pref_now_playing_screen.xml b/app/src/main/res/xml/pref_now_playing_screen.xml index c0155844..edb39ff1 100644 --- a/app/src/main/res/xml/pref_now_playing_screen.xml +++ b/app/src/main/res/xml/pref_now_playing_screen.xml @@ -8,6 +8,13 @@ android:title="@string/pref_title_now_playing_screen_appearance" app:icon="@drawable/ic_play_circle_filled_white_24dp" /> + + diff --git a/app/src/main/res/xml/pref_ui.xml b/app/src/main/res/xml/pref_ui.xml index 037de101..8b648127 100644 --- a/app/src/main/res/xml/pref_ui.xml +++ b/app/src/main/res/xml/pref_ui.xml @@ -3,29 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> - - - - + app:title="@string/home"> - + diff --git a/appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/TintHelper.java b/appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/TintHelper.java index 3f04d133..649ec803 100755 --- a/appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/TintHelper.java +++ b/appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/TintHelper.java @@ -78,7 +78,7 @@ public final class TintHelper { } @CheckResult - @Nullable + @NonNull public static Drawable createTintedDrawable(Context context, @DrawableRes int res, @ColorInt int color) { Drawable drawable = ContextCompat.getDrawable(context, res); @@ -87,7 +87,7 @@ public final class TintHelper { // This returns a NEW Drawable because of the mutate() call. The mutate() call is necessary because Drawables with the same resource have shared states otherwise. @CheckResult - @Nullable + @NonNull public static Drawable createTintedDrawable(@Nullable Drawable drawable, @ColorInt int color) { if (drawable == null) { return null;