From 1eb50adf5ef25bdb835cdd4116b862a53f8fb2f6 Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sat, 28 Jan 2023 18:02:13 +0100 Subject: [PATCH 1/7] Fix cloning playlists in the create playlist dialog --- .../com/github/libretube/ui/dialogs/CreatePlaylistDialog.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/github/libretube/ui/dialogs/CreatePlaylistDialog.kt b/app/src/main/java/com/github/libretube/ui/dialogs/CreatePlaylistDialog.kt index 9b8c98027..5fbce2408 100644 --- a/app/src/main/java/com/github/libretube/ui/dialogs/CreatePlaylistDialog.kt +++ b/app/src/main/java/com/github/libretube/ui/dialogs/CreatePlaylistDialog.kt @@ -1,6 +1,7 @@ package com.github.libretube.ui.dialogs import android.app.Dialog +import android.net.Uri import android.os.Bundle import android.widget.Toast import androidx.fragment.app.DialogFragment @@ -24,11 +25,12 @@ class CreatePlaylistDialog( binding.clonePlaylist.setOnClickListener { val playlistUrl = binding.playlistUrl.text.toString() - if (!TextUtils.validateUrl(playlistUrl)) { + val playlistId = Uri.parse(playlistUrl).getQueryParameter("list") + if (!TextUtils.validateUrl(playlistUrl) || playlistId == null) { Toast.makeText(context, R.string.invalid_url, Toast.LENGTH_SHORT).show() return@setOnClickListener } - PlaylistsHelper.clonePlaylist(requireContext().applicationContext, playlistUrl) + PlaylistsHelper.clonePlaylist(requireContext().applicationContext, playlistId) dismiss() } From 4b395e03727187d4458df5fc9700222d64c0c10f Mon Sep 17 00:00:00 2001 From: faisalcodes Date: Sat, 28 Jan 2023 23:42:51 +0530 Subject: [PATCH 2/7] Fixes #2878 : Using multi-level comments display. --- .../com/github/libretube/api/obj/Comment.kt | 2 +- .../github/libretube/constants/IntentData.kt | 1 + .../libretube/ui/adapters/CommentsAdapter.kt | 101 +++----------- .../ui/fragments/CommentsMainFragment.kt | 76 +++++++++++ .../ui/fragments/CommentsRepliesFragment.kt | 106 +++++++++++++++ .../libretube/ui/models/CommentsViewModel.kt | 1 + .../libretube/ui/sheets/CommentsSheet.kt | 128 +++++++++++------- app/src/main/res/layout/comments_row.xml | 38 ++---- app/src/main/res/layout/comments_sheet.xml | 71 ++++++---- app/src/main/res/layout/fragment_comments.xml | 29 ++++ app/src/main/res/values-night/colors.xml | 5 + app/src/main/res/values/colors.xml | 2 + app/src/main/res/values/strings.xml | 1 + 13 files changed, 374 insertions(+), 187 deletions(-) create mode 100644 app/src/main/java/com/github/libretube/ui/fragments/CommentsMainFragment.kt create mode 100644 app/src/main/java/com/github/libretube/ui/fragments/CommentsRepliesFragment.kt create mode 100644 app/src/main/res/layout/fragment_comments.xml create mode 100644 app/src/main/res/values-night/colors.xml diff --git a/app/src/main/java/com/github/libretube/api/obj/Comment.kt b/app/src/main/java/com/github/libretube/api/obj/Comment.kt index d21018e88..3b779b09f 100644 --- a/app/src/main/java/com/github/libretube/api/obj/Comment.kt +++ b/app/src/main/java/com/github/libretube/api/obj/Comment.kt @@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable data class Comment( val author: String, val commentId: String, - val commentText: String, + val commentText: String?, val commentedTime: String, val commentorUrl: String, val repliesPage: String? = null, diff --git a/app/src/main/java/com/github/libretube/constants/IntentData.kt b/app/src/main/java/com/github/libretube/constants/IntentData.kt index c10d30549..843d7c797 100644 --- a/app/src/main/java/com/github/libretube/constants/IntentData.kt +++ b/app/src/main/java/com/github/libretube/constants/IntentData.kt @@ -18,4 +18,5 @@ object IntentData { const val downloading = "downloading" const val openAudioPlayer = "openAudioPlayer" const val fragmentToOpen = "fragmentToOpen" + const val replyPage = "replyPage" } diff --git a/app/src/main/java/com/github/libretube/ui/adapters/CommentsAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/CommentsAdapter.kt index aa72c25f0..6c72d187a 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/CommentsAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/CommentsAdapter.kt @@ -1,42 +1,34 @@ package com.github.libretube.ui.adapters import android.annotation.SuppressLint -import android.util.Log +import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Button import android.widget.Toast import androidx.core.text.parseAsHtml +import androidx.fragment.app.Fragment import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.github.libretube.R -import com.github.libretube.api.RetrofitInstance import com.github.libretube.api.obj.Comment -import com.github.libretube.api.obj.CommentsPage +import com.github.libretube.constants.IntentData import com.github.libretube.databinding.CommentsRowBinding -import com.github.libretube.extensions.TAG import com.github.libretube.extensions.formatShort +import com.github.libretube.ui.fragments.CommentsRepliesFragment import com.github.libretube.ui.viewholders.CommentsViewHolder import com.github.libretube.util.ClipboardHelper import com.github.libretube.util.ImageHelper import com.github.libretube.util.NavigationHelper import com.github.libretube.util.TextUtils -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext class CommentsAdapter( + private val fragment: Fragment?, private val videoId: String, private val comments: MutableList, private val isRepliesAdapter: Boolean = false, - private val dismiss: () -> Unit + private val dismiss: () -> Unit, ) : RecyclerView.Adapter() { - - private var isLoading = false - private lateinit var repliesPage: CommentsPage - fun clear() { val size: Int = comments.size comments.clear() @@ -59,15 +51,8 @@ class CommentsAdapter( override fun onBindViewHolder(holder: CommentsViewHolder, position: Int) { val comment = comments[position] holder.binding.apply { - if (isRepliesAdapter) { - root.scaleX = REPLIES_ADAPTER_SCALE - root.scaleY = REPLIES_ADAPTER_SCALE - commentorImage.scaleX = REPLIES_ADAPTER_SCALE - commentorImage.scaleY = REPLIES_ADAPTER_SCALE - } - commentInfos.text = comment.author + TextUtils.SEPARATOR + comment.commentedTime - commentText.text = comment.commentText.parseAsHtml() + commentText.text = comment.commentText?.parseAsHtml() ImageHelper.loadImage(comment.thumbnail, commentorImage) likesTextView.text = comment.likeCount.formatShort() @@ -85,79 +70,31 @@ class CommentsAdapter( dismiss.invoke() } - repliesRecView.layoutManager = LinearLayoutManager(root.context) - val repliesAdapter = CommentsAdapter(videoId, mutableListOf(), true, dismiss) - repliesRecView.adapter = repliesAdapter if (!isRepliesAdapter && comment.repliesPage != null) { + val repliesFragment = CommentsRepliesFragment().apply { + arguments = Bundle().apply { + putString(IntentData.videoId, videoId) + putString(IntentData.replyPage, comment.repliesPage) + } + } root.setOnClickListener { - showMoreReplies(comment.repliesPage, showMore, repliesAdapter) + fragment!!.parentFragmentManager + .beginTransaction() + .replace(R.id.commentFragContainer, repliesFragment) + .addToBackStack(null) + .commit() } } root.setOnLongClickListener { - ClipboardHelper(root.context).save(comment.commentText) + ClipboardHelper(root.context).save(comment.commentText ?: "") Toast.makeText(root.context, R.string.copied, Toast.LENGTH_SHORT).show() true } } } - private fun showMoreReplies( - nextPage: String, - showMoreBtn: Button, - repliesAdapter: CommentsAdapter - ) { - when (repliesAdapter.itemCount) { - 0 -> { - fetchReplies(nextPage) { - repliesAdapter.updateItems(it.comments) - if (repliesPage.nextpage == null) { - showMoreBtn.visibility = View.GONE - return@fetchReplies - } - showMoreBtn.visibility = View.VISIBLE - showMoreBtn.setOnClickListener { view -> - if (repliesPage.nextpage == null) { - view.visibility = View.GONE - return@setOnClickListener - } - fetchReplies( - repliesPage.nextpage!! - ) { - repliesAdapter.updateItems(repliesPage.comments) - } - } - } - } - else -> { - repliesAdapter.clear() - showMoreBtn.visibility = View.GONE - } - } - } - override fun getItemCount(): Int { return comments.size } - - private fun fetchReplies(nextPage: String, onFinished: (CommentsPage) -> Unit) { - CoroutineScope(Dispatchers.IO).launch { - if (isLoading) return@launch - isLoading = true - repliesPage = try { - RetrofitInstance.api.getCommentsNextPage(videoId, nextPage) - } catch (e: Exception) { - Log.e(TAG(), "IOException, you might not have internet connection") - return@launch - } - withContext(Dispatchers.Main) { - onFinished.invoke(repliesPage) - } - isLoading = false - } - } - - companion object { - private const val REPLIES_ADAPTER_SCALE = 0.9f - } } diff --git a/app/src/main/java/com/github/libretube/ui/fragments/CommentsMainFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/CommentsMainFragment.kt new file mode 100644 index 000000000..bf8c5020d --- /dev/null +++ b/app/src/main/java/com/github/libretube/ui/fragments/CommentsMainFragment.kt @@ -0,0 +1,76 @@ +package com.github.libretube.ui.fragments + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.recyclerview.widget.LinearLayoutManager +import com.github.libretube.R +import com.github.libretube.databinding.FragmentCommentsBinding +import com.github.libretube.ui.adapters.CommentsAdapter +import com.github.libretube.ui.models.CommentsViewModel + +class CommentsMainFragment : Fragment() { + private lateinit var binding: FragmentCommentsBinding + private lateinit var commentsAdapter: CommentsAdapter + + private val viewModel: CommentsViewModel by activityViewModels() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentCommentsBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.commentsRV.layoutManager = LinearLayoutManager(requireContext()) + binding.commentsRV.setItemViewCacheSize(20) + + binding.commentsRV.viewTreeObserver + .addOnScrollChangedListener { + if (!binding.commentsRV.canScrollVertically(1)) { + viewModel.fetchNextComments() + } + } + + commentsAdapter = CommentsAdapter( + this, + viewModel.videoId!!, + viewModel.commentsPage.value?.comments.orEmpty().toMutableList() + ) { + viewModel.commentsSheetDismiss?.invoke() + } + binding.commentsRV.adapter = commentsAdapter + + if (viewModel.commentsPage.value?.comments.orEmpty().isEmpty()) { + binding.progress.visibility = View.VISIBLE + viewModel.fetchComments() + } + + // listen for new comments to be loaded + viewModel.commentsPage.observe(viewLifecycleOwner) { + it ?: return@observe + binding.progress.visibility = View.GONE + if (it.disabled == true) { + binding.errorTV.visibility = View.VISIBLE + return@observe + } + if (it.comments.isEmpty()) { + binding.errorTV.text = getString(R.string.no_comments_available) + binding.errorTV.visibility = View.VISIBLE + return@observe + } + commentsAdapter.updateItems( + // only add the new comments to the recycler view + it.comments.subList(commentsAdapter.itemCount, it.comments.size) + ) + } + } +} diff --git a/app/src/main/java/com/github/libretube/ui/fragments/CommentsRepliesFragment.kt b/app/src/main/java/com/github/libretube/ui/fragments/CommentsRepliesFragment.kt new file mode 100644 index 000000000..33f61757b --- /dev/null +++ b/app/src/main/java/com/github/libretube/ui/fragments/CommentsRepliesFragment.kt @@ -0,0 +1,106 @@ +package com.github.libretube.ui.fragments + +import android.os.Bundle +import android.util.Log +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.recyclerview.widget.LinearLayoutManager +import com.github.libretube.api.RetrofitInstance +import com.github.libretube.api.obj.CommentsPage +import com.github.libretube.constants.IntentData +import com.github.libretube.databinding.FragmentCommentsBinding +import com.github.libretube.extensions.TAG +import com.github.libretube.ui.adapters.CommentsAdapter +import com.github.libretube.ui.models.CommentsViewModel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class CommentsRepliesFragment : Fragment() { + private lateinit var binding: FragmentCommentsBinding + private lateinit var repliesPage: CommentsPage + private lateinit var repliesAdapter: CommentsAdapter + private val viewModel: CommentsViewModel by activityViewModels() + + private var isLoading = false + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + binding = FragmentCommentsBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + val videoId = arguments?.getString(IntentData.videoId) ?: "" + val nextPage = arguments?.getString(IntentData.replyPage) ?: "" + + repliesAdapter = CommentsAdapter(null, videoId, mutableListOf(), true) { + viewModel.commentsSheetDismiss?.invoke() + } + + binding.commentsRV.layoutManager = LinearLayoutManager(view.context) + binding.commentsRV.adapter = repliesAdapter + + binding.commentsRV.viewTreeObserver + .addOnScrollChangedListener { + if (!binding.commentsRV.canScrollVertically(1) && + ::repliesPage.isInitialized && + repliesPage.nextpage != null + ) { + fetchReplies(videoId, repliesPage.nextpage!!) { + repliesAdapter.updateItems(repliesPage.comments) + } + } + } + + loadInitialReplies(videoId, nextPage, repliesAdapter) + } + + private fun loadInitialReplies( + videoId: String, + nextPage: String, + repliesAdapter: CommentsAdapter + ) { + when (repliesAdapter.itemCount) { + 0 -> { + binding.progress.visibility = View.VISIBLE + fetchReplies(videoId, nextPage) { + repliesAdapter.updateItems(it.comments) + binding.progress.visibility = View.GONE + } + } + else -> { + repliesAdapter.clear() + } + } + } + + private fun fetchReplies( + videoId: String, + nextPage: String, + onFinished: (CommentsPage) -> Unit + ) { + CoroutineScope(Dispatchers.IO).launch { + if (isLoading) return@launch + isLoading = true + repliesPage = try { + RetrofitInstance.api.getCommentsNextPage(videoId, nextPage) + } catch (e: Exception) { + Log.e(TAG(), "IOException, you might not have internet connection") + return@launch + } + withContext(Dispatchers.Main) { + onFinished.invoke(repliesPage) + } + isLoading = false + } + } +} diff --git a/app/src/main/java/com/github/libretube/ui/models/CommentsViewModel.kt b/app/src/main/java/com/github/libretube/ui/models/CommentsViewModel.kt index 016b00ff0..4d142fc79 100644 --- a/app/src/main/java/com/github/libretube/ui/models/CommentsViewModel.kt +++ b/app/src/main/java/com/github/libretube/ui/models/CommentsViewModel.kt @@ -20,6 +20,7 @@ class CommentsViewModel : ViewModel() { var videoId: String? = null var maxHeight: Int = 0 + var commentsSheetDismiss: (() -> Unit)? = null fun fetchComments() { videoId ?: return diff --git a/app/src/main/java/com/github/libretube/ui/sheets/CommentsSheet.kt b/app/src/main/java/com/github/libretube/ui/sheets/CommentsSheet.kt index d6f35d7bb..f3f5f1d4e 100644 --- a/app/src/main/java/com/github/libretube/ui/sheets/CommentsSheet.kt +++ b/app/src/main/java/com/github/libretube/ui/sheets/CommentsSheet.kt @@ -1,25 +1,24 @@ package com.github.libretube.ui.sheets +import android.app.Dialog +import android.content.DialogInterface import android.os.Bundle +import android.view.KeyEvent import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.ViewTreeObserver -import androidx.core.view.updateLayoutParams +import android.view.WindowManager import androidx.fragment.app.activityViewModels -import androidx.recyclerview.widget.LinearLayoutManager import com.github.libretube.R import com.github.libretube.databinding.CommentsSheetBinding -import com.github.libretube.extensions.dpToPx -import com.github.libretube.ui.adapters.CommentsAdapter +import com.github.libretube.ui.fragments.CommentsMainFragment +import com.github.libretube.ui.fragments.CommentsRepliesFragment import com.github.libretube.ui.models.CommentsViewModel class CommentsSheet : ExpandedBottomSheet() { private lateinit var binding: CommentsSheetBinding - - private lateinit var commentsAdapter: CommentsAdapter - - private val viewModel: CommentsViewModel by activityViewModels() + private val commentsViewModel: CommentsViewModel by activityViewModels() override fun onCreateView( inflater: LayoutInflater, @@ -33,56 +32,83 @@ class CommentsSheet : ExpandedBottomSheet() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.dragHandle.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { - override fun onGlobalLayout() { - binding.dragHandle.viewTreeObserver.removeOnGlobalLayoutListener(this) - // limit the recyclerview height to not cover the video - binding.commentsRV.updateLayoutParams { - height = viewModel.maxHeight - (binding.dragHandle.height + 20.dpToPx().toInt()) + commentsViewModel.commentsSheetDismiss = this::dismiss + + binding.apply { + dragHandle.viewTreeObserver.addOnGlobalLayoutListener(object : + ViewTreeObserver.OnGlobalLayoutListener { + override fun onGlobalLayout() { + dragHandle.viewTreeObserver.removeOnGlobalLayoutListener(this) + + // limit the recyclerview height to not cover the video + binding.standardBottomSheet.layoutParams = + binding.commentFragContainer.layoutParams.apply { + height = commentsViewModel.maxHeight + } } - } - }) + }) - binding.commentsRV.layoutManager = LinearLayoutManager(requireContext()) - binding.commentsRV.setItemViewCacheSize(20) - - binding.commentsRV.viewTreeObserver - .addOnScrollChangedListener { - if (!binding.commentsRV.canScrollVertically(1)) { - viewModel.fetchNextComments() + btnBack.setOnClickListener { + if (childFragmentManager.backStackEntryCount > 0) { + childFragmentManager.popBackStack() } } - commentsAdapter = CommentsAdapter( - viewModel.videoId!!, - viewModel.commentsPage.value?.comments.orEmpty().toMutableList() - ) { - dialog?.dismiss() - } - binding.commentsRV.adapter = commentsAdapter - - if (viewModel.commentsPage.value?.comments.orEmpty().isEmpty()) { - binding.progress.visibility = View.VISIBLE - viewModel.fetchComments() + btnClose.setOnClickListener { dismiss() } } - // listen for new comments to be loaded - viewModel.commentsPage.observe(viewLifecycleOwner) { - it ?: return@observe - binding.progress.visibility = View.GONE - if (it.disabled == true) { - binding.errorTV.visibility = View.VISIBLE - return@observe - } - if (it.comments.isEmpty()) { - binding.errorTV.text = getString(R.string.no_comments_available) - binding.errorTV.visibility = View.VISIBLE - return@observe - } - commentsAdapter.updateItems( - // only add the new comments to the recycler view - it.comments.subList(commentsAdapter.itemCount, it.comments.size) - ) + childFragmentManager.apply { + addOnBackStackChangedListener(this@CommentsSheet::onFragmentChanged) + + beginTransaction() + .replace(R.id.commentFragContainer, CommentsMainFragment()) + .runOnCommit(this@CommentsSheet::onFragmentChanged) + .commit() } } + + private fun onFragmentChanged() { + childFragmentManager.findFragmentById(R.id.commentFragContainer)?.let { + when (it) { + is CommentsRepliesFragment -> { + binding.btnBack.visibility = View.VISIBLE + binding.commentsTitle.text = getString(R.string.replies) + } + else -> { + binding.btnBack.visibility = View.GONE + binding.commentsTitle.text = getString(R.string.comments) + } + } + } + } + + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + commentsViewModel.commentsSheetDismiss = null + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val dialog = super.onCreateDialog(savedInstanceState) + + dialog.apply { + setOnKeyListener { _, keyCode, _ -> + if (keyCode == KeyEvent.KEYCODE_BACK) { + if (childFragmentManager.backStackEntryCount > 0) { + childFragmentManager.popBackStack() + return@setOnKeyListener true + } + } + return@setOnKeyListener false + } + + window?.let { + it.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL) + it.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) + } + + setCanceledOnTouchOutside(false) + } + + return dialog + } } diff --git a/app/src/main/res/layout/comments_row.xml b/app/src/main/res/layout/comments_row.xml index b48377435..abad110c8 100644 --- a/app/src/main/res/layout/comments_row.xml +++ b/app/src/main/res/layout/comments_row.xml @@ -4,7 +4,7 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@drawable/rounded_ripple"> + android:background="?selectableItemBackground"> @@ -47,8 +48,8 @@ android:layout_height="wrap_content" android:ellipsize="end" android:maxLines="2" - android:textSize="15sp" - android:textStyle="bold" + android:textSize="14sp" + android:textColor="@color/text_color_secondary" tools:text="Author and Time" /> @@ -120,7 +123,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="6dp" - tools:text="LikeCount" /> + tools:text="ReplyCount" /> @@ -128,26 +131,5 @@ - - - - diff --git a/app/src/main/res/layout/comments_sheet.xml b/app/src/main/res/layout/comments_sheet.xml index 6beb68f0c..ecf9a0357 100644 --- a/app/src/main/res/layout/comments_sheet.xml +++ b/app/src/main/res/layout/comments_sheet.xml @@ -1,6 +1,7 @@ @@ -9,7 +10,6 @@ style="@style/Widget.Material3.BottomSheet" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingBottom="20dp" app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> + + + + + + + + + + + + - - - - - - - - + android:layout_height="0dp" + android:layout_weight="1" /> diff --git a/app/src/main/res/layout/fragment_comments.xml b/app/src/main/res/layout/fragment_comments.xml new file mode 100644 index 000000000..4b841a7f3 --- /dev/null +++ b/app/src/main/res/layout/fragment_comments.xml @@ -0,0 +1,29 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml new file mode 100644 index 000000000..f4247d820 --- /dev/null +++ b/app/src/main/res/values-night/colors.xml @@ -0,0 +1,5 @@ + + + #BFBFBF + #3A3A3A + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 4886b7498..e23e7aa9c 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -3,6 +3,8 @@ #AA000000 #EEFFFFFF #0061A6 + #505050 + #CCCCCC #0058CB #FFFFFF diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 78c142d15..53d5cef34 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -72,6 +72,7 @@ Connect to the Internet first. Retry Comments + Replies Choose search filter Channels All From c2da09ab777e5408ebce749fdd1a065d8976e6c7 Mon Sep 17 00:00:00 2001 From: faisalcodes Date: Sat, 28 Jan 2023 23:44:35 +0530 Subject: [PATCH 3/7] Run ktlint --- .../java/com/github/libretube/ui/adapters/CommentsAdapter.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/github/libretube/ui/adapters/CommentsAdapter.kt b/app/src/main/java/com/github/libretube/ui/adapters/CommentsAdapter.kt index 6c72d187a..72e9fa107 100644 --- a/app/src/main/java/com/github/libretube/ui/adapters/CommentsAdapter.kt +++ b/app/src/main/java/com/github/libretube/ui/adapters/CommentsAdapter.kt @@ -8,7 +8,6 @@ import android.view.ViewGroup import android.widget.Toast import androidx.core.text.parseAsHtml import androidx.fragment.app.Fragment -import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView import com.github.libretube.R import com.github.libretube.api.obj.Comment @@ -27,7 +26,7 @@ class CommentsAdapter( private val videoId: String, private val comments: MutableList, private val isRepliesAdapter: Boolean = false, - private val dismiss: () -> Unit, + private val dismiss: () -> Unit ) : RecyclerView.Adapter() { fun clear() { val size: Int = comments.size From cf5dee32c53ab3cc1f221a980a87ec73f299b250 Mon Sep 17 00:00:00 2001 From: Kazevic Date: Thu, 26 Jan 2023 20:13:37 +0000 Subject: [PATCH 4/7] Translated using Weblate (Portuguese (Brazil)) Currently translated at 100.0% (450 of 450 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/pt_BR/ --- app/src/main/res/values-pt-rBR/strings.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 9507a3a94..8536098cd 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -190,8 +190,8 @@ Notificações Notificações sobre novo conteúdo de criadores que você segue. Verificando a cada… - %1$s novas transmissões estão disponíveis - Novas transmissôes por %1$s … + %1$s novos vídeos estão disponíveis + Novos vídeos de %1$s… Tem certeza\? Isto não pode ser desfeito! Menos visualizações Nome do canal (A-Z) @@ -267,7 +267,7 @@ URL para a interface da instância Qualidade Comportamento - Buscar incremento + Incremento de avanço/retrocesso Pausa automática Pausar quando a tela é desligada. Reproduzir o próximo vídeo assim que o atual termina. @@ -307,7 +307,7 @@ Hora de tirar uma pausa Preencher Nenhum - Imagem em imagem (PIP) + Imagem em imagem (PiP) Minutos antes de ser lembrado Vídeos curtos Legendas não disponíveis @@ -315,7 +315,7 @@ Cópia de segurança Encaixar Atual - Exibe uma notificação quando novas transmissões estão disponíveis. + Exibe uma notificação quando novos vídeos estão disponíveis. Serviço de notificações Reproduzir a seguir Modo de segundo plano @@ -405,7 +405,7 @@ Este vídeo não tem comentários disponíveis. O autor não permite comentários. Tamanho das legendas - Dois toques para buscar + Dois toques para avançar/retrodeceder Você está atualizado Você viu todos os vídeos novos Toque duas vezes à esquerda ou à direita para retroceder ou avançar a posição do reprodutor. @@ -435,7 +435,7 @@ Avançar Pausar Controles PiP alternativos - Mostrar opções de apenas áudio e pular no PiP em vez de avançar e retroceder + Exibir opções de apenas áudio e pular no PiP em vez de avançar e retroceder Reprodutor de áudio Sem legendas Transferência pausada From 07ee6418e0183c7a795b2da489cb80e4f15caf12 Mon Sep 17 00:00:00 2001 From: RethinkDev Date: Sat, 28 Jan 2023 08:45:28 +0000 Subject: [PATCH 5/7] Translated using Weblate (Vietnamese) Currently translated at 89.7% (404 of 450 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/vi/ --- app/src/main/res/values-vi/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index f426dcd70..49a678b2e 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -401,4 +401,8 @@ Điều khiển vuốt Sử dụng thao tác vuốt để điều chỉnh độ sáng và âm lượng. Đánh dấu trang + Tạm dừng tải xuống + Tải xuống hoàn tất + Tải xuống đồng thời tối đa + Không có phụ đề \ No newline at end of file From 4d3c604f46ec9d371daa02b650fb0f7dd4d0d622 Mon Sep 17 00:00:00 2001 From: Ivon Huang Date: Fri, 27 Jan 2023 11:25:22 +0000 Subject: [PATCH 6/7] Translated using Weblate (Chinese (Traditional)) Currently translated at 100.0% (450 of 450 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/zh_Hant/ --- app/src/main/res/values-zh-rTW/strings.xml | 280 +++++++++++++++++++-- 1 file changed, 262 insertions(+), 18 deletions(-) diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 979b28da8..9fefb45da 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -24,8 +24,8 @@ 註冊完成。現在你可以開始訂閱頻道了。 已登入。請登出現有的帳號。 請登入並再試一次。 - 選擇實體 - 自訂實體 + 選擇實例… + 自訂實例 地區 登入/註冊 請先登入或到設定裡註冊。 @@ -55,7 +55,7 @@ 深色主題 %1$s個訂閱者 設定 - 實體 + 實例 自訂 網站 %1$s部影片 @@ -93,12 +93,12 @@ 授權 強調色 放鬆紅 - 像素藍 + 幸福藍 活力黃 時髦綠 愉快紫 - 黑色主題 - 神秘質感3 + 黑色 + Material You 通知 圖示 開啟 @@ -113,10 +113,10 @@ 儲存下載影音的位置。 貢獻 捐贈 - 按這裡檢查APP是否為最新版本。 + 按這裡檢查更新 現在是最新版本。 - 預設播放速度 - 播放器,下載,歷史 + 播放速度 + 下載和重設 直播 此留言無任何回覆。 作者 @@ -135,19 +135,19 @@ 飛馳烈焰 加速鳥兒 Piped,登入,訂閱 - 加入自訂實體 (風險自負) - 實體名稱 - 實體API網址 - 新增實體 + 加入實例 + 實例名稱 + 實例API網址 + 新增實例 請填寫名稱和API網址欄位。 - 清除自訂實體 + 清除自訂實例 請填入有效的網址 版本%1$s 認識LibretTube團隊,以及背後緣由。 - 相關串流 + 相關內容 在影片中顯示相關的串流。 顯示章節 - 緩衝 + 預先載入 訂閱 媒體庫 @@ -160,7 +160,7 @@ 關於 語言 註冊 - 伺服器出了點問題。換個實體試試? + 伺服器出了點問題。換個實例試試? 有其他下載正在進行,請等待所有下載完成… 系統 @@ -181,7 +181,7 @@ 是否重置所有設定並從實例登出? 刪除帳號 刪除您於piped實例中的帳號 - 播放器所使用的視頻格式 + 播放器所使用的影片格式 音頻 視訊 下載中… @@ -206,4 +206,248 @@ 無視訊 HLS 拷貝播放清單 + 開啟… + 已複製播放清單 + 確認取消訂閱 + 字幕語言 + 本機播放清單 + 多彩紫 + 新串流上線時顯示通知。 + 章節 + 選單選項尚未啟用! + 請先在另一個啟動頁籤選取! + 全部播放 + 音量 + 亮度 + 自動 + 滑動控制 + 使用滑動手勢調整亮度和音量。 + 在通知欄顯示附有按鈕的音訊播放器。 + 尚無歷史紀錄。 + 通知 + 新串流通知 + 您跟隨的創作者最新串流的通知。 + Wi-Fi + 彈出 + 這部影片沒有留言。 + 需要的連線 + 全部 + 暫停 + 後退 + 前進 + 沒有更多了 + 重複模式 + 填滿 + 放大 + 背景模式 + 加入佇列 + 跳過片段 + 手動跳過 + 不要自動跳過片段,總是事先提醒。 + 本機訂閱列表 + 偏好設定 + 播放佇列 + 佇列 + 時長 + 開始時間 + 結束時間 + 通知時長 + 通知顯示的時長。 + 下載完成 + 無法取得可用實例。 + 播放下一部 + 社群 + 需要重新啟動APP + 授權呼叫時使用不同的實例。 + 觀看次數 + 最大並行下載數 + 已達到最大並行下載數。 + 未知 + 繼續 + 自動暫停 + 肖像 + Discord + Matrix + Telegram + 請開啟Wifi或行動數據連上網路。 + 永不 + 播放速度 + 已選取 + 標籤可見度 + 總是 + 自動全螢幕 + 純粹主題 + 裝置旋轉後自動全螢幕。 + 找不到外部播放器。請確認已安裝外部播放器。 + 跳過縮圖和其他圖片。 + 數據節省模式 + 記住搜尋 + 於本機儲存影片觀看歷史 + 觀看和搜尋歷史 + 音訊品質 + 說明文字大小 + 排序 + 顯示按鈕,跳至上一部或下一部影片。 + 是時候休息一下了 + 最大圖片快取大小 + 裝置資訊 + 從下載刪除 + 新影片的指示器 + 自訂實例 + 預設 + 在背景載入訂閱列表 + 將HLS限制為1080p + 在背景載入訂閱列表,並防止自動重新載入。 + 載入的進度間隔 + 檔案名稱 + 最近更新 (反序) + 新增至播放清單 + 您確定要取消訂閱 %1$s 嗎? + 雜項 + 重新調整大小模式 + 幾分鐘前提醒 + 休息提醒 + 適應 + 複製到剪貼簿 + + 如果有新影片,顯示數量徽章。 + 從訂閱列表隱藏觀看過的影片 + 不要在訂閱列表頁籤顯示觀看進度90%以上的影片。 + 請至少選取一個項目 + 下載服務 + 在取消訂閱前顯示確認對話框。 + 直播 + 數值越低,影片初始載入可能就越慢。 + 檔案名稱無效! + 音高 + 播放清單順序 + 播放清單名稱 (反序) + 最近更新 + 純粹白/黑主題 + 記住播放位置 + 重設 + + 系統說明文字樣式 + 現在安裝新版本LibreTube嗎? + 在背景播放… + 下載APK… + 播放器的音訊格式 + 新增 %1$s 個串流 + 翻譯 + 最大歷史紀錄 + 無限 + 你已花費%1$s 在此APP上,是時候休息一下了。 + 短影片 + 目前的 + 備份 & 還原 + 備份 + 畫中畫 + 另外一種熱門影片版面 + 重新命名播放清單 + 行動數據 + 導航列 + 目前的區域似乎無法使用熱門影片。請在設定中選取其他地區。 + 舊版訂閱列表 + 預設值與行為 + 重啟APP以套用變更。 + 影片預覽 + 拖動播放指示器時顯示快照。 + 下載成功 + 分享時包含時間戳 + 使用手勢放大縮小。 + 預設 + 語言和地區 + 最差 + 說明文字 + 最舊 + 監測 + 說明文字 + 僅限Wifi + 檢查頻率… + 最多觀看 + 頻道名稱 (A-Z) + 最新 + 無字幕可用 + 頻道名稱 (Z-A) + %1$s 的新串流… + 您確定嗎?此操作無法撤銷! + 最少觀看 + 品質與格式 + 沒有選取任何項目! + 按二下快轉 + 匯入&匯出訂閱列表,播放清單… + 匯出播放清單 + 應用程式備份 + 已匯出。 + 隱私警告 + 使用不推薦的電子郵件繼續嗎? + 繼續 + 標記 + 在時間軸上標記片段。 + 全螢幕方向 + 影片比例 + 自動旋轉 + 風景 + Reddit + Twitter + 調整音高 + 播放最新影片 + 音訊曲目 + 預設 + 匯出訂閱列表 + 跳過按鈕 + 無結果。 + 錯誤 + 已複製 + 另一種影片版面 + 預設亮色 + 檔案格式不支援! + 開啟 + 一般 + 音訊播放器 + 播放清單網址 + 背景模式 + 在下載媒體檔案時顯示通知。 + 通知工作器 + 從通知開啟佇列 + 顯示更多 + 時間戳 (秒) + 熱門影片 + 精選影片 + 純音訊模式 + 將LibreTube變成音樂播放器。 + 無字幕 + 下載暫停 + 另一種熱門影片版面 + 排序 + 版面 + 另一種播放器版面 + 在留言上方顯示一排相關影片,而非留言下面。 + 使用HLS + 使用HLS而非DASH (較慢,不推薦) + 自動 + 現正熱門 + 上傳者停用了留言功能。 + 極簡單色 + 退出後暫停 + 插入相關影片 + 書籤 + 加入書籤 + 清除書籤 + 沒有書籤! + 隨機 + 新增至書籤 + 移除書籤 + 按螢幕左邊或右邊二下快轉影片。 + 限制執行時間 + 睡眠定時器 + 跳過無聲片段 + 幫助 + 問答 + 最佳 + 快轉幅度 + 匯入播放清單 + 另一種畫中畫控制模式 + 只顯示音訊,跳過畫中畫的前進後退控制 + 您已經看完了所有影片 \ No newline at end of file From 8283b439c9a0fd5a24327d6ceb13c2a13468db0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Veseli=20Kraji=C5=A1nik?= Date: Sat, 28 Jan 2023 08:38:02 +0000 Subject: [PATCH 7/7] Translated using Weblate (Serbian) Currently translated at 100.0% (450 of 450 strings) Translation: LibreTube/LibreTube Translate-URL: https://hosted.weblate.org/projects/libretube/libretube/sr/ --- app/src/main/res/values-sr/strings.xml | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 39329ad9b..480d40c4d 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -36,7 +36,7 @@ Морате да унесете корисничко име и лозинку. Видео резолуција Мрежне колоне - Нема ништа овде. + Нема ништа. Додај на листу Направи листу Библиотека @@ -88,7 +88,7 @@ Црвена Системска Обавештења - Иконица + Икона Укључено Искључено Пајпед @@ -127,7 +127,7 @@ Верзија %1$s Упознајте LibreTube тим и како све то функцијонише. Сличан садржај - Прикажите сличне садржаје испод оног што тренутно гледате. + Прикажите сличан садржај испод тренутног гледања. Прикажи поглавља Сакриј поглавља Предучитавање @@ -182,8 +182,8 @@ Чиста бело/црна тема Није пронађен екстерни плејер. Проверите да ли имате неки инсталиран. Режим уштеде података - Запамти претраге - Чувајте историју прегледа видеа локално + Памти претраге + Чувајте историју прегледа снимака локално Запамћене позиције репродукције Ресетуј Наслови @@ -267,7 +267,7 @@ Обавештења о новим стримовима Провера на сваких … %1$s нових стримова је доступно - Обавештења када буду доступни нови стримови из ваших претплата. + Обавештења када буду доступни нови стримови из ваших праћења. Нови стримови од %1$s… Да ли сте сигурни\? Ово не може бити опозвано! Потребна веза @@ -335,13 +335,13 @@ Пусти следеће Висина тона Аутоматски - Неколико минута пре подсећања + Минута пре подсећања Чини се да трендови нису доступни за тренутни регион. Молимо изаберите другу у подешавањима. Ограничи HLS на 1080p Назив фајла Непостојеће име фајла! - Редослед плејлиста - Назив плејлисте (обрнуто) + Редослед листи + Назив листе (обрнуто) Недавно ажуриран Недавно ажурирано (обрнуто) Преузми услугу @@ -380,7 +380,7 @@ Подразумевано светло Неподржан формат датотеке! Користи HLS - Користи HLS уместо DASH (биће спорије, не препоручује се) + Користи HLS уместо DASH (спорије, не препоручује се) Аутоматски Ограничење времена коришћења Отвори редослед из обавештења @@ -432,7 +432,7 @@ Премотај унапред Алтернативне PiP контроле Приказивање само звука и прескакање контрола у PiP-у уместо унапред и уназад - Режим само звука + Режим аудио плејера Претвори LibreTube у музички плејер. Максимално истовремених преузимања је достигнуто. Користите покрет штипања за увећавање/умањивање. @@ -446,4 +446,8 @@ Насумично Обриши обележивач Додај у обележиваче + Аутоматско искључење + Прескочи тишину + Помоћ + Често постављена питања \ No newline at end of file