Fixed Playlist save

main
Prathamesh More 2021-11-17 16:52:39 +05:30
parent 9a32aa2805
commit e9b7b5a203
5 changed files with 129 additions and 33 deletions

View File

@ -21,13 +21,16 @@ import android.widget.Toast
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.App import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.EXTRA_PLAYLIST import code.name.monkey.retromusic.EXTRA_PLAYLIST
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.colorButtons
import code.name.monkey.retromusic.extensions.createNewFile
import code.name.monkey.retromusic.extensions.extraNotNull import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.helper.M3UWriter
import code.name.monkey.retromusic.util.PlaylistsUtil import code.name.monkey.retromusic.util.PlaylistsUtil
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -46,22 +49,59 @@ class SavePlaylistDialog : DialogFragment() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
lifecycleScope.launch(Dispatchers.IO) { val playlistWithSongs = extraNotNull<PlaylistWithSongs>(EXTRA_PLAYLIST).value
val playlistWithSongs = extraNotNull<PlaylistWithSongs>(EXTRA_PLAYLIST).value
val file = PlaylistsUtil.savePlaylistWithSongs(playlistWithSongs) if (VersionUtils.hasR()) {
MediaScannerConnection.scanFile( createNewFile(
requireActivity(), "audio/mpegurl",
arrayOf<String>(file.path), playlistWithSongs.playlistEntity.playlistName
null ) { outputStream, data ->
) { _, _ -> try {
if (outputStream != null) {
lifecycleScope.launch(Dispatchers.IO) {
M3UWriter.writeIO(
outputStream,
playlistWithSongs
)
withContext(Dispatchers.Main) {
Toast.makeText(
requireContext(),
String.format(
requireContext().getString(R.string.saved_playlist_to),
data?.lastPathSegment
),
Toast.LENGTH_LONG
).show()
dismiss()
}
}
}
} catch (e: Exception) {
Toast.makeText(
context,
"Something went wrong : " + e.message,
Toast.LENGTH_SHORT
)
.show()
}
} }
withContext(Dispatchers.Main) { } else {
Toast.makeText( lifecycleScope.launch(Dispatchers.IO) {
requireContext(), val file = PlaylistsUtil.savePlaylistWithSongs(playlistWithSongs)
String.format(App.getContext().getString(R.string.saved_playlist_to), file), MediaScannerConnection.scanFile(
Toast.LENGTH_LONG requireActivity(),
).show() arrayOf<String>(file.path),
dismiss() null
) { _, _ ->
}
withContext(Dispatchers.Main) {
Toast.makeText(
requireContext(),
String.format(App.getContext().getString(R.string.saved_playlist_to), file),
Toast.LENGTH_LONG
).show()
dismiss()
}
} }
} }
} }

View File

@ -0,0 +1,35 @@
package code.name.monkey.retromusic.extensions
import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Environment
import android.provider.DocumentsContract
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.Fragment
import java.io.File
import java.io.OutputStream
fun Fragment.createNewFile(
mimeType: String,
fileName: String,
write: (outputStream: OutputStream?, data: Uri?) -> Unit
) {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = mimeType
intent.putExtra(Intent.EXTRA_TITLE, fileName)
val startForResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{ result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
val outputStream: OutputStream? =
context?.contentResolver?.openOutputStream(result.data?.data!!)
write(outputStream, result.data?.data)
}
}
startForResult.launch(intent)
}

View File

@ -18,10 +18,7 @@ import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.toSongs import code.name.monkey.retromusic.db.toSongs
import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Playlist
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import java.io.BufferedWriter import java.io.*
import java.io.File
import java.io.FileWriter
import java.io.IOException
object M3UWriter : M3UConstants { object M3UWriter : M3UConstants {
@JvmStatic @JvmStatic
@ -69,4 +66,23 @@ object M3UWriter : M3UConstants {
} }
return file return file
} }
fun writeIO(outputStream: OutputStream, playlistWithSongs: PlaylistWithSongs) {
val songs: List<Song> = playlistWithSongs.songs.sortedBy {
it.songPrimaryKey
}.toSongs()
if (songs.isNotEmpty()) {
val bufferedWriter = outputStream.bufferedWriter()
bufferedWriter.write(M3UConstants.HEADER)
songs.forEach {
bufferedWriter.newLine()
bufferedWriter.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title)
bufferedWriter.newLine()
bufferedWriter.write(it.data)
}
bufferedWriter.close()
}
outputStream.flush()
outputStream.close()
}
} }

View File

@ -36,6 +36,7 @@ import java.util.List;
import code.name.monkey.retromusic.R; import code.name.monkey.retromusic.R;
import code.name.monkey.retromusic.db.PlaylistWithSongs; import code.name.monkey.retromusic.db.PlaylistWithSongs;
import code.name.monkey.retromusic.helper.M3UConstants;
import code.name.monkey.retromusic.helper.M3UWriter; import code.name.monkey.retromusic.helper.M3UWriter;
import code.name.monkey.retromusic.model.Playlist; import code.name.monkey.retromusic.model.Playlist;
import code.name.monkey.retromusic.model.PlaylistSong; import code.name.monkey.retromusic.model.PlaylistSong;
@ -319,9 +320,9 @@ public class PlaylistsUtil {
private static boolean doesPlaylistExist( private static boolean doesPlaylistExist(
@NonNull Context context, @NonNull final String selection, @NonNull final String[] values) { @NonNull Context context, @NonNull final String selection, @NonNull final String[] values) {
Cursor cursor = Cursor cursor =
context context
.getContentResolver() .getContentResolver()
.query(EXTERNAL_CONTENT_URI, new String[] {}, selection, values, null); .query(EXTERNAL_CONTENT_URI, new String[]{}, selection, values, null);
boolean exists = false; boolean exists = false;
if (cursor != null) { if (cursor != null) {

View File

@ -8,18 +8,11 @@ import android.os.Build
object VersionUtils { object VersionUtils {
/**
* @return true if device is running API >= 21
*/
fun hasLollipop(): Boolean {
return Build.VERSION.SDK_INT >= 21
}
/** /**
* @return true if device is running API >= 23 * @return true if device is running API >= 23
*/ */
fun hasMarshmallow(): Boolean { fun hasMarshmallow(): Boolean {
return Build.VERSION.SDK_INT >= 23 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
} }
/** /**
@ -30,7 +23,7 @@ object VersionUtils {
} }
/** /**
* @return true if device is running API >= 24 * @return true if device is running API >= 25
*/ */
fun hasNougatMR(): Boolean { fun hasNougatMR(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1
@ -44,20 +37,31 @@ object VersionUtils {
} }
/** /**
* @return true if device is running API >= 27 * @return true if device is running API >= 28
*/ */
fun hasP(): Boolean { fun hasP(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
} }
/** /**
* @return true if device is running API >= 28 * @return true if device is running API >= 29
*/ */
@JvmStatic @JvmStatic
fun hasQ(): Boolean { fun hasQ(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
} }
/**
* @return true if device is running API >= 30
*/
@JvmStatic
fun hasR(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.R
}
/**
* @return true if device is running API >= 31
*/
@JvmStatic @JvmStatic
fun hasS(): Boolean { fun hasS(): Boolean {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S return Build.VERSION.SDK_INT >= Build.VERSION_CODES.S