mirror of
https://github.com/libre-tube/LibreTube.git
synced 2024-12-15 06:40:30 +05:30
refactor: use Bundle for DialogFragment arguments
This commit is contained in:
parent
ba2b918ebc
commit
995868b96c
@ -1,8 +1,12 @@
|
||||
package com.github.libretube.obj
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class ShareData(
|
||||
val currentChannel: String? = null,
|
||||
val currentVideo: String? = null,
|
||||
val currentPlaylist: String? = null,
|
||||
var currentPosition: Long? = null
|
||||
)
|
||||
) : Parcelable
|
||||
|
@ -24,13 +24,19 @@ import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* Dialog to insert new videos to a playlist
|
||||
* @param videoId The id of the video to add. If non is provided, insert the whole playing queue
|
||||
* videoId: The id of the video to add. If non is provided, insert the whole playing queue
|
||||
*/
|
||||
class AddToPlaylistDialog(
|
||||
private val videoId: String? = null
|
||||
) : DialogFragment() {
|
||||
class AddToPlaylistDialog : DialogFragment() {
|
||||
private var videoId: String? = null
|
||||
private val viewModel: PlaylistViewModel by activityViewModels()
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
arguments?.let {
|
||||
videoId = it.getString("videoId")!!
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val binding = DialogAddToPlaylistBinding.inflate(layoutInflater)
|
||||
|
||||
@ -93,7 +99,7 @@ class AddToPlaylistDialog(
|
||||
val streams = when {
|
||||
videoId != null -> listOfNotNull(
|
||||
runCatching {
|
||||
RetrofitInstance.api.getStreams(videoId!!).toStreamItem(videoId)
|
||||
RetrofitInstance.api.getStreams(videoId!!).toStreamItem(videoId!!)
|
||||
}.getOrNull()
|
||||
)
|
||||
|
||||
|
@ -32,10 +32,17 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import retrofit2.HttpException
|
||||
|
||||
class DownloadDialog(
|
||||
private val videoId: String
|
||||
) : DialogFragment() {
|
||||
class DownloadDialog : DialogFragment() {
|
||||
private lateinit var videoId: String
|
||||
private var onDownloadConfirm = {}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
arguments?.let {
|
||||
videoId = it.getString("videoId")!!
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val binding = DialogDownloadBinding.inflate(layoutInflater)
|
||||
|
||||
|
@ -6,7 +6,9 @@ import android.os.Bundle
|
||||
import android.text.InputType
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.api.PlaylistsHelper
|
||||
@ -18,11 +20,18 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class PlaylistDescriptionDialog(
|
||||
private val playlistId: String,
|
||||
private val currentPlaylistDescription: String,
|
||||
private val onSuccess: (String) -> Unit
|
||||
) : DialogFragment() {
|
||||
class PlaylistDescriptionDialog : DialogFragment() {
|
||||
private lateinit var playlistId: String
|
||||
private lateinit var currentPlaylistDescription: String
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
arguments?.let {
|
||||
playlistId = it.getString("playlistId")!!
|
||||
currentPlaylistDescription = it.getString("currentPlaylistDescription")!!
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val binding = DialogTextPreferenceBinding.inflate(layoutInflater)
|
||||
binding.input.inputType = InputType.TYPE_CLASS_TEXT
|
||||
@ -68,7 +77,7 @@ class PlaylistDescriptionDialog(
|
||||
}
|
||||
if (success) {
|
||||
appContext.toastFromMainDispatcher(R.string.success)
|
||||
onSuccess.invoke(newDescription)
|
||||
setFragmentResult("requestKey", bundleOf("bundleKey" to newDescription))
|
||||
} else {
|
||||
appContext.toastFromMainDispatcher(R.string.server_error)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package com.github.libretube.ui.dialogs
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.DialogFragment
|
||||
@ -18,11 +19,26 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
class ShareDialog(
|
||||
private val id: String,
|
||||
private val shareObjectType: ShareObjectType,
|
||||
private val shareData: ShareData
|
||||
) : DialogFragment() {
|
||||
class ShareDialog : DialogFragment() {
|
||||
private lateinit var id: String
|
||||
private lateinit var shareObjectType: ShareObjectType
|
||||
private lateinit var shareData: ShareData
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
arguments?.let {
|
||||
id = it.getString("id")!!
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
shareObjectType =
|
||||
it.getSerializable("shareObjectType", ShareObjectType::class.java)!!
|
||||
shareData = it.getParcelable("shareData", ShareData::class.java)!!
|
||||
} else {
|
||||
shareObjectType = it.getSerializable("shareObjectType") as ShareObjectType
|
||||
shareData = it.getParcelable("shareData")!!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
var shareOptions = arrayOf(
|
||||
getString(R.string.piped),
|
||||
|
@ -20,11 +20,20 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class SubmitSegmentDialog(
|
||||
private val videoId: String,
|
||||
private val currentPosition: Long,
|
||||
private val duration: Long?
|
||||
) : DialogFragment() {
|
||||
class SubmitSegmentDialog : DialogFragment() {
|
||||
private var videoId: String = ""
|
||||
private var currentPosition: Long = 0
|
||||
private var duration: Long? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
arguments?.let {
|
||||
videoId = it.getString("videoId")!!
|
||||
currentPosition = it.getLong("currentPosition")
|
||||
duration = it.getLong("duration")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val binding = DialogSubmitSegmentBinding.inflate(layoutInflater)
|
||||
|
||||
@ -67,7 +76,7 @@ class SubmitSegmentDialog(
|
||||
|
||||
if (duration != null) {
|
||||
// the end time can't be greater than the video duration
|
||||
endTime = minOf(endTime, duration.toFloat())
|
||||
endTime = minOf(endTime, duration!!.toFloat())
|
||||
}
|
||||
|
||||
val categories = resources.getStringArray(R.array.sponsorBlockSegments)
|
||||
|
@ -8,10 +8,18 @@ import androidx.fragment.app.DialogFragment
|
||||
import com.github.libretube.R
|
||||
import com.github.libretube.obj.update.UpdateInfo
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class UpdateAvailableDialog(
|
||||
private val updateInfo: UpdateInfo
|
||||
) : DialogFragment() {
|
||||
class UpdateAvailableDialog : DialogFragment() {
|
||||
private lateinit var updateInfo: UpdateInfo
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
arguments?.let {
|
||||
val encodedString = it.getString("updateInfo")!!
|
||||
updateInfo = Json.decodeFromString(encodedString)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return MaterialAlertDialogBuilder(requireContext())
|
||||
|
@ -168,17 +168,26 @@ class AudioPlayerFragment : Fragment(), AudioPlayerOptions {
|
||||
|
||||
binding.download.setOnClickListener {
|
||||
val videoId = PlayingQueue.getCurrent()?.url?.toID() ?: return@setOnClickListener
|
||||
val downloadDialog = DownloadDialog(videoId)
|
||||
downloadDialog.show(childFragmentManager, DownloadDialog::class.java.name)
|
||||
|
||||
val bundle = Bundle().apply {
|
||||
putString("videoId", videoId)
|
||||
}
|
||||
val newFragment = DownloadDialog()
|
||||
newFragment.arguments = bundle
|
||||
newFragment.show(childFragmentManager, DownloadDialog::class.java.name)
|
||||
}
|
||||
|
||||
binding.share.setOnClickListener {
|
||||
val currentVideo = PlayingQueue.getCurrent() ?: return@setOnClickListener
|
||||
ShareDialog(
|
||||
id = currentVideo.url!!.toID(),
|
||||
shareObjectType = ShareObjectType.VIDEO,
|
||||
shareData = ShareData(currentVideo = currentVideo.title)
|
||||
).show(childFragmentManager, null)
|
||||
|
||||
val bundle = Bundle().apply {
|
||||
putString("id", currentVideo.url!!.toID())
|
||||
putSerializable("shareObjectType", ShareObjectType.VIDEO)
|
||||
putParcelable("shareData", ShareData(currentVideo = currentVideo.title))
|
||||
}
|
||||
val newShareDialog = ShareDialog()
|
||||
newShareDialog.arguments = bundle
|
||||
newShareDialog.show(childFragmentManager, null)
|
||||
}
|
||||
|
||||
binding.chapters.setOnClickListener {
|
||||
|
@ -154,12 +154,14 @@ class ChannelFragment : Fragment() {
|
||||
)
|
||||
|
||||
binding.channelShare.setOnClickListener {
|
||||
val shareDialog = ShareDialog(
|
||||
channelId.toID(),
|
||||
ShareObjectType.CHANNEL,
|
||||
shareData
|
||||
)
|
||||
shareDialog.show(childFragmentManager, ShareDialog::class.java.name)
|
||||
val bundle = Bundle().apply {
|
||||
putString("id", channelId.toID())
|
||||
putSerializable("shareObjectType", ShareObjectType.CHANNEL)
|
||||
putParcelable("shareData", shareData)
|
||||
}
|
||||
val newShareDialog = ShareDialog()
|
||||
newShareDialog.arguments = bundle
|
||||
newShareDialog.show(childFragmentManager, ShareDialog::class.java.name)
|
||||
}
|
||||
|
||||
nextPage = response.nextpage
|
||||
|
@ -444,16 +444,20 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
// share button
|
||||
binding.relPlayerShare.setOnClickListener {
|
||||
if (!this::streams.isInitialized) return@setOnClickListener
|
||||
val shareDialog =
|
||||
ShareDialog(
|
||||
videoId,
|
||||
ShareObjectType.VIDEO,
|
||||
val bundle = Bundle().apply {
|
||||
putString("id", videoId)
|
||||
putSerializable("shareObjectType", ShareObjectType.VIDEO)
|
||||
putParcelable(
|
||||
"shareData",
|
||||
ShareData(
|
||||
currentVideo = streams.title,
|
||||
currentPosition = exoPlayer.currentPosition / 1000
|
||||
)
|
||||
)
|
||||
shareDialog.show(childFragmentManager, ShareDialog::class.java.name)
|
||||
}
|
||||
val newShareDialog = ShareDialog()
|
||||
newShareDialog.arguments = bundle
|
||||
newShareDialog.show(childFragmentManager, ShareDialog::class.java.name)
|
||||
}
|
||||
|
||||
binding.relPlayerShare.setOnLongClickListener {
|
||||
@ -774,7 +778,8 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
// enable the chapters dialog in the player
|
||||
playerBinding.chapterLL.setOnClickListener {
|
||||
updateMaxSheetHeight()
|
||||
val sheet = chaptersBottomSheet ?: ChaptersBottomSheet(chapters, exoPlayer).also {
|
||||
val sheet =
|
||||
chaptersBottomSheet ?: ChaptersBottomSheet(chapters, exoPlayer).also {
|
||||
chaptersBottomSheet = it
|
||||
}
|
||||
if (sheet.isVisible) {
|
||||
@ -997,7 +1002,11 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
if (streams.duration <= 0) {
|
||||
Toast.makeText(context, R.string.cannotDownload, Toast.LENGTH_SHORT).show()
|
||||
} else if (!DownloadService.IS_DOWNLOAD_RUNNING) {
|
||||
val newFragment = DownloadDialog(videoId)
|
||||
val bundle = Bundle().apply {
|
||||
putString("videoId", videoId)
|
||||
}
|
||||
val newFragment = DownloadDialog()
|
||||
newFragment.arguments = bundle
|
||||
newFragment.show(childFragmentManager, DownloadDialog::class.java.name)
|
||||
} else {
|
||||
Toast.makeText(context, R.string.dlisinprogress, Toast.LENGTH_SHORT)
|
||||
@ -1048,10 +1057,12 @@ class PlayerFragment : Fragment(), OnlinePlayerOptions {
|
||||
)
|
||||
|
||||
binding.relPlayerSave.setOnClickListener {
|
||||
AddToPlaylistDialog(videoId).show(
|
||||
childFragmentManager,
|
||||
AddToPlaylistDialog::class.java.name
|
||||
)
|
||||
val bundle = Bundle().apply {
|
||||
putString("videoId", videoId)
|
||||
}
|
||||
val newAddToPlaylistDialog = AddToPlaylistDialog()
|
||||
newAddToPlaylistDialog.arguments = bundle
|
||||
newAddToPlaylistDialog.show(childFragmentManager, AddToPlaylistDialog::class.java.name)
|
||||
}
|
||||
|
||||
syncQueueButtons()
|
||||
|
@ -14,6 +14,8 @@ import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
class MainSettings : BasePreferenceFragment() {
|
||||
override val titleResourceId: Int = R.string.settings
|
||||
@ -46,7 +48,13 @@ class MainSettings : BasePreferenceFragment() {
|
||||
|
||||
if (BuildConfig.VERSION_NAME != updateInfo.name) {
|
||||
// show the UpdateAvailableDialog if there's an update available
|
||||
UpdateAvailableDialog(updateInfo).show(
|
||||
val encodedUpdateInfo = Json.encodeToString(updateInfo)
|
||||
val bundle = Bundle().apply {
|
||||
putString("updateInfo", encodedUpdateInfo)
|
||||
}
|
||||
val newUpdateAvailableDialog = UpdateAvailableDialog()
|
||||
newUpdateAvailableDialog.arguments = bundle
|
||||
newUpdateAvailableDialog.show(
|
||||
childFragmentManager,
|
||||
UpdateAvailableDialog::class.java.name
|
||||
)
|
||||
|
@ -37,8 +37,14 @@ class ChannelOptionsBottomSheet(
|
||||
setSimpleItems(optionsList) { which ->
|
||||
when (optionsList[which]) {
|
||||
getString(R.string.share) -> {
|
||||
ShareDialog(channelId, ShareObjectType.CHANNEL, shareData)
|
||||
.show(parentFragmentManager, null)
|
||||
val bundle = Bundle().apply {
|
||||
putString("id", channelId)
|
||||
putSerializable("shareObjectType", ShareObjectType.CHANNEL)
|
||||
putParcelable("shareData", shareData)
|
||||
}
|
||||
val newShareDialog = ShareDialog()
|
||||
newShareDialog.arguments = bundle
|
||||
newShareDialog.show(parentFragmentManager, null)
|
||||
}
|
||||
|
||||
getString(R.string.play_latest_videos) -> {
|
||||
|
@ -38,8 +38,14 @@ class DownloadOptionsBottomSheet(
|
||||
|
||||
2 -> {
|
||||
val shareData = ShareData(currentVideo = download.uploader)
|
||||
ShareDialog(download.videoId, ShareObjectType.VIDEO, shareData)
|
||||
.show(parentFragmentManager, null)
|
||||
val bundle = Bundle().apply {
|
||||
putString("id", download.videoId)
|
||||
putSerializable("shareObjectType", ShareObjectType.CHANNEL)
|
||||
putParcelable("shareData", shareData)
|
||||
}
|
||||
val newShareDialog = ShareDialog()
|
||||
newShareDialog.arguments = bundle
|
||||
newShareDialog.show(parentFragmentManager, null)
|
||||
}
|
||||
|
||||
3 -> {
|
||||
|
@ -70,6 +70,7 @@ class PlaylistOptionsBottomSheet(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
getString(R.string.add_to_queue) -> {
|
||||
PlayingQueue.insertPlaylist(playlistId, null)
|
||||
}
|
||||
@ -87,9 +88,15 @@ class PlaylistOptionsBottomSheet(
|
||||
}
|
||||
// share the playlist
|
||||
getString(R.string.share) -> {
|
||||
val shareDialog = ShareDialog(playlistId, ShareObjectType.PLAYLIST, shareData)
|
||||
val bundle = Bundle().apply {
|
||||
putString("id", playlistId)
|
||||
putSerializable("shareObjectType", ShareObjectType.PLAYLIST)
|
||||
putParcelable("shareData", shareData)
|
||||
}
|
||||
val newShareDialog = ShareDialog()
|
||||
newShareDialog.arguments = bundle
|
||||
// using parentFragmentManager, childFragmentManager doesn't work here
|
||||
shareDialog.show(parentFragmentManager, ShareDialog::class.java.name)
|
||||
newShareDialog.show(parentFragmentManager, ShareDialog::class.java.name)
|
||||
}
|
||||
|
||||
getString(R.string.deletePlaylist) -> {
|
||||
@ -105,8 +112,20 @@ class PlaylistOptionsBottomSheet(
|
||||
}
|
||||
|
||||
getString(R.string.change_playlist_description) -> {
|
||||
PlaylistDescriptionDialog(playlistId, "", onChangeDescription)
|
||||
.show(parentFragmentManager, null)
|
||||
val bundle = Bundle().apply {
|
||||
putString("playlistId", playlistId)
|
||||
putString("currentPlaylistDescription", "")
|
||||
}
|
||||
val newShareDialog = PlaylistDescriptionDialog()
|
||||
newShareDialog.arguments = bundle
|
||||
newShareDialog.show(parentFragmentManager, null)
|
||||
parentFragmentManager.setFragmentResultListener(
|
||||
"requestKey",
|
||||
this
|
||||
) { _, resultBundle ->
|
||||
val newDescription = resultBundle.getString("bundleKey")!!
|
||||
onChangeDescription.invoke(newDescription)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
|
@ -81,21 +81,36 @@ class VideoOptionsBottomSheet(
|
||||
}
|
||||
// Add Video to Playlist Dialog
|
||||
getString(R.string.addToPlaylist) -> {
|
||||
AddToPlaylistDialog(videoId).show(
|
||||
val bundle = Bundle().apply {
|
||||
putString("videoId", videoId)
|
||||
}
|
||||
val newAddToPlaylistDialog = AddToPlaylistDialog()
|
||||
newAddToPlaylistDialog.arguments = bundle
|
||||
newAddToPlaylistDialog.show(
|
||||
parentFragmentManager,
|
||||
AddToPlaylistDialog::class.java.name
|
||||
)
|
||||
}
|
||||
|
||||
getString(R.string.download) -> {
|
||||
val downloadDialog = DownloadDialog(videoId)
|
||||
downloadDialog.show(parentFragmentManager, DownloadDialog::class.java.name)
|
||||
val bundle = Bundle().apply {
|
||||
putString("videoId", videoId)
|
||||
}
|
||||
val newFragment = DownloadDialog()
|
||||
newFragment.arguments = bundle
|
||||
newFragment.show(parentFragmentManager, DownloadDialog::class.java.name)
|
||||
}
|
||||
|
||||
getString(R.string.share) -> {
|
||||
val shareDialog = ShareDialog(videoId, ShareObjectType.VIDEO, shareData)
|
||||
val bundle = Bundle().apply {
|
||||
putString("id", videoId)
|
||||
putSerializable("shareObjectType", ShareObjectType.VIDEO)
|
||||
putParcelable("shareData", shareData)
|
||||
}
|
||||
val newShareDialog = ShareDialog()
|
||||
newShareDialog.arguments = bundle
|
||||
// using parentFragmentManager is important here
|
||||
shareDialog.show(parentFragmentManager, ShareDialog::class.java.name)
|
||||
newShareDialog.show(parentFragmentManager, ShareDialog::class.java.name)
|
||||
}
|
||||
|
||||
getString(R.string.play_next) -> {
|
||||
|
@ -2,6 +2,7 @@ package com.github.libretube.ui.views
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.os.Bundle
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
@ -166,11 +167,18 @@ class OnlinePlayerView(
|
||||
|
||||
binding.sbSubmit.isVisible = PlayerHelper.sponsorBlockEnabled
|
||||
binding.sbSubmit.setOnClickListener {
|
||||
val currentPosition = player?.currentPosition?.takeIf { it != C.TIME_UNSET }
|
||||
val currentPosition = player?.currentPosition?.takeIf { it != C.TIME_UNSET } ?: 0
|
||||
val duration = player?.duration?.takeIf { it != C.TIME_UNSET }
|
||||
val videoId = PlayingQueue.getCurrent()?.url?.toID() ?: return@setOnClickListener
|
||||
SubmitSegmentDialog(videoId, currentPosition ?: 0, duration)
|
||||
.show((context as BaseActivity).supportFragmentManager, null)
|
||||
|
||||
val bundle = Bundle().apply {
|
||||
putLong("currentPosition", currentPosition)
|
||||
putLong("duration", duration!!)
|
||||
putString("videoId", videoId)
|
||||
}
|
||||
val newSubmitSegmentDialog = SubmitSegmentDialog()
|
||||
newSubmitSegmentDialog.arguments = bundle
|
||||
newSubmitSegmentDialog.show((context as BaseActivity).supportFragmentManager, null)
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user