Merge pull request #1254 from Bnyro/master

Option to rename playlists
This commit is contained in:
Bnyro 2022-09-10 12:43:56 +02:00 committed by GitHub
commit 7bfc1d18eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 451 additions and 442 deletions

View File

@ -85,32 +85,29 @@ class PlaylistsAdapter(
} }
private fun deletePlaylist(id: String, position: Int) { private fun deletePlaylist(id: String, position: Int) {
fun run() { CoroutineScope(Dispatchers.IO).launch {
CoroutineScope(Dispatchers.IO).launch { val response = try {
val response = try { RetrofitInstance.authApi.deletePlaylist(
RetrofitInstance.authApi.deletePlaylist( PreferenceHelper.getToken(),
PreferenceHelper.getToken(), PlaylistId(id)
PlaylistId(id) )
) } catch (e: IOException) {
} catch (e: IOException) { println(e)
println(e) Log.e(TAG(), "IOException, you might not have internet connection")
Log.e(TAG(), "IOException, you might not have internet connection") return@launch
return@launch } catch (e: HttpException) {
} catch (e: HttpException) { Log.e(TAG(), "HttpException, unexpected response")
Log.e(TAG(), "HttpException, unexpected response") return@launch
return@launch }
} try {
try { if (response.message == "ok") {
if (response.message == "ok") { playlists.removeAt(position)
playlists.removeAt(position) activity.runOnUiThread { notifyDataSetChanged() }
activity.runOnUiThread { notifyDataSetChanged() }
}
} catch (e: Exception) {
Log.e(TAG(), e.toString())
} }
} catch (e: Exception) {
Log.e(TAG(), e.toString())
} }
} }
run()
} }
} }

View File

@ -140,6 +140,12 @@ interface PipedApi {
@GET("user/playlists") @GET("user/playlists")
suspend fun playlists(@Header("Authorization") token: String): List<Playlists> suspend fun playlists(@Header("Authorization") token: String): List<Playlists>
@POST("user/playlists/rename")
suspend fun renamePlaylist(
@Header("Authorization") token: String,
@Body playlistId: PlaylistId
)
@POST("user/playlists/delete") @POST("user/playlists/delete")
suspend fun deletePlaylist( suspend fun deletePlaylist(
@Header("Authorization") token: String, @Header("Authorization") token: String,

View File

@ -44,51 +44,48 @@ class AddToPlaylistDialog : DialogFragment() {
} }
private fun fetchPlaylists() { private fun fetchPlaylists() {
fun run() { lifecycleScope.launchWhenCreated {
lifecycleScope.launchWhenCreated { val response = try {
val response = try { RetrofitInstance.authApi.playlists(token)
RetrofitInstance.authApi.playlists(token) } catch (e: IOException) {
} catch (e: IOException) { println(e)
println(e) Log.e(TAG(), "IOException, you might not have internet connection")
Log.e(TAG(), "IOException, you might not have internet connection") Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show() return@launchWhenCreated
return@launchWhenCreated } catch (e: HttpException) {
} catch (e: HttpException) { Log.e(TAG(), "HttpException, unexpected response")
Log.e(TAG(), "HttpException, unexpected response") Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show() return@launchWhenCreated
return@launchWhenCreated }
} if (response.isNotEmpty()) {
if (response.isNotEmpty()) { val names = response.map { it.name }
val names = response.map { it.name } val arrayAdapter =
val arrayAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, names)
ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, names) arrayAdapter.setDropDownViewResource(
arrayAdapter.setDropDownViewResource( android.R.layout.simple_spinner_dropdown_item
android.R.layout.simple_spinner_dropdown_item )
) binding.playlistsSpinner.adapter = arrayAdapter
binding.playlistsSpinner.adapter = arrayAdapter if (viewModel.lastSelectedPlaylistId != null) {
if (viewModel.lastSelectedPlaylistId != null) { var selectionIndex = 0
var selectionIndex = 0 response.forEachIndexed { index, playlist ->
response.forEachIndexed { index, playlist -> if (playlist.id == viewModel.lastSelectedPlaylistId) {
if (playlist.id == viewModel.lastSelectedPlaylistId) { selectionIndex =
selectionIndex = index
index
}
} }
binding.playlistsSpinner.setSelection(selectionIndex)
} }
runOnUiThread { binding.playlistsSpinner.setSelection(selectionIndex)
binding.addToPlaylist.setOnClickListener { }
val index = binding.playlistsSpinner.selectedItemPosition runOnUiThread {
viewModel.lastSelectedPlaylistId = response[index].id!! binding.addToPlaylist.setOnClickListener {
addToPlaylist( val index = binding.playlistsSpinner.selectedItemPosition
response[index].id!! viewModel.lastSelectedPlaylistId = response[index].id!!
) addToPlaylist(
} response[index].id!!
)
} }
} }
} }
} }
run()
} }
private fun addToPlaylist(playlistId: String) { private fun addToPlaylist(playlistId: String) {

View File

@ -50,36 +50,33 @@ class CreatePlaylistDialog : DialogFragment() {
} }
private fun createPlaylist(name: String) { private fun createPlaylist(name: String) {
fun run() { lifecycleScope.launchWhenCreated {
lifecycleScope.launchWhenCreated { val response = try {
val response = try { RetrofitInstance.authApi.createPlaylist(token, Playlists(name = name))
RetrofitInstance.authApi.createPlaylist(token, Playlists(name = name)) } catch (e: IOException) {
} catch (e: IOException) { println(e)
println(e) Log.e(TAG(), "IOException, you might not have internet connection")
Log.e(TAG(), "IOException, you might not have internet connection") Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show() return@launchWhenCreated
return@launchWhenCreated } catch (e: HttpException) {
} catch (e: HttpException) { Log.e(TAG(), "HttpException, unexpected response $e")
Log.e(TAG(), "HttpException, unexpected response $e") Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show() return@launchWhenCreated
return@launchWhenCreated
}
if (response.playlistId != null) {
Toast.makeText(context, R.string.playlistCreated, Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(context, getString(R.string.unknown_error), Toast.LENGTH_SHORT)
.show()
}
// refresh the playlists in the library
try {
val parent = parentFragment as LibraryFragment
parent.fetchPlaylists()
} catch (e: Exception) {
Log.e(TAG(), e.toString())
}
dismiss()
} }
if (response.playlistId != null) {
Toast.makeText(context, R.string.playlistCreated, Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(context, getString(R.string.unknown_error), Toast.LENGTH_SHORT)
.show()
}
// refresh the playlists in the library
try {
val parent = parentFragment as LibraryFragment
parent.fetchPlaylists()
} catch (e: Exception) {
Log.e(TAG(), e.toString())
}
dismiss()
} }
run()
} }
} }

View File

@ -41,24 +41,21 @@ class DeleteAccountDialog : DialogFragment() {
} }
private fun deleteAccount(password: String) { private fun deleteAccount(password: String) {
fun run() { lifecycleScope.launchWhenCreated {
lifecycleScope.launchWhenCreated { val token = PreferenceHelper.getToken()
val token = PreferenceHelper.getToken()
try { try {
RetrofitInstance.authApi.deleteAccount(token, DeleteUserRequest(password)) RetrofitInstance.authApi.deleteAccount(token, DeleteUserRequest(password))
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG(), e.toString()) Log.e(TAG(), e.toString())
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show() Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
return@launchWhenCreated return@launchWhenCreated
}
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
logout()
val restartDialog = RequireRestartDialog()
restartDialog.show(childFragmentManager, RequireRestartDialog::class.java.name)
} }
Toast.makeText(context, R.string.success, Toast.LENGTH_SHORT).show()
logout()
val restartDialog = RequireRestartDialog()
restartDialog.show(childFragmentManager, RequireRestartDialog::class.java.name)
} }
run()
} }
private fun logout() { private fun logout() {

View File

@ -55,35 +55,32 @@ class LoginDialog : DialogFragment() {
} }
private fun login(login: Login) { private fun login(login: Login) {
fun run() { lifecycleScope.launchWhenCreated {
lifecycleScope.launchWhenCreated { val response = try {
val response = try { RetrofitInstance.authApi.login(login)
RetrofitInstance.authApi.login(login) } catch (e: IOException) {
} catch (e: IOException) { println(e)
println(e) Log.e(TAG(), "IOException, you might not have internet connection")
Log.e(TAG(), "IOException, you might not have internet connection") Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show() return@launchWhenCreated
return@launchWhenCreated } catch (e: HttpException) {
} catch (e: HttpException) { Log.e(TAG(), "HttpException, unexpected response")
Log.e(TAG(), "HttpException, unexpected response") Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show() return@launchWhenCreated
return@launchWhenCreated } catch (e: Exception) {
} catch (e: Exception) { Log.e(TAG(), "dafaq?$e")
Log.e(TAG(), "dafaq?$e") return@launchWhenCreated
return@launchWhenCreated }
} if (response.error != null) {
if (response.error != null) { Toast.makeText(context, response.error, Toast.LENGTH_SHORT).show()
Toast.makeText(context, response.error, Toast.LENGTH_SHORT).show() } else if (response.token != null) {
} else if (response.token != null) { Toast.makeText(context, R.string.loggedIn, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.loggedIn, Toast.LENGTH_SHORT).show() PreferenceHelper.setToken(response.token!!)
PreferenceHelper.setToken(response.token!!) PreferenceHelper.setUsername(login.username!!)
PreferenceHelper.setUsername(login.username!!) dialog?.dismiss()
dialog?.dismiss() activity?.recreate()
activity?.recreate()
}
} }
} }
run()
} }
private fun register(login: Login) { private fun register(login: Login) {

View File

@ -2,12 +2,14 @@ package com.github.libretube.dialogs
import android.app.Dialog import android.app.Dialog
import android.os.Bundle import android.os.Bundle
import android.text.InputType
import android.util.Log import android.util.Log
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.RetrofitInstance
import com.github.libretube.databinding.DialogTextPreferenceBinding
import com.github.libretube.extensions.TAG import com.github.libretube.extensions.TAG
import com.github.libretube.extensions.toID import com.github.libretube.extensions.toID
import com.github.libretube.obj.PlaylistId import com.github.libretube.obj.PlaylistId
@ -36,6 +38,7 @@ class PlaylistOptionsDialog(
if (isOwner) { if (isOwner) {
optionsList = optionsList + optionsList = optionsList +
context?.getString(R.string.renamePlaylist)!! +
context?.getString(R.string.deletePlaylist)!! - context?.getString(R.string.deletePlaylist)!! -
context?.getString(R.string.clonePlaylist)!! context?.getString(R.string.clonePlaylist)!!
} }
@ -88,8 +91,31 @@ class PlaylistOptionsDialog(
shareDialog.show(parentFragmentManager, ShareDialog::class.java.name) shareDialog.show(parentFragmentManager, ShareDialog::class.java.name)
} }
context?.getString(R.string.deletePlaylist) -> { context?.getString(R.string.deletePlaylist) -> {
val token = PreferenceHelper.getToken() deletePlaylist(
deletePlaylist(playlistId, token) playlistId
)
}
context?.getString(R.string.renamePlaylist) -> {
val binding = DialogTextPreferenceBinding.inflate(layoutInflater)
binding.input.hint = context?.getString(R.string.playlistName)
binding.input.inputType = InputType.TYPE_CLASS_TEXT
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.renamePlaylist)
.setView(binding.root)
.setPositiveButton(R.string.okay) { _, _ ->
if (binding.input.text.toString() == "") {
Toast.makeText(
context,
R.string.emptyPlaylistName,
Toast.LENGTH_SHORT
).show()
return@setPositiveButton
}
renamePlaylist(playlistId, binding.input.text.toString())
}
.setNegativeButton(R.string.cancel, null)
.show()
} }
} }
} }
@ -97,37 +123,45 @@ class PlaylistOptionsDialog(
} }
private fun importPlaylist(token: String, playlistId: String) { private fun importPlaylist(token: String, playlistId: String) {
fun run() { CoroutineScope(Dispatchers.IO).launch {
CoroutineScope(Dispatchers.IO).launch { val response = try {
val response = try { RetrofitInstance.authApi.importPlaylist(token, PlaylistId(playlistId))
RetrofitInstance.authApi.importPlaylist(token, PlaylistId(playlistId)) } catch (e: IOException) {
} catch (e: IOException) { println(e)
println(e) return@launch
return@launch } catch (e: HttpException) {
} catch (e: HttpException) { return@launch
return@launch
}
Log.e(TAG(), response.toString())
} }
Log.e(TAG(), response.toString())
} }
run()
} }
private fun deletePlaylist(id: String, token: String) { private fun renamePlaylist(id: String, newName: String) {
fun run() { CoroutineScope(Dispatchers.IO).launch {
CoroutineScope(Dispatchers.IO).launch { try {
try { RetrofitInstance.authApi.renamePlaylist(
RetrofitInstance.authApi.deletePlaylist(token, PlaylistId(id)) PreferenceHelper.getToken(),
} catch (e: IOException) { PlaylistId(
println(e) playlistId = id,
Log.e(TAG(), "IOException, you might not have internet connection") newName = newName
return@launch )
} catch (e: HttpException) { )
Log.e(TAG(), "HttpException, unexpected response") } catch (e: Exception) {
return@launch return@launch
} }
}
}
private fun deletePlaylist(id: String) {
CoroutineScope(Dispatchers.IO).launch {
try {
RetrofitInstance.authApi.deletePlaylist(
PreferenceHelper.getToken(),
PlaylistId(id)
)
} catch (e: Exception) {
return@launch
} }
} }
run()
} }
} }

View File

@ -83,87 +83,84 @@ class ChannelFragment : BaseFragment() {
} }
private fun fetchChannel() { private fun fetchChannel() {
fun run() { lifecycleScope.launchWhenCreated {
lifecycleScope.launchWhenCreated { val response = try {
val response = try { if (channelId != null) {
if (channelId != null) { RetrofitInstance.api.getChannel(channelId!!)
RetrofitInstance.api.getChannel(channelId!!) } else {
} else { RetrofitInstance.api.getChannelByName(channelName!!)
RetrofitInstance.api.getChannelByName(channelName!!)
}
} catch (e: IOException) {
binding.channelRefresh.isRefreshing = false
println(e)
Log.e(TAG(), "IOException, you might not have internet connection")
return@launchWhenCreated
} catch (e: HttpException) {
binding.channelRefresh.isRefreshing = false
Log.e(TAG(), "HttpException, unexpected response")
return@launchWhenCreated
} }
// needed if the channel gets loaded by the ID } catch (e: IOException) {
channelId = response.id
// fetch and update the subscription status
isSubscribed = SubscriptionHelper.isSubscribed(channelId!!)
if (isSubscribed == null) return@launchWhenCreated
runOnUiThread {
if (isSubscribed == true) {
binding.channelSubscribe.text = getString(R.string.unsubscribe)
}
binding.channelSubscribe.setOnClickListener {
binding.channelSubscribe.text = if (isSubscribed == true) {
SubscriptionHelper.unsubscribe(channelId!!)
isSubscribed = false
getString(R.string.subscribe)
} else {
SubscriptionHelper.subscribe(channelId!!)
isSubscribed = true
getString(R.string.unsubscribe)
}
}
}
nextPage = response.nextpage
isLoading = false
binding.channelRefresh.isRefreshing = false binding.channelRefresh.isRefreshing = false
println(e)
Log.e(TAG(), "IOException, you might not have internet connection")
return@launchWhenCreated
} catch (e: HttpException) {
binding.channelRefresh.isRefreshing = false
Log.e(TAG(), "HttpException, unexpected response")
return@launchWhenCreated
}
// needed if the channel gets loaded by the ID
channelId = response.id
runOnUiThread { // fetch and update the subscription status
binding.channelScrollView.visibility = View.VISIBLE isSubscribed = SubscriptionHelper.isSubscribed(channelId!!)
binding.channelName.text = response.name if (isSubscribed == null) return@launchWhenCreated
if (response.verified) {
binding.channelName.setCompoundDrawablesWithIntrinsicBounds( runOnUiThread {
0, if (isSubscribed == true) {
0, binding.channelSubscribe.text = getString(R.string.unsubscribe)
R.drawable.ic_verified, }
0
) binding.channelSubscribe.setOnClickListener {
} binding.channelSubscribe.text = if (isSubscribed == true) {
binding.channelSubs.text = resources.getString( SubscriptionHelper.unsubscribe(channelId!!)
R.string.subscribers, isSubscribed = false
response.subscriberCount.formatShort() getString(R.string.subscribe)
)
if (response.description?.trim() == "") {
binding.channelDescription.visibility = View.GONE
} else { } else {
binding.channelDescription.text = response.description?.trim() SubscriptionHelper.subscribe(channelId!!)
isSubscribed = true
getString(R.string.unsubscribe)
} }
ImageHelper.loadImage(response.bannerUrl, binding.channelBanner)
ImageHelper.loadImage(response.avatarUrl, binding.channelImage)
// recyclerview of the videos by the channel
channelAdapter = ChannelAdapter(
response.relatedStreams!!.toMutableList(),
childFragmentManager
)
binding.channelRecView.adapter = channelAdapter
} }
} }
nextPage = response.nextpage
isLoading = false
binding.channelRefresh.isRefreshing = false
runOnUiThread {
binding.channelScrollView.visibility = View.VISIBLE
binding.channelName.text = response.name
if (response.verified) {
binding.channelName.setCompoundDrawablesWithIntrinsicBounds(
0,
0,
R.drawable.ic_verified,
0
)
}
binding.channelSubs.text = resources.getString(
R.string.subscribers,
response.subscriberCount.formatShort()
)
if (response.description?.trim() == "") {
binding.channelDescription.visibility = View.GONE
} else {
binding.channelDescription.text = response.description?.trim()
}
ImageHelper.loadImage(response.bannerUrl, binding.channelBanner)
ImageHelper.loadImage(response.avatarUrl, binding.channelImage)
// recyclerview of the videos by the channel
channelAdapter = ChannelAdapter(
response.relatedStreams!!.toMutableList(),
childFragmentManager
)
binding.channelRecView.adapter = channelAdapter
}
} }
run()
} }
private fun fetchChannelNextPage() { private fun fetchChannelNextPage() {

View File

@ -62,50 +62,47 @@ class HomeFragment : BaseFragment() {
} }
private fun fetchTrending() { private fun fetchTrending() {
fun run() { lifecycleScope.launchWhenCreated {
lifecycleScope.launchWhenCreated { val response = try {
val response = try { RetrofitInstance.api.getTrending(region)
RetrofitInstance.api.getTrending(region) } catch (e: IOException) {
} catch (e: IOException) { println(e)
println(e) Log.e(TAG(), "IOException, you might not have internet connection")
Log.e(TAG(), "IOException, you might not have internet connection") Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show() return@launchWhenCreated
return@launchWhenCreated } catch (e: HttpException) {
} catch (e: HttpException) { Log.e(TAG(), "HttpException, unexpected response")
Log.e(TAG(), "HttpException, unexpected response") Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show() return@launchWhenCreated
return@launchWhenCreated } finally {
} finally { binding.homeRefresh.isRefreshing = false
binding.homeRefresh.isRefreshing = false }
} runOnUiThread {
runOnUiThread { binding.progressBar.visibility = View.GONE
binding.progressBar.visibility = View.GONE if (
if ( PreferenceHelper.getBoolean(
PreferenceHelper.getBoolean( PreferenceKeys.ALTERNATIVE_TRENDING_LAYOUT,
PreferenceKeys.ALTERNATIVE_TRENDING_LAYOUT, false
false )
) ) {
) { binding.recview.layoutManager = LinearLayoutManager(context)
binding.recview.layoutManager = LinearLayoutManager(context)
binding.recview.adapter = ChannelAdapter( binding.recview.adapter = ChannelAdapter(
response.toMutableList(), response.toMutableList(),
childFragmentManager childFragmentManager
) )
} else { } else {
binding.recview.layoutManager = GridLayoutManager( binding.recview.layoutManager = GridLayoutManager(
context, context,
PreferenceHelper.getString( PreferenceHelper.getString(
PreferenceKeys.GRID_COLUMNS, PreferenceKeys.GRID_COLUMNS,
resources.getInteger(R.integer.grid_items).toString() resources.getInteger(R.integer.grid_items).toString()
).toInt() ).toInt()
) )
binding.recview.adapter = TrendingAdapter(response, childFragmentManager) binding.recview.adapter = TrendingAdapter(response, childFragmentManager)
}
} }
} }
} }
run()
} }
} }

View File

@ -95,51 +95,48 @@ class LibraryFragment : BaseFragment() {
} }
fun fetchPlaylists() { fun fetchPlaylists() {
fun run() { binding.playlistRefresh.isRefreshing = true
binding.playlistRefresh.isRefreshing = true lifecycleScope.launchWhenCreated {
lifecycleScope.launchWhenCreated { val response = try {
val response = try { RetrofitInstance.authApi.playlists(token)
RetrofitInstance.authApi.playlists(token) } catch (e: IOException) {
} catch (e: IOException) { println(e)
println(e) Log.e(TAG(), "IOException, you might not have internet connection")
Log.e(TAG(), "IOException, you might not have internet connection") Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.unknown_error, Toast.LENGTH_SHORT).show() return@launchWhenCreated
return@launchWhenCreated } catch (e: HttpException) {
} catch (e: HttpException) { Log.e(TAG(), "HttpException, unexpected response")
Log.e(TAG(), "HttpException, unexpected response") Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show()
Toast.makeText(context, R.string.server_error, Toast.LENGTH_SHORT).show() return@launchWhenCreated
return@launchWhenCreated } finally {
} finally { binding.playlistRefresh.isRefreshing = false
binding.playlistRefresh.isRefreshing = false }
} if (response.isNotEmpty()) {
if (response.isNotEmpty()) { binding.loginOrRegister.visibility = View.GONE
binding.loginOrRegister.visibility = View.GONE
val playlistsAdapter = PlaylistsAdapter( val playlistsAdapter = PlaylistsAdapter(
response.toMutableList(), response.toMutableList(),
childFragmentManager, childFragmentManager,
requireActivity() requireActivity()
) )
// listen for playlists to become deleted // listen for playlists to become deleted
playlistsAdapter.registerAdapterDataObserver(object : playlistsAdapter.registerAdapterDataObserver(object :
RecyclerView.AdapterDataObserver() { RecyclerView.AdapterDataObserver() {
override fun onChanged() { override fun onChanged() {
if (playlistsAdapter.itemCount == 0) { if (playlistsAdapter.itemCount == 0) {
binding.loginOrRegister.visibility = View.VISIBLE binding.loginOrRegister.visibility = View.VISIBLE
}
super.onChanged()
} }
}) super.onChanged()
}
})
binding.playlistRecView.adapter = playlistsAdapter binding.playlistRecView.adapter = playlistsAdapter
} else { } else {
runOnUiThread { runOnUiThread {
binding.loginOrRegister.visibility = View.VISIBLE binding.loginOrRegister.visibility = View.VISIBLE
}
} }
} }
} }
run()
} }
} }

View File

@ -1332,32 +1332,29 @@ class PlayerFragment : BaseFragment() {
} }
private fun isSubscribed() { private fun isSubscribed() {
fun run() { val channelId = streams.uploaderUrl!!.toID()
val channelId = streams.uploaderUrl!!.toID() lifecycleScope.launchWhenCreated {
lifecycleScope.launchWhenCreated { isSubscribed = SubscriptionHelper.isSubscribed(channelId)
isSubscribed = SubscriptionHelper.isSubscribed(channelId)
if (isSubscribed == null) return@launchWhenCreated if (isSubscribed == null) return@launchWhenCreated
runOnUiThread { runOnUiThread {
if (isSubscribed == true) {
binding.playerSubscribe.text = getString(R.string.unsubscribe)
}
binding.playerSubscribe.setOnClickListener {
if (isSubscribed == true) { if (isSubscribed == true) {
SubscriptionHelper.unsubscribe(channelId)
binding.playerSubscribe.text = getString(R.string.subscribe)
isSubscribed = false
} else {
SubscriptionHelper.subscribe(channelId)
binding.playerSubscribe.text = getString(R.string.unsubscribe) binding.playerSubscribe.text = getString(R.string.unsubscribe)
} isSubscribed = true
binding.playerSubscribe.setOnClickListener {
if (isSubscribed == true) {
SubscriptionHelper.unsubscribe(channelId)
binding.playerSubscribe.text = getString(R.string.subscribe)
isSubscribed = false
} else {
SubscriptionHelper.subscribe(channelId)
binding.playerSubscribe.text = getString(R.string.unsubscribe)
isSubscribed = true
}
} }
} }
} }
} }
run()
} }
private fun fetchComments() { private fun fetchComments() {

View File

@ -58,108 +58,105 @@ class PlaylistFragment : BaseFragment() {
} }
private fun fetchPlaylist() { private fun fetchPlaylist() {
fun run() { lifecycleScope.launchWhenCreated {
lifecycleScope.launchWhenCreated { val response = try {
val response = try { // load locally stored playlists with the auth api
// load locally stored playlists with the auth api if (isOwner) {
if (isOwner) { RetrofitInstance.authApi.getPlaylist(playlistId!!)
RetrofitInstance.authApi.getPlaylist(playlistId!!) } else {
} else { RetrofitInstance.api.getPlaylist(playlistId!!)
RetrofitInstance.api.getPlaylist(playlistId!!)
}
} catch (e: IOException) {
println(e)
Log.e(TAG(), "IOException, you might not have internet connection")
return@launchWhenCreated
} catch (e: HttpException) {
Log.e(TAG(), "HttpException, unexpected response")
return@launchWhenCreated
} }
nextPage = response.nextpage } catch (e: IOException) {
isLoading = false println(e)
runOnUiThread { Log.e(TAG(), "IOException, you might not have internet connection")
binding.playlistProgress.visibility = View.GONE return@launchWhenCreated
binding.playlistName.text = response.name } catch (e: HttpException) {
binding.uploader.text = response.uploader Log.e(TAG(), "HttpException, unexpected response")
binding.videoCount.text = return@launchWhenCreated
getString(R.string.videoCount, response.videos.toString()) }
nextPage = response.nextpage
isLoading = false
runOnUiThread {
binding.playlistProgress.visibility = View.GONE
binding.playlistName.text = response.name
binding.uploader.text = response.uploader
binding.videoCount.text =
getString(R.string.videoCount, response.videos.toString())
// show playlist options // show playlist options
binding.optionsMenu.setOnClickListener { binding.optionsMenu.setOnClickListener {
val optionsDialog = val optionsDialog =
PlaylistOptionsDialog(playlistId!!, isOwner) PlaylistOptionsDialog(playlistId!!, isOwner)
optionsDialog.show( optionsDialog.show(
childFragmentManager, childFragmentManager,
PlaylistOptionsDialog::class.java.name PlaylistOptionsDialog::class.java.name
)
}
playlistAdapter = PlaylistAdapter(
response.relatedStreams!!.toMutableList(),
playlistId!!,
isOwner,
requireActivity(),
childFragmentManager
) )
}
// listen for playlist items to become deleted playlistAdapter = PlaylistAdapter(
playlistAdapter!!.registerAdapterDataObserver(object : response.relatedStreams!!.toMutableList(),
RecyclerView.AdapterDataObserver() { playlistId!!,
override fun onChanged() { isOwner,
binding.videoCount.text = requireActivity(),
getString( childFragmentManager
R.string.videoCount, )
playlistAdapter!!.itemCount.toString()
)
}
})
binding.playlistRecView.adapter = playlistAdapter // listen for playlist items to become deleted
binding.playlistScrollview.viewTreeObserver playlistAdapter!!.registerAdapterDataObserver(object :
.addOnScrollChangedListener { RecyclerView.AdapterDataObserver() {
if (binding.playlistScrollview.getChildAt(0).bottom override fun onChanged() {
== (binding.playlistScrollview.height + binding.playlistScrollview.scrollY) binding.videoCount.text =
) { getString(
// scroll view is at bottom R.string.videoCount,
if (nextPage != null && !isLoading) { playlistAdapter!!.itemCount.toString()
isLoading = true )
fetchNextPage()
}
}
} }
})
/** binding.playlistRecView.adapter = playlistAdapter
* listener for swiping to the left or right binding.playlistScrollview.viewTreeObserver
*/ .addOnScrollChangedListener {
if (isOwner) { if (binding.playlistScrollview.getChildAt(0).bottom
val itemTouchCallback = object : ItemTouchHelper.SimpleCallback( == (binding.playlistScrollview.height + binding.playlistScrollview.scrollY)
0,
ItemTouchHelper.LEFT
) { ) {
override fun onMove( // scroll view is at bottom
recyclerView: RecyclerView, if (nextPage != null && !isLoading) {
viewHolder: RecyclerView.ViewHolder, isLoading = true
target: RecyclerView.ViewHolder fetchNextPage()
): Boolean {
return false
}
override fun onSwiped(
viewHolder: RecyclerView.ViewHolder,
direction: Int
) {
val position = viewHolder.absoluteAdapterPosition
playlistAdapter!!.removeFromPlaylist(position)
} }
} }
val itemTouchHelper = ItemTouchHelper(itemTouchCallback)
itemTouchHelper.attachToRecyclerView(binding.playlistRecView)
} }
/**
* listener for swiping to the left or right
*/
if (isOwner) {
val itemTouchCallback = object : ItemTouchHelper.SimpleCallback(
0,
ItemTouchHelper.LEFT
) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
return false
}
override fun onSwiped(
viewHolder: RecyclerView.ViewHolder,
direction: Int
) {
val position = viewHolder.absoluteAdapterPosition
playlistAdapter!!.removeFromPlaylist(position)
}
}
val itemTouchHelper = ItemTouchHelper(itemTouchCallback)
itemTouchHelper.attachToRecyclerView(binding.playlistRecView)
} }
} }
} }
run()
} }
private fun fetchNextPage() { private fun fetchNextPage() {

View File

@ -69,32 +69,29 @@ class SearchFragment : BaseFragment() {
} }
private fun fetchSuggestions(query: String) { private fun fetchSuggestions(query: String) {
fun run() { lifecycleScope.launchWhenCreated {
lifecycleScope.launchWhenCreated { val response = try {
val response = try { RetrofitInstance.api.getSuggestions(query)
RetrofitInstance.api.getSuggestions(query) } catch (e: IOException) {
} catch (e: IOException) { println(e)
println(e) Log.e(TAG(), "IOException, you might not have internet connection")
Log.e(TAG(), "IOException, you might not have internet connection") return@launchWhenCreated
return@launchWhenCreated } catch (e: HttpException) {
} catch (e: HttpException) { Log.e(TAG(), "HttpException, unexpected response")
Log.e(TAG(), "HttpException, unexpected response") return@launchWhenCreated
return@launchWhenCreated }
} // only load the suggestions if the input field didn't get cleared yet
// only load the suggestions if the input field didn't get cleared yet val suggestionsAdapter =
val suggestionsAdapter = SearchSuggestionsAdapter(
SearchSuggestionsAdapter( response,
response, (activity as MainActivity).searchView
(activity as MainActivity).searchView )
) runOnUiThread {
runOnUiThread { if (viewModel.searchQuery.value != "") {
if (viewModel.searchQuery.value != "") { binding.suggestionsRecycler.adapter = suggestionsAdapter
binding.suggestionsRecycler.adapter = suggestionsAdapter
}
} }
} }
} }
run()
} }
private fun showHistory() { private fun showHistory() {

View File

@ -6,5 +6,6 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties
data class PlaylistId( data class PlaylistId(
var playlistId: String? = null, var playlistId: String? = null,
var videoId: String? = null, var videoId: String? = null,
var newName: String? = null,
var index: Int = -1 var index: Int = -1
) )

View File

@ -316,4 +316,5 @@
<string name="audio_video_summary">Quality and format</string> <string name="audio_video_summary">Quality and format</string>
<string name="delete">Delete</string> <string name="delete">Delete</string>
<string name="trending_layout">Alternative trending layout</string> <string name="trending_layout">Alternative trending layout</string>
<string name="renamePlaylist">Rename playlist</string>
</resources> </resources>