Here's a list of changes/features: https://github.com/RetroMusicPlayer/RetroMusicPlayer/releases/tag/v5.0

Internal Changes:
1) Migrated to ViewBinding
2) Migrated to Glide V4
3) Migrated to kotlin version of Material Dialogs
This commit is contained in:
Prathamesh More 2021-09-09 00:00:20 +05:30
parent fc42767031
commit bce6dbfa27
421 changed files with 13285 additions and 5757 deletions

View file

@ -1,155 +0,0 @@
package code.name.monkey.retromusic.dialogs;
import android.Manifest;
import android.app.Dialog;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.DialogFragment;
import code.name.monkey.retromusic.R;
import com.afollestad.materialdialogs.MaterialDialog;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class BlacklistFolderChooserDialog extends DialogFragment
implements MaterialDialog.ListCallback {
String initialPath = Environment.getExternalStorageDirectory().getAbsolutePath();
private File parentFolder;
private File[] parentContents;
private boolean canGoUp = false;
private FolderCallback callback;
public static BlacklistFolderChooserDialog create() {
return new BlacklistFolderChooserDialog();
}
private String[] getContentsArray() {
if (parentContents == null) {
if (canGoUp) {
return new String[] {".."};
}
return new String[] {};
}
String[] results = new String[parentContents.length + (canGoUp ? 1 : 0)];
if (canGoUp) {
results[0] = "..";
}
for (int i = 0; i < parentContents.length; i++) {
results[canGoUp ? i + 1 : i] = parentContents[i].getName();
}
return results;
}
private File[] listFiles() {
File[] contents = parentFolder.listFiles();
List<File> results = new ArrayList<>();
if (contents != null) {
for (File fi : contents) {
if (fi.isDirectory()) {
results.add(fi);
}
}
Collections.sort(results, new FolderSorter());
return results.toArray(new File[results.size()]);
}
return null;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& ActivityCompat.checkSelfPermission(
requireActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
return new MaterialDialog.Builder(requireActivity())
.title(R.string.md_error_label)
.content(R.string.md_storage_perm_error)
.positiveText(android.R.string.ok)
.build();
}
if (savedInstanceState == null) {
savedInstanceState = new Bundle();
}
if (!savedInstanceState.containsKey("current_path")) {
savedInstanceState.putString("current_path", initialPath);
}
parentFolder = new File(savedInstanceState.getString("current_path", File.pathSeparator));
checkIfCanGoUp();
parentContents = listFiles();
MaterialDialog.Builder builder =
new MaterialDialog.Builder(requireContext())
.title(parentFolder.getAbsolutePath())
.items((CharSequence[]) getContentsArray())
.itemsCallback(this)
.autoDismiss(false)
.onPositive(
(dialog, which) -> {
callback.onFolderSelection(BlacklistFolderChooserDialog.this, parentFolder);
dismiss();
})
.onNegative((materialDialog, dialogAction) -> dismiss())
.positiveText(R.string.add_action)
.negativeText(android.R.string.cancel);
return builder.build();
}
@Override
public void onSelection(MaterialDialog materialDialog, View view, int i, CharSequence s) {
if (canGoUp && i == 0) {
parentFolder = parentFolder.getParentFile();
if (parentFolder.getAbsolutePath().equals("/storage/emulated")) {
parentFolder = parentFolder.getParentFile();
}
checkIfCanGoUp();
} else {
parentFolder = parentContents[canGoUp ? i - 1 : i];
canGoUp = true;
if (parentFolder.getAbsolutePath().equals("/storage/emulated")) {
parentFolder = Environment.getExternalStorageDirectory();
}
}
reload();
}
private void checkIfCanGoUp() {
canGoUp = parentFolder.getParent() != null;
}
private void reload() {
parentContents = listFiles();
MaterialDialog dialog = (MaterialDialog) getDialog();
dialog.setTitle(parentFolder.getAbsolutePath());
dialog.setItems((CharSequence[]) getContentsArray());
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("current_path", parentFolder.getAbsolutePath());
}
public void setCallback(FolderCallback callback) {
this.callback = callback;
}
public interface FolderCallback {
void onFolderSelection(@NonNull BlacklistFolderChooserDialog dialog, @NonNull File folder);
}
private static class FolderSorter implements Comparator<File> {
@Override
public int compare(File lhs, File rhs) {
return lhs.getName().compareTo(rhs.getName());
}
}
}

View file

@ -0,0 +1,152 @@
package code.name.monkey.retromusic.dialogs
import android.Manifest
import android.app.Dialog
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Environment
import androidx.core.app.ActivityCompat
import androidx.fragment.app.DialogFragment
import code.name.monkey.retromusic.R
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.list.listItems
import com.afollestad.materialdialogs.list.updateListItems
import java.io.File
import java.util.*
class BlacklistFolderChooserDialog : DialogFragment() {
private var initialPath: String = Environment.getExternalStorageDirectory().absolutePath
private var parentFolder: File? = null
private var parentContents: Array<File>? = null
private var canGoUp = false
private var callback: FolderCallback? = null
private val contentsArray: Array<String?>
get() {
if (parentContents == null) {
return if (canGoUp) {
arrayOf("..")
} else arrayOf()
}
val results = arrayOfNulls<String>(parentContents!!.size + if (canGoUp) 1 else 0)
if (canGoUp) {
results[0] = ".."
}
for (i in parentContents!!.indices) {
results[if (canGoUp) i + 1 else i] = parentContents!![i].name
}
return results
}
private fun listFiles(): Array<File>? {
val contents = parentFolder!!.listFiles()
val results: MutableList<File> = ArrayList()
if (contents != null) {
for (fi in contents) {
if (fi.isDirectory) {
results.add(fi)
}
}
Collections.sort(results, FolderSorter())
return results.toTypedArray()
}
return null
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
var mSavedInstanceState = savedInstanceState
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& ActivityCompat.checkSelfPermission(
requireActivity(), Manifest.permission.READ_EXTERNAL_STORAGE
)
!= PackageManager.PERMISSION_GRANTED
) {
return MaterialDialog(requireActivity()).show {
title(res = R.string.md_error_label)
message(res = R.string.md_storage_perm_error)
positiveButton(res = android.R.string.ok)
}
}
if (mSavedInstanceState == null) {
mSavedInstanceState = Bundle()
}
if (!mSavedInstanceState.containsKey("current_path")) {
mSavedInstanceState.putString("current_path", initialPath)
}
parentFolder = File(mSavedInstanceState.getString("current_path", File.pathSeparator))
checkIfCanGoUp()
parentContents = listFiles()
return MaterialDialog(requireContext())
.title(text = parentFolder!!.absolutePath)
.listItems(
items = contentsArray.toCharSequence(),
waitForPositiveButton = false
) { _: MaterialDialog, i: Int, _: CharSequence ->
onSelection(i)
}
.noAutoDismiss()
.cornerRadius(literalDp = 20F)
.positiveButton(res = R.string.add_action) {
callback!!.onFolderSelection(this@BlacklistFolderChooserDialog, parentFolder!!)
dismiss()
}
.negativeButton(res = android.R.string.cancel) { dismiss() }
}
private fun onSelection(i: Int) {
if (canGoUp && i == 0) {
parentFolder = parentFolder!!.parentFile
if (parentFolder!!.absolutePath == "/storage/emulated") {
parentFolder = parentFolder!!.parentFile
}
checkIfCanGoUp()
} else {
parentFolder = parentContents!![if (canGoUp) i - 1 else i]
canGoUp = true
if (parentFolder!!.absolutePath == "/storage/emulated") {
parentFolder = Environment.getExternalStorageDirectory()
}
}
reload()
}
private fun checkIfCanGoUp() {
canGoUp = parentFolder!!.parent != null
}
private fun reload() {
parentContents = listFiles()
val dialog = dialog as MaterialDialog?
dialog!!.setTitle(parentFolder!!.absolutePath)
dialog.updateListItems(items = contentsArray.toCharSequence())
}
private fun Array<String?>.toCharSequence(): List<CharSequence> {
return map { it as CharSequence }
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("current_path", parentFolder!!.absolutePath)
}
fun setCallback(callback: FolderCallback?) {
this.callback = callback
}
interface FolderCallback {
fun onFolderSelection(dialog: BlacklistFolderChooserDialog, folder: File)
}
private class FolderSorter : Comparator<File> {
override fun compare(lhs: File, rhs: File): Int {
return lhs.name.compareTo(rhs.name)
}
}
companion object {
fun create(): BlacklistFolderChooserDialog {
return BlacklistFolderChooserDialog()
}
}
}

View file

@ -17,29 +17,23 @@ package code.name.monkey.retromusic.dialogs
import android.app.Dialog
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import android.widget.Toast
import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.EXTRA_SONG
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.db.PlaylistEntity
import code.name.monkey.retromusic.db.toSongEntity
import code.name.monkey.retromusic.databinding.DialogPlaylistBinding
import code.name.monkey.retromusic.extensions.colorButtons
import code.name.monkey.retromusic.extensions.extra
import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.fragments.ReloadType.Playlists
import code.name.monkey.retromusic.model.Song
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
import kotlinx.android.synthetic.main.dialog_playlist.view.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class CreatePlaylistDialog : DialogFragment() {
private var _binding: DialogPlaylistBinding? = null
private val binding get() = _binding!!
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
companion object {
@ -56,13 +50,15 @@ class CreatePlaylistDialog : DialogFragment() {
}
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val view = LayoutInflater.from(requireActivity()).inflate(R.layout.dialog_playlist, null)
_binding = DialogPlaylistBinding.inflate(layoutInflater)
val songs: List<Song> = extra<List<Song>>(EXTRA_SONG).value ?: emptyList()
val playlistView: TextInputEditText = view.actionNewPlaylist
val playlistContainer: TextInputLayout = view.actionNewPlaylistContainer
val playlistView: TextInputEditText = binding.actionNewPlaylist
val playlistContainer: TextInputLayout = binding.actionNewPlaylistContainer
return materialDialog(R.string.new_playlist_title)
.setView(view)
.setView(binding.root)
.setPositiveButton(
R.string.create_action
) { _, _ ->
@ -77,4 +73,9 @@ class CreatePlaylistDialog : DialogFragment() {
.create()
.colorButtons()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}

View file

@ -14,24 +14,31 @@
*/
package code.name.monkey.retromusic.dialogs
import android.app.Activity
import android.app.Dialog
import android.content.Intent
import android.os.Bundle
import androidx.core.os.bundleOf
import androidx.core.text.HtmlCompat
import androidx.fragment.app.DialogFragment
import code.name.monkey.retromusic.EXTRA_SONG
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.colorButtons
import code.name.monkey.retromusic.activities.saf.SAFGuideActivity
import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.fragments.ReloadType
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
import code.name.monkey.retromusic.util.SAFUtil
import com.afollestad.materialdialogs.MaterialDialog
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.koin.androidx.viewmodel.ext.android.getViewModel
class DeleteSongsDialog : DialogFragment() {
private val libraryViewModel by sharedViewModel<LibraryViewModel>()
lateinit var libraryViewModel: LibraryViewModel
companion object {
fun create(song: Song): DeleteSongsDialog {
@ -50,6 +57,7 @@ class DeleteSongsDialog : DialogFragment() {
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
libraryViewModel = activity?.getViewModel() as LibraryViewModel
val songs = extraNotNull<List<Song>>(EXTRA_SONG).value
val pair = if (songs.size > 1) {
Pair(
@ -69,17 +77,66 @@ class DeleteSongsDialog : DialogFragment() {
)
}
return materialDialog(pair.first)
.setMessage(pair.second)
.setCancelable(false)
.setPositiveButton(R.string.action_delete) { _, _ ->
if (songs.isNotEmpty() and (songs.size == 1) and MusicPlayerRemote.isPlaying(songs.first())) {
return MaterialDialog(requireContext())
.title(pair.first)
.message(text = pair.second)
.noAutoDismiss()
.cornerRadius(16F)
.negativeButton(android.R.string.cancel) {
dismiss()
}
.positiveButton(R.string.action_delete) {
if ((songs.size == 1) && MusicPlayerRemote.isPlaying(songs[0])) {
MusicPlayerRemote.playNextSong()
}
MusicUtil.deleteTracks(requireActivity(), songs)
libraryViewModel.deleteTracks(songs)
if (!SAFUtil.isSAFRequiredForSongs(songs)) {
CoroutineScope(Dispatchers.IO).launch {
dismiss()
MusicUtil.deleteTracks(requireContext(), songs)
reloadTabs()
}
} else {
if (SAFUtil.isSDCardAccessGranted(requireActivity())) {
deleteSongs(songs)
} else {
startActivityForResult(
Intent(requireActivity(), SAFGuideActivity::class.java),
SAFGuideActivity.REQUEST_CODE_SAF_GUIDE
)
}
}
}
.create()
.colorButtons()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
SAFGuideActivity.REQUEST_CODE_SAF_GUIDE -> {
SAFUtil.openTreePicker(this)
}
SAFUtil.REQUEST_SAF_PICK_TREE,
SAFUtil.REQUEST_SAF_PICK_FILE -> {
if (resultCode == Activity.RESULT_OK) {
SAFUtil.saveTreeUri(requireActivity(), data)
val songs = extraNotNull<List<Song>>(EXTRA_SONG).value
deleteSongs(songs)
}
}
}
}
fun deleteSongs(songs: List<Song>) {
CoroutineScope(Dispatchers.IO).launch {
dismiss()
MusicUtil.deleteTracks(requireActivity(), songs, null, null)
reloadTabs()
}
}
fun reloadTabs() {
libraryViewModel.forceReload(ReloadType.Songs)
libraryViewModel.forceReload(ReloadType.HomeSections)
libraryViewModel.forceReload(ReloadType.Artists)
libraryViewModel.forceReload(ReloadType.Albums)
}
}

View file

@ -38,8 +38,9 @@ import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.ACTION_PENDING_QUIT
import code.name.monkey.retromusic.service.MusicService.ACTION_QUIT
import code.name.monkey.retromusic.util.PreferenceUtil
import com.afollestad.materialdialogs.DialogAction
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.WhichButton
import com.afollestad.materialdialogs.actions.getActionButton
class SleepTimerDialog : DialogFragment() {
@ -150,14 +151,14 @@ class SleepTimerDialog : DialogFragment() {
private fun updateCancelButton() {
val musicService = MusicPlayerRemote.musicService
if (musicService != null && musicService.pendingQuit) {
dialog.getActionButton(DialogAction.NEUTRAL).text =
dialog.getActionButton(WhichButton.NEUTRAL).text =
dialog.context.getString(R.string.cancel_current_timer)
} else {
dialog.getActionButton(DialogAction.NEUTRAL).text = null
dialog.getActionButton(WhichButton.NEUTRAL).text = null
}
}
private inner class TimerUpdater() :
private inner class TimerUpdater :
CountDownTimer(
PreferenceUtil.nextSleepTimerElapsedRealTime - SystemClock.elapsedRealtime(),
1000

View file

@ -32,13 +32,13 @@ import code.name.monkey.retromusic.extensions.colorButtons
import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
import java.io.File
import java.io.IOException
import org.jaudiotagger.audio.AudioFileIO
import org.jaudiotagger.audio.exceptions.CannotReadException
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException
import org.jaudiotagger.tag.TagException
import java.io.File
import java.io.IOException
class SongDetailDialog : DialogFragment() {