Merge pull request #88 from recloudstream/voting

This commit is contained in:
Cloudburst 2022-09-06 21:41:09 +02:00 committed by GitHub
commit 39dce7935c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 649 additions and 26 deletions

View file

@ -0,0 +1,84 @@
package com.lagradost.cloudstream3.plugins
import android.util.Log
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
import java.security.MessageDigest
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
object VotingApi { // please do not cheat the votes lol
private const val LOGKEY = "VotingApi"
enum class VoteType(val value: Int) {
UPVOTE(1),
DOWNVOTE(-1),
NONE(0)
}
private val apiDomain = "https://api.countapi.xyz"
private fun transformUrl(url: String): String = // dont touch or all votes get reset
MessageDigest
.getInstance("SHA-256")
.digest("${url}#funny-salt".toByteArray())
.fold("") { str, it -> str + "%02x".format(it) }
suspend fun SitePlugin.getVotes(): Int {
return getVotes(url)
}
suspend fun SitePlugin.vote(requestType: VoteType): Int {
return vote(url, requestType)
}
fun SitePlugin.getVoteType(): VoteType {
if (repositoryUrl == null) return VoteType.NONE
return getVoteType(url)
}
suspend fun getVotes(pluginUrl: String): Int {
val url = "${apiDomain}/get/cs3-votes/${transformUrl(pluginUrl)}"
Log.d(LOGKEY, "Requesting: $url")
return app.get(url).parsedSafe<Result>()?.value ?: (0.also {
ioSafe {
createBucket(pluginUrl)
}
})
}
fun getVoteType(pluginUrl: String): VoteType {
return getKey("cs3-votes/${transformUrl(pluginUrl)}") ?: VoteType.NONE
}
private suspend fun createBucket(pluginUrl: String) {
val url = "${apiDomain}/create?namespace=cs3-votes&key=${transformUrl(pluginUrl)}&value=0&update_lowerbound=-2&update_upperbound=2&enable_reset=0"
Log.d(LOGKEY, "Requesting: $url")
app.get(url)
}
suspend fun vote(pluginUrl: String, requestType: VoteType): Int {
val savedType: VoteType = getKey("cs3-votes/${transformUrl(pluginUrl)}") ?: VoteType.NONE
var newType: VoteType = requestType
var changeValue = 0
if (requestType == savedType) {
newType = VoteType.NONE
changeValue = -requestType.value
} else if (savedType == VoteType.NONE) {
changeValue = requestType.value
} else if (savedType != requestType) {
changeValue = -savedType.value + requestType.value
}
val url = "${apiDomain}/update/cs3-votes/${transformUrl(pluginUrl)}?amount=${changeValue}"
Log.d(LOGKEY, "Requesting: $url")
val res = app.get(url).parsedSafe<Result>()?.value
if (res != null) {
setKey("cs3-votes/${transformUrl(pluginUrl)}", newType)
}
return res ?: 0
}
private data class Result(
val value: Int?
)
}

View file

@ -4,10 +4,8 @@ import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.LayoutRes
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.widget.ContentLoadingProgressBar

View file

@ -5,24 +5,31 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.AcraApplication.Companion.getActivity
import com.lagradost.cloudstream3.PROVIDER_STATUS_DOWN
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.plugins.PluginManager
import com.lagradost.cloudstream3.plugins.VotingApi.getVotes
import com.lagradost.cloudstream3.ui.result.setText
import com.lagradost.cloudstream3.ui.result.txt
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.isTrueTvSettings
import com.lagradost.cloudstream3.utils.AppUtils.html
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.GlideApp
import com.lagradost.cloudstream3.utils.SubtitleHelper.fromTwoLettersToLanguage
import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso
import com.lagradost.cloudstream3.utils.UIHelper.setImage
import com.lagradost.cloudstream3.utils.UIHelper.toPx
import kotlinx.android.synthetic.main.repository_item.view.*
import org.junit.Assert
import org.junit.Test
import java.text.DecimalFormat
data class PluginViewData(
@ -101,6 +108,23 @@ class PluginAdapter(
private val iconSize by lazy {
findClosestBase2(iconSizeExact, 16, 512)
}
fun prettyCount(number: Number): String? {
val suffix = charArrayOf(' ', 'k', 'M', 'B', 'T', 'P', 'E')
val numValue = number.toLong()
val value = Math.floor(Math.log10(numValue.toDouble())).toInt()
val base = value / 3
return if (value >= 3 && base < suffix.size) {
DecimalFormat("#0.00").format(
numValue / Math.pow(
10.0,
(base * 3).toDouble()
)
) + suffix[base]
} else {
DecimalFormat().format(numValue)
}
}
}
inner class PluginViewHolder(itemView: View) :
@ -112,6 +136,7 @@ class PluginAdapter(
val metadata = data.plugin.second
val disabled = metadata.status == PROVIDER_STATUS_DOWN
val alpha = if (disabled) 0.6f else 1f
val isLocal = !data.plugin.second.url.startsWith("http")
itemView.main_text?.alpha = alpha
itemView.sub_text?.alpha = alpha
@ -125,6 +150,13 @@ class PluginAdapter(
itemView.action_button?.setOnClickListener {
iconClickCallback.invoke(data.plugin)
}
itemView.setOnClickListener {
if (isLocal) return@setOnClickListener
val sheet = PluginDetailsFragment(data)
val activity = itemView.context.getActivity() as AppCompatActivity
sheet.show(activity.supportFragmentManager, "PluginDetails")
}
//if (itemView.context?.isTrueTvSettings() == false) {
// val siteUrl = metadata.repositoryUrl
// if (siteUrl != null && siteUrl.isNotBlank() && siteUrl != "NONE") {
@ -181,8 +213,19 @@ class PluginAdapter(
itemView.lang_icon?.isVisible = false
} else {
itemView.lang_icon?.isVisible = true
//itemView.lang_icon.text = getFlagFromIso(metadata.language)
itemView.lang_icon.text = fromTwoLettersToLanguage(metadata.language)
itemView.lang_icon.text = "${getFlagFromIso(metadata.language)} ${fromTwoLettersToLanguage(metadata.language)}"
}
if (isLocal) {
itemView.ext_votes?.isVisible = false
} else {
itemView.ext_votes?.isVisible = false
ioSafe {
metadata.getVotes().main {
itemView.ext_votes?.setText(txt(R.string.extension_rating, prettyCount(it)))
itemView.ext_votes?.isVisible = true
}
}
}

View file

@ -0,0 +1,127 @@
package com.lagradost.cloudstream3.ui.settings.extensions
import android.content.res.ColorStateList
import android.os.Bundle
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.utils.UIHelper.setImage
import com.lagradost.cloudstream3.utils.UIHelper.toPx
import kotlinx.android.synthetic.main.fragment_plugin_details.*
import android.text.format.Formatter.formatFileSize
import com.lagradost.cloudstream3.plugins.VotingApi
import com.lagradost.cloudstream3.plugins.VotingApi.getVoteType
import com.lagradost.cloudstream3.plugins.VotingApi.getVotes
import com.lagradost.cloudstream3.plugins.VotingApi.vote
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
import com.lagradost.cloudstream3.utils.Coroutines.main
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
import com.lagradost.cloudstream3.AcraApplication.Companion.openBrowser
import com.lagradost.cloudstream3.utils.SubtitleHelper
import com.lagradost.cloudstream3.utils.SubtitleHelper.fromTwoLettersToLanguage
import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso
class PluginDetailsFragment(val data: PluginViewData) : BottomSheetDialogFragment() {
companion object {
private tailrec fun findClosestBase2(target: Int, current: Int = 16, max: Int = 512): Int {
if (current >= max) return max
if (current >= target) return current
return findClosestBase2(target, current * 2, max)
}
private val iconSizeExact = 50.toPx
private val iconSize by lazy {
findClosestBase2(iconSizeExact, 16, 512)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_plugin_details, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val metadata = data.plugin.second
if (plugin_icon?.setImage(//plugin_icon?.height ?:
metadata.iconUrl?.replace(
"%size%",
"$iconSize"
)?.replace(
"%exact_size%",
"$iconSizeExact"
),
null,
errorImageDrawable = R.drawable.ic_baseline_extension_24
) != true
) {
plugin_icon?.setImageResource(R.drawable.ic_baseline_extension_24)
}
plugin_name?.text = metadata.name
plugin_version?.text = metadata.version.toString()
plugin_description?.text = metadata.description ?: getString(R.string.no_data)
plugin_size?.text = if (metadata.fileSize == null) getString(R.string.no_data) else formatFileSize(context, metadata.fileSize)
plugin_author?.text = if (metadata.authors.isEmpty()) getString(R.string.no_data) else metadata.authors.joinToString(", ")
plugin_status?.text = resources.getStringArray(R.array.extension_statuses)[metadata.status]
plugin_types?.text = if ((metadata.tvTypes == null) || metadata.tvTypes.isEmpty()) getString(R.string.no_data) else metadata.tvTypes.joinToString(", ")
plugin_lang?.text = if (metadata.language == null)
getString(R.string.no_data)
else
"${getFlagFromIso(metadata.language)} ${fromTwoLettersToLanguage(metadata.language)}"
github_btn.setOnClickListener {
if (metadata.repositoryUrl != null) {
openBrowser(metadata.repositoryUrl)
}
}
upvote.setOnClickListener {
ioSafe {
metadata.vote(VotingApi.VoteType.UPVOTE).main {
updateVoting(it)
}
}
}
downvote.setOnClickListener {
ioSafe {
metadata.vote(VotingApi.VoteType.DOWNVOTE).main {
updateVoting(it)
}
}
}
ioSafe {
metadata.getVotes().main {
updateVoting(it)
}
}
}
private fun updateVoting(value: Int) {
val metadata = data.plugin.second
plugin_votes.text = value.toString()
when (metadata.getVoteType()) {
VotingApi.VoteType.UPVOTE -> {
upvote.imageTintList = ColorStateList.valueOf(context?.colorFromAttribute(R.attr.colorPrimary) ?: R.color.colorPrimary)
downvote.imageTintList = ColorStateList.valueOf(context?.colorFromAttribute(R.attr.white) ?: R.color.white)
}
VotingApi.VoteType.DOWNVOTE -> {
downvote.imageTintList = ColorStateList.valueOf(context?.colorFromAttribute(R.attr.colorPrimary) ?: R.color.colorPrimary)
upvote.imageTintList = ColorStateList.valueOf(context?.colorFromAttribute(R.attr.white) ?: R.color.white)
}
VotingApi.VoteType.NONE -> {
upvote.imageTintList = ColorStateList.valueOf(context?.colorFromAttribute(R.attr.white) ?: R.color.white)
downvote.imageTintList = ColorStateList.valueOf(context?.colorFromAttribute(R.attr.white) ?: R.color.white)
}
}
}
}

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="?attr/white"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M15,3L6,3c-0.83,0 -1.54,0.5 -1.84,1.22l-3.02,7.05c-0.09,0.23 -0.14,0.47 -0.14,0.73v2c0,1.1 0.9,2 2,2h6.31l-0.95,4.57 -0.03,0.32c0,0.41 0.17,0.79 0.44,1.06L9.83,23l6.59,-6.59c0.36,-0.36 0.58,-0.86 0.58,-1.41L17,5c0,-1.1 -0.9,-2 -2,-2zM19,3v12h4L23,3h-4z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="?attr/white"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M1,21h4L5,9L1,9v12zM23,10c0,-1.1 -0.9,-2 -2,-2h-6.31l0.95,-4.57 0.03,-0.32c0,-0.41 -0.17,-0.79 -0.44,-1.06L14.17,1 7.59,7.59C7.22,7.95 7,8.45 7,9v10c0,1.1 0.9,2 2,2h9c0.83,0 1.54,-0.5 1.84,-1.22l3.02,-7.05c0.09,-0.23 0.14,-0.47 0.14,-0.73v-2z"/>
</vector>

View file

@ -0,0 +1,314 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="?attr/primaryGrayBackground"
android:clipToPadding="false"
android:orientation="vertical"
tools:context=".ui.settings.extensions.PluginDetailsFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:padding="20dp"
android:visibility="visible">
<androidx.cardview.widget.CardView
android:layout_width="50dp"
android:layout_height="50dp"
app:cardCornerRadius="25dp">
<ImageView
android:id="@+id/plugin_icon"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="ContentDescription" />
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/plugin_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:gravity="center_vertical"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:textColor="?attr/textColor"
android:textSize="20sp"
android:textStyle="normal"
tools:text="Hello world" />
<ImageView
android:id="@+id/github_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_github_logo" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:padding="8dp">
<!--marquee_forever-->
<com.google.android.material.button.MaterialButton
style="@style/SmallBlackButton"
android:layout_gravity="center"
android:layout_marginStart="10dp"
android:text="@string/extension_description" />
<TextView
android:id="@+id/plugin_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:layout_marginEnd="10dp"
android:ellipsize="none"
android:gravity="center_vertical"
android:singleLine="false"
android:textColor="?attr/textColor"
tools:text="Lolem ipsum kek Lolem ipsum kek Lolem ipsum kek Lolem ipsum kek " />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:padding="8dp">
<!--marquee_forever-->
<com.google.android.material.button.MaterialButton
style="@style/SmallBlackButton"
android:layout_gravity="center"
android:layout_marginStart="10dp"
android:text="@string/extension_authors" />
<TextView
android:id="@+id/plugin_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:singleLine="false"
android:textColor="?attr/textColor"
tools:text="Lolem ipsum kek" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:padding="8dp">
<!--marquee_forever-->
<com.google.android.material.button.MaterialButton
style="@style/SmallBlackButton"
android:layout_gravity="center"
android:layout_marginStart="10dp"
android:text="@string/extension_version" />
<TextView
android:id="@+id/plugin_version"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="?attr/textColor"
tools:text="Lolem ipsum kek" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:padding="8dp">
<!--marquee_forever-->
<com.google.android.material.button.MaterialButton
style="@style/SmallBlackButton"
android:layout_gravity="center"
android:layout_marginStart="10dp"
android:text="@string/extension_status" />
<TextView
android:id="@+id/plugin_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="?attr/textColor"
tools:text="Lolem ipsum kek" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:padding="8dp">
<!--marquee_forever-->
<com.google.android.material.button.MaterialButton
style="@style/SmallBlackButton"
android:layout_gravity="center"
android:layout_marginStart="10dp"
android:text="@string/extension_size" />
<TextView
android:id="@+id/plugin_size"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:singleLine="true"
android:textColor="?attr/textColor"
tools:text="Lolem ipsum kek" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:padding="8dp">
<!--marquee_forever-->
<com.google.android.material.button.MaterialButton
style="@style/SmallBlackButton"
android:layout_gravity="center"
android:layout_marginStart="10dp"
android:text="@string/extension_types" />
<TextView
android:id="@+id/plugin_types"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:singleLine="false"
android:textColor="?attr/textColor"
tools:text="Lolem ipsum kek" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="?android:attr/selectableItemBackgroundBorderless"
android:padding="8dp">
<!--marquee_forever-->
<com.google.android.material.button.MaterialButton
style="@style/SmallBlackButton"
android:layout_gravity="center"
android:layout_marginStart="10dp"
android:text="@string/extension_language" />
<TextView
android:id="@+id/plugin_lang"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="10dp"
android:ellipsize="marquee"
android:gravity="center_vertical"
android:singleLine="false"
android:textColor="?attr/textColor"
tools:text="Lolem ipsum kek" />
</LinearLayout>
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center_horizontal|center_vertical">
<ImageView
android:id="@+id/downvote"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_baseline_thumb_down_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/plugin_votes"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/plugin_votes"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="32dp"
android:gravity="center_horizontal|center_vertical"
android:text="0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/upvote"
app:layout_constraintStart_toEndOf="@+id/downvote"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/upvote"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="32dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_baseline_thumb_up_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/plugin_votes"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>

View file

@ -73,6 +73,17 @@
android:visibility="gone"
tools:visibility="visible" />
<TextView
android:id="@+id/ext_votes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="5dp"
android:textColor="?attr/grayTextColor"
tools:text="Votes: 10K"
android:visibility="gone"
tools:visibility="visible" />
<TextView
android:id="@+id/nsfw_marker"
android:layout_width="wrap_content"
@ -88,6 +99,7 @@
android:id="@+id/sub_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textColor="?attr/grayTextColor"
android:textSize="12sp"
tools:text="https://github.com/..." />

View file

@ -73,6 +73,17 @@
android:visibility="gone"
tools:visibility="visible" />
<TextView
android:id="@+id/ext_votes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginEnd="5dp"
tools:text="Rating: 0"
android:textColor="?attr/grayTextColor"
android:visibility="gone"
tools:visibility="visible" />
<TextView
android:id="@+id/nsfw_marker"
android:layout_width="wrap_content"
@ -88,9 +99,11 @@
android:id="@+id/sub_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textColor="?attr/grayTextColor"
android:textSize="12sp"
tools:text="https://github.com/..." />
</LinearLayout>
<ImageView
@ -119,4 +132,4 @@
android:padding="12dp"
tools:src="@drawable/ic_baseline_add_24" />
</LinearLayout>
</LinearLayout>

View file

@ -29,18 +29,14 @@
<item>4</item>
</array>
<array name="media_type_pref">
<item>Wszystko</item>
<item>Filmy i TV</item>
<item>Anime</item>
<item>Dokumentalne</item>
</array>
<array name="media_type_pref_values">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
</array>
<string-array name="extension_statuses">
<item>Nie działa</item>
<!-- "Ok" is usually capitalized as "OK". Ok android studio 🤓-->
<item>Ok</item>
<item>Wolny</item>
<item>Beta</item>
</string-array>
<array name="limit_title_rez_pref_names">
<item>@string/resolution_and_title</item>

View file

@ -408,23 +408,23 @@
<string name="repository_url_hint">Adres url repozytorium</string>
<string name="plugin_loaded">Rozszerzenie załadowane</string>
<string name="plugin_deleted">Rozszerzenie usunięte</string>
<string name="plugin_load_fail">Błąd ładowania %s</string>
<string name="plugin_load_fail" formatted="true">Błąd ładowania %s</string>
<string name="is_adult">+18</string>
<string name="batch_download_start_format">Zaczęto pobieranie %d %s</string>
<string name="batch_download_finish_format">Pobrano %d %s</string>
<string name="batch_download_nothing_to_download_format">Wszystkie %s już pobrane</string>
<string name="batch_download_start_format" formatted="true">Zaczęto pobieranie %d %s</string>
<string name="batch_download_finish_format" formatted="true">Pobrano %d %s</string>
<string name="batch_download_nothing_to_download_format" formatted="true">Wszystkie %s już pobrane</string>
<string name="batch_download">Pobierz wszystko</string>
<string name="plugin_singular">rozszerzenie</string>
<string name="plugin">rozszerzenia</string>
<string name="delete_repository_plugins">Ta akcja usunie także wszystkie rozszerzenia z repozytorium</string>
<string name="delete_repository">Usuń repozytorium</string>
<string name="setup_extensions_subtext">Pobierz strony które Cię interesują</string>
<string name="plugins_downloaded">Pobrano: %d</string>
<string name="plugins_disabled">Wyłączono: %d</string>
<string name="plugins_not_downloaded">Nie pobrano: %d</string>
<string name="plugins_downloaded" formatted="true">Pobrano: %d</string>
<string name="plugins_disabled" formatted="true">Wyłączono: %d</string>
<string name="plugins_not_downloaded" formatted="true">Nie pobrano: %d</string>
<string name="blank_repo_message">Dodaj repozytorium aby zainstalować rozszerzenia</string>
<string name="sync_score">Ocenione</string>
<string name="sync_score_format">%d na 10</string>
<string name="sync_score_format" formatted="true">%d na 10</string>
<string name="others">Inne</string>
<string name="other_singular">Wideo</string>
<string name="view_public_repositories_button">Zobacz repozytoria społeczności</string>
@ -433,7 +433,7 @@
<string name="subtitles_filter_lang">Filtrowanie wg preferowanego języka mediów</string>
<string name="uppercase_all_subtitles">Wszystkie napisy wielką literą</string>
<string name="download_all_plugins_from_repo">Pobrać wszystkie rozszerzenia z tego repozytorium?</string>
<string name="single_plugin_disabled">%s (Wyłączone)</string>
<string name="single_plugin_disabled" formatted="true">%s (Wyłączone)</string>
<string name="pref_filter_search_quality">Ukryj wybraną jakość wideo w wynikach wyszukiwania</string>
<string name="enable_nsfw_on_providers">Włącz NSFW u obsługiwanych dostawców</string>
<string name="category_providers">Dostawcy</string>
@ -446,4 +446,12 @@
<string name="apply_on_restart">Zastosuj po ponownym uruchomieniu</string>
<string name="autoplay_next_settings_des">Rozpocznij następny odcinek po zakończeniu bieżącego</string>
<string name="autoplay_next_settings">Autoodtwarzanie następnego odcinka</string>
<string name="extension_rating" formatted="true">Ocena: %s</string>
<string name="extension_description">Opis</string>
<string name="extension_version">Versja</string>
<string name="extension_status">Status</string>
<string name="extension_size">Rozmiar</string>
<string name="extension_authors">Autorzy</string>
<string name="extension_types">Wspierane</string>
<string name="extension_language">Język</string>
</resources>

View file

@ -257,6 +257,14 @@
<item>Light</item>
</string-array>
<string-array name="extension_statuses">
<item>Down</item>
<!-- "Ok" is usually capitalized as "OK". Ok android studio 🤓-->
<item>Ok</item>
<item>Slow</item>
<item>Beta</item>
</string-array>
<!--https://github.com/videolan/vlc-android/blob/72ccfb93db027b49855760001d1a930fa657c5a8/application/resources/src/main/res/values/arrays.xml#L266-->
<string-array name="subtitles_encoding_list" tools:ignore="TypographyDashes">
<item>@string/automatic</item>

View file

@ -615,5 +615,15 @@
<string name="safe_mode_title">Safe Mode enabled</string>
<string name="safe_mode_description">An unrecoverable crash occurred and we\'ve automatically disabled all extensions, so you can find and remove the extension which is causing trouble.</string>
<string name="safe_mode_crash_info">View crash info</string>
<string name="extension_rating" formatted="true">Rating: %s</string>
<string name="extension_description">Description</string>
<string name="extension_version">Version</string>
<string name="extension_status">Status</string>
<string name="extension_size">Size</string>
<string name="extension_authors">Authors</string>
<string name="extension_types">Supported</string>
<string name="extension_language">Language</string>
<string name="hls_playlist">HLS Playlist</string>
</resources>