diff --git a/app/src/main/java/com/github/libretube/adapters/PlaylistAdapter.kt b/app/src/main/java/com/github/libretube/adapters/PlaylistAdapter.kt index 3938ae50d4..bfc1e481a9 100644 --- a/app/src/main/java/com/github/libretube/adapters/PlaylistAdapter.kt +++ b/app/src/main/java/com/github/libretube/adapters/PlaylistAdapter.kt @@ -21,7 +21,8 @@ import com.github.libretube.obj.StreamItem import com.github.libretube.util.RetrofitInstance import com.squareup.picasso.Picasso import java.io.IOException -import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import retrofit2.HttpException @@ -92,7 +93,7 @@ class PlaylistAdapter( private fun removeFromPlaylist(token: String, position: Int) { fun run() { - GlobalScope.launch { + CoroutineScope(Dispatchers.IO).launch { val response = try { RetrofitInstance.api.removeFromPlaylist( token, diff --git a/app/src/main/java/com/github/libretube/adapters/SearchAdapter.kt b/app/src/main/java/com/github/libretube/adapters/SearchAdapter.kt index 75fedea491..33b5c705fe 100644 --- a/app/src/main/java/com/github/libretube/adapters/SearchAdapter.kt +++ b/app/src/main/java/com/github/libretube/adapters/SearchAdapter.kt @@ -13,6 +13,7 @@ import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.RecyclerView import com.github.libretube.MainActivity import com.github.libretube.R +import com.github.libretube.dialogs.PlaylistOptionsDialog import com.github.libretube.dialogs.VideoOptionsDialog import com.github.libretube.fragments.PlayerFragment import com.github.libretube.obj.SearchItem @@ -153,6 +154,12 @@ class SearchViewHolder( val bundle = bundleOf("playlist_id" to item.url) activity.navController.navigate(R.id.playlistFragment, bundle) } + v.setOnLongClickListener { + val playlistId = item.url!!.replace("/playlist?list=", "") + PlaylistOptionsDialog(playlistId, v.context) + .show(childFragmentManager, "PlaylistOptionsDialog") + true + } } fun bind(searchItem: SearchItem) { diff --git a/app/src/main/java/com/github/libretube/dialogs/PlaylistOptionsDialog.kt b/app/src/main/java/com/github/libretube/dialogs/PlaylistOptionsDialog.kt new file mode 100644 index 0000000000..2c12decb97 --- /dev/null +++ b/app/src/main/java/com/github/libretube/dialogs/PlaylistOptionsDialog.kt @@ -0,0 +1,77 @@ +package com.github.libretube.dialogs + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.util.Log +import android.widget.ArrayAdapter +import androidx.fragment.app.DialogFragment +import com.github.libretube.R +import com.github.libretube.obj.PlaylistId +import com.github.libretube.util.RetrofitInstance +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import java.io.IOException +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import retrofit2.HttpException + +class PlaylistOptionsDialog( + private val playlistId: String, + context: Context +) : DialogFragment() { + val TAG = "PlaylistOptionsDialog" + + private val optionsList = listOf( + context.getString(R.string.clonePlaylist), + context.getString(R.string.share) + ) + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val dialog = MaterialAlertDialogBuilder(requireContext()) + .setNegativeButton(R.string.cancel) { dialog, _ -> + dialog.dismiss() + } + .setAdapter( + ArrayAdapter( + requireContext(), + R.layout.video_options_dialog_item, + optionsList + ) + ) { _, which -> + when (which) { + // Clone the playlist to the users Piped account + 0 -> { + val sharedPref = + context?.getSharedPreferences("token", Context.MODE_PRIVATE) + val token = sharedPref?.getString("token", "")!! + importPlaylist(token, playlistId) + } + // share the playlist + 1 -> { + val shareDialog = ShareDialog(playlistId, true) + // using parentFragmentManager is important here + shareDialog.show(parentFragmentManager, "ShareDialog") + } + } + } + return dialog.show() + } + + private fun importPlaylist(token: String, playlistId: String) { + fun run() { + CoroutineScope(Dispatchers.IO).launch { + val response = try { + RetrofitInstance.api.importPlaylist(token, PlaylistId(playlistId)) + } catch (e: IOException) { + println(e) + return@launch + } catch (e: HttpException) { + return@launch + } + Log.e(TAG, response.toString()) + } + } + run() + } +} diff --git a/app/src/main/java/com/github/libretube/dialogs/ShareDialog.kt b/app/src/main/java/com/github/libretube/dialogs/ShareDialog.kt index bddaf47453..992b4d1c06 100644 --- a/app/src/main/java/com/github/libretube/dialogs/ShareDialog.kt +++ b/app/src/main/java/com/github/libretube/dialogs/ShareDialog.kt @@ -3,12 +3,17 @@ package com.github.libretube.dialogs import android.app.Dialog import android.content.Intent import android.os.Bundle +import androidx.core.content.ContentProviderCompat.requireContext import androidx.fragment.app.DialogFragment import androidx.preference.PreferenceManager import com.github.libretube.R +import com.github.libretube.util.RetrofitInstance.url import com.google.android.material.dialog.MaterialAlertDialogBuilder -class ShareDialog(private val videoId: String) : DialogFragment() { +class ShareDialog( + private val id: String, + private val isPlaylist: Boolean +) : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return activity?.let { @@ -25,17 +30,22 @@ class ShareDialog(private val videoId: String) : DialogFragment() { .setTitle(context?.getString(R.string.share)) .setItems( shareOptions - ) { _, id -> - val url = when (id) { - 0 -> "https://piped.kavin.rocks/watch?v=$videoId" - 1 -> "https://youtu.be/$videoId" - 2 -> "$instanceUrl/watch?v=$videoId" // only available for custom instances - else -> "https://piped.kavin.rocks/watch?v=$videoId" + ) { _, which -> + val host = when (which) { + 0 -> "https://piped.kavin.rocks" + 1 -> "https://youtube.com" + // only available for custom instances + else -> instanceUrl } + val path = if (!isPlaylist) "/watch?v=$id" else "/playlist?list=$id" + val url = "$host$path" + val intent = Intent() - intent.action = Intent.ACTION_SEND - intent.putExtra(Intent.EXTRA_TEXT, url) - intent.type = "text/plain" + intent.apply { + action = Intent.ACTION_SEND + putExtra(Intent.EXTRA_TEXT, url) + type = "text/plain" + } context?.startActivity( Intent.createChooser(intent, context?.getString(R.string.shareTo)) ) diff --git a/app/src/main/java/com/github/libretube/dialogs/VideoOptionsDialog.kt b/app/src/main/java/com/github/libretube/dialogs/VideoOptionsDialog.kt index 532808e0d8..e5eb2a764e 100644 --- a/app/src/main/java/com/github/libretube/dialogs/VideoOptionsDialog.kt +++ b/app/src/main/java/com/github/libretube/dialogs/VideoOptionsDialog.kt @@ -19,7 +19,7 @@ class VideoOptionsDialog(private val videoId: String, context: Context) : Dialog /** * List that stores the different menu options. In the future could be add more options here. */ - private val list = listOf( + private val optionsList = listOf( context.getString(R.string.playOnBackground), context.getString(R.string.addToPlaylist), context.getString(R.string.share) @@ -37,9 +37,9 @@ class VideoOptionsDialog(private val videoId: String, context: Context) : Dialog ArrayAdapter( requireContext(), R.layout.video_options_dialog_item, - list + optionsList ) - ) { dialog, which -> + ) { _, which -> // For now, this checks the position of the option with the position that is in the // list. I don't like it, but we will do like this for now. when (which) { @@ -66,13 +66,10 @@ class VideoOptionsDialog(private val videoId: String, context: Context) : Dialog } } 2 -> { - val shareDialog = ShareDialog(videoId) + val shareDialog = ShareDialog(videoId, false) // using parentFragmentManager is important here shareDialog.show(parentFragmentManager, "ShareDialog") } - else -> { - dialog.dismiss() - } } } .show() diff --git a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt index 98249200ea..54aa2cad5c 100644 --- a/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/PlayerFragment.kt @@ -564,7 +564,7 @@ class PlayerFragment : Fragment() { // share button view.findViewById(R.id.relPlayer_share).setOnClickListener { - val shareDialog = ShareDialog(videoId!!) + val shareDialog = ShareDialog(videoId!!, false) shareDialog.show(childFragmentManager, "ShareDialog") } // check if livestream diff --git a/app/src/main/java/com/github/libretube/fragments/PlaylistFragment.kt b/app/src/main/java/com/github/libretube/fragments/PlaylistFragment.kt index e52c16acef..02ac6193a3 100644 --- a/app/src/main/java/com/github/libretube/fragments/PlaylistFragment.kt +++ b/app/src/main/java/com/github/libretube/fragments/PlaylistFragment.kt @@ -6,6 +6,7 @@ import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.widget.ProgressBar import android.widget.ScrollView import android.widget.TextView import androidx.fragment.app.Fragment @@ -45,10 +46,11 @@ class PlaylistFragment : Fragment() { super.onViewCreated(view, savedInstanceState) playlistId = playlistId!!.replace("/playlist?list=", "") - view.findViewById(R.id.playlist_name).text = playlistId val recyclerView = view.findViewById(R.id.playlist_recView) recyclerView.layoutManager = LinearLayoutManager(context) + val progressBar = view.findViewById(R.id.playlist_progress) + progressBar.visibility = View.VISIBLE fetchPlaylist(view) } @@ -68,6 +70,7 @@ class PlaylistFragment : Fragment() { nextPage = response.nextpage isLoading = false runOnUiThread { + view.findViewById(R.id.playlist_progress).visibility = View.GONE view.findViewById(R.id.playlist_name).text = response.name view.findViewById(R.id.playlist_uploader).text = response.uploader view.findViewById(R.id.playlist_totVideos).text = diff --git a/app/src/main/java/com/github/libretube/util/PipedApi.kt b/app/src/main/java/com/github/libretube/util/PipedApi.kt index 5a32e9d47c..82b8c67aa5 100644 --- a/app/src/main/java/com/github/libretube/util/PipedApi.kt +++ b/app/src/main/java/com/github/libretube/util/PipedApi.kt @@ -117,6 +117,12 @@ interface PipedApi { @Body channels: List ): Message + @POST("import/playlist") + suspend fun importPlaylist( + @Header("Authorization") token: String, + @Body playlistId: PlaylistId + ): Message + @GET("user/playlists") suspend fun playlists(@Header("Authorization") token: String): List diff --git a/app/src/main/res/layout/fragment_playlist.xml b/app/src/main/res/layout/fragment_playlist.xml index 9c1e25101b..25d84fbc4d 100644 --- a/app/src/main/res/layout/fragment_playlist.xml +++ b/app/src/main/res/layout/fragment_playlist.xml @@ -1,10 +1,22 @@ - + tools:context=".fragments.PlaylistFragment"> + + + + + - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f90925c766..aef9e11b1b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -200,4 +200,5 @@ Autopause Pause the player when the screen is turned off. Automatically play the next video when the current is finished. + Clone playlist