mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
settings change + flashbang mode fixes
This commit is contained in:
parent
db04dd2781
commit
162ce53a82
37 changed files with 357 additions and 604 deletions
|
@ -36,7 +36,7 @@ android {
|
|||
targetSdkVersion 30
|
||||
|
||||
versionCode 47
|
||||
versionName "2.10.26"
|
||||
versionName "2.10.27"
|
||||
|
||||
resValue "string", "app_version",
|
||||
"${defaultConfig.versionName}${versionNameSuffix ?: ""}"
|
||||
|
|
|
@ -53,7 +53,6 @@ object APIHolder {
|
|||
PelisflixProvider(),
|
||||
SeriesflixProvider(),
|
||||
IHaveNoTvProvider(), // Documentaries provider
|
||||
LookMovieProvider(), // RECAPTCHA (Please allow up to 5 seconds...)
|
||||
VMoveeProvider(),
|
||||
AllMoviesForYouProvider(),
|
||||
VidEmbedProvider(),
|
||||
|
@ -472,12 +471,6 @@ fun base64Encode(array: ByteArray): String {
|
|||
|
||||
class ErrorLoadingException(message: String? = null) : Exception(message)
|
||||
|
||||
fun parseRating(ratingString: String?): Int? {
|
||||
if (ratingString == null) return null
|
||||
val floatRating = ratingString.toFloatOrNull() ?: return null
|
||||
return (floatRating * 10).toInt()
|
||||
}
|
||||
|
||||
fun MainAPI.fixUrlNull(url: String?): String? {
|
||||
if (url.isNullOrEmpty()) {
|
||||
return null
|
||||
|
|
|
@ -137,6 +137,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
R.id.navigation_settings_ui,
|
||||
R.id.navigation_settings_account,
|
||||
R.id.navigation_settings_lang,
|
||||
R.id.navigation_settings_general,
|
||||
).contains(destination.id)
|
||||
|
||||
val landscape = when (resources.configuration.orientation) {
|
||||
|
|
|
@ -1,298 +0,0 @@
|
|||
package com.lagradost.cloudstream3.movieproviders
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.APIHolder.unixTime
|
||||
import com.lagradost.cloudstream3.extractors.M3u8Manifest
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import org.jsoup.Jsoup
|
||||
|
||||
//BE AWARE THAT weboas.is is a clone of lookmovie
|
||||
class LookMovieProvider : MainAPI() {
|
||||
override val hasQuickSearch = true
|
||||
override var name = "LookMovie"
|
||||
override var mainUrl = "https://lookmovie.io"
|
||||
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Movie,
|
||||
TvType.TvSeries,
|
||||
)
|
||||
|
||||
data class LookMovieSearchResult(
|
||||
@JsonProperty("backdrop") val backdrop: String?,
|
||||
@JsonProperty("imdb_rating") val imdb_rating: String,
|
||||
@JsonProperty("poster") val poster: String?,
|
||||
@JsonProperty("slug") val slug: String,
|
||||
@JsonProperty("title") val title: String,
|
||||
@JsonProperty("year") val year: String?,
|
||||
// @JsonProperty("flag_quality") val flag_quality: Int?,
|
||||
)
|
||||
|
||||
data class LookMovieTokenRoot(
|
||||
@JsonProperty("data") val data: LookMovieTokenResult?,
|
||||
@JsonProperty("success") val success: Boolean,
|
||||
)
|
||||
|
||||
data class LookMovieTokenResult(
|
||||
@JsonProperty("accessToken") val accessToken: String,
|
||||
@JsonProperty("subtitles") val subtitles: List<LookMovieTokenSubtitle>?,
|
||||
)
|
||||
|
||||
data class LookMovieTokenSubtitle(
|
||||
@JsonProperty("language") val language: String,
|
||||
@JsonProperty("source") val source: String?,
|
||||
//@JsonProperty("source_id") val source_id: String,
|
||||
//@JsonProperty("kind") val kind: String,
|
||||
//@JsonProperty("id") val id: String,
|
||||
@JsonProperty("file") val file: String,
|
||||
)
|
||||
|
||||
data class LookMovieSearchResultRoot(
|
||||
// @JsonProperty("per_page") val per_page: Int?,
|
||||
// @JsonProperty("total") val total: Int?,
|
||||
@JsonProperty("result") val result: List<LookMovieSearchResult>?,
|
||||
)
|
||||
|
||||
data class LookMovieEpisode(
|
||||
@JsonProperty("title") var title: String,
|
||||
@JsonProperty("index") var index: String,
|
||||
@JsonProperty("episode") var episode: String,
|
||||
@JsonProperty("id_episode") var idEpisode: Int,
|
||||
@JsonProperty("season") var season: String,
|
||||
)
|
||||
|
||||
override suspend fun quickSearch(query: String): List<SearchResponse> {
|
||||
val movieUrl = "$mainUrl/api/v1/movies/search/?q=$query"
|
||||
val movieResponse = app.get(movieUrl).text
|
||||
val movies = mapper.readValue<LookMovieSearchResultRoot>(movieResponse).result
|
||||
|
||||
val showsUrl = "$mainUrl/api/v1/shows/search/?q=$query"
|
||||
val showsResponse = app.get(showsUrl).text
|
||||
val shows = mapper.readValue<LookMovieSearchResultRoot>(showsResponse).result
|
||||
|
||||
val returnValue = ArrayList<SearchResponse>()
|
||||
if (!movies.isNullOrEmpty()) {
|
||||
for (m in movies) {
|
||||
val url = "$mainUrl/movies/view/${m.slug}"
|
||||
returnValue.add(
|
||||
MovieSearchResponse(
|
||||
m.title,
|
||||
url,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
m.poster ?: m.backdrop,
|
||||
m.year?.toIntOrNull()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (!shows.isNullOrEmpty()) {
|
||||
for (s in shows) {
|
||||
val url = "$mainUrl/shows/view/${s.slug}"
|
||||
returnValue.add(
|
||||
MovieSearchResponse(
|
||||
s.title,
|
||||
url,
|
||||
this.name,
|
||||
TvType.TvSeries,
|
||||
s.poster ?: s.backdrop,
|
||||
s.year?.toIntOrNull()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return returnValue
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
suspend fun search(query: String, isMovie: Boolean): List<SearchResponse> {
|
||||
val url = "$mainUrl/${if (isMovie) "movies" else "shows"}/search/?q=$query"
|
||||
val response = app.get(url).text
|
||||
val document = Jsoup.parse(response)
|
||||
|
||||
val items = document.select("div.flex-wrap-movielist > div.movie-item-style-1")
|
||||
return items.map { item ->
|
||||
val titleHolder = item.selectFirst("> div.mv-item-infor > h6 > a")
|
||||
val href = fixUrl(titleHolder!!.attr("href"))
|
||||
val name = titleHolder.text()
|
||||
val posterHolder = item.selectFirst("> div.image__placeholder > a")
|
||||
val poster = posterHolder!!.selectFirst("> img")?.attr("data-src")
|
||||
val year = posterHolder.selectFirst("> p.year")?.text()?.toIntOrNull()
|
||||
if (isMovie) {
|
||||
MovieSearchResponse(
|
||||
name, href, this.name, TvType.Movie, poster, year
|
||||
)
|
||||
} else
|
||||
TvSeriesSearchResponse(
|
||||
name, href, this.name, TvType.TvSeries, poster, year, null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val movieList = search(query, true).toMutableList()
|
||||
val seriesList = search(query, false)
|
||||
movieList.addAll(seriesList)
|
||||
return movieList
|
||||
}
|
||||
|
||||
data class LookMovieLinkLoad(val url: String, val extraUrl: String, val isMovie: Boolean)
|
||||
|
||||
private fun addSubtitles(
|
||||
subs: List<LookMovieTokenSubtitle>?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit
|
||||
) {
|
||||
if (subs == null) return
|
||||
subs.forEach {
|
||||
if (it.file.endsWith(".vtt"))
|
||||
subtitleCallback.invoke(SubtitleFile(it.language, fixUrl(it.file)))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun loadCurrentLinks(url: String, callback: (ExtractorLink) -> Unit) {
|
||||
val response = app.get(url.replace("\$unixtime", unixTime.toString())).text
|
||||
M3u8Manifest.extractLinks(response).forEach {
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
"${this.name} - ${it.second}",
|
||||
fixUrl(it.first),
|
||||
"",
|
||||
getQualityFromName(it.second),
|
||||
true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun loadLinks(
|
||||
data: String,
|
||||
isCasting: Boolean,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val localData: LookMovieLinkLoad = mapper.readValue(data)
|
||||
|
||||
if (localData.isMovie) {
|
||||
val tokenResponse = app.get(localData.url).text
|
||||
val root = mapper.readValue<LookMovieTokenRoot>(tokenResponse)
|
||||
val accessToken = root.data?.accessToken ?: return false
|
||||
addSubtitles(root.data.subtitles, subtitleCallback)
|
||||
loadCurrentLinks(localData.extraUrl.replace("\$accessToken", accessToken), callback)
|
||||
return true
|
||||
} else {
|
||||
loadCurrentLinks(localData.url, callback)
|
||||
val subResponse = app.get(localData.extraUrl).text
|
||||
val subs = mapper.readValue<List<LookMovieTokenSubtitle>>(subResponse)
|
||||
addSubtitles(subs, subtitleCallback)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse? {
|
||||
val response = app.get(url).text
|
||||
val document = Jsoup.parse(response)
|
||||
val isMovie = url.contains("/movies/")
|
||||
|
||||
val watchHeader = document.selectFirst("div.watch-heading")
|
||||
val nameHeader = watchHeader!!.selectFirst("> h1.bd-hd")
|
||||
val year = nameHeader!!.selectFirst("> span")?.text()?.toIntOrNull()
|
||||
val title = nameHeader.ownText()
|
||||
val rating =
|
||||
parseRating(watchHeader.selectFirst("> div.movie-rate > div.rate > p > span")!!.text())
|
||||
val imgElement = document.selectFirst("div.movie-img > p.movie__poster")
|
||||
val img = imgElement?.attr("style")
|
||||
var poster = if (img.isNullOrEmpty()) null else "url\\((.*?)\\)".toRegex()
|
||||
.find(img)?.groupValues?.get(1)
|
||||
if (poster.isNullOrEmpty()) poster = imgElement?.attr("data-background-image")
|
||||
val descript = document.selectFirst("p.description-short")!!.text()
|
||||
val id = "${if (isMovie) "id_movie" else "id_show"}:(.*?),".toRegex()
|
||||
.find(response)?.groupValues?.get(1)
|
||||
?.replace(" ", "")
|
||||
?: return null
|
||||
val realSlug = url.replace("$mainUrl/${if (isMovie) "movies" else "shows"}/view/", "")
|
||||
val realUrl =
|
||||
"$mainUrl/api/v1/security/${if (isMovie) "movie" else "show"}-access?${if (isMovie) "id_movie=$id" else "slug=$realSlug"}&token=1&sk=&step=1"
|
||||
|
||||
if (isMovie) {
|
||||
val localData =
|
||||
LookMovieLinkLoad(
|
||||
realUrl,
|
||||
"$mainUrl/manifests/movies/json/$id/\$unixtime/\$accessToken/master.m3u8",
|
||||
true
|
||||
).toJson()
|
||||
|
||||
return MovieLoadResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
TvType.Movie,
|
||||
localData,
|
||||
poster,
|
||||
year,
|
||||
descript,
|
||||
rating
|
||||
)
|
||||
} else {
|
||||
val tokenResponse = app.get(realUrl).text
|
||||
val root = mapper.readValue<LookMovieTokenRoot>(tokenResponse)
|
||||
val accessToken = root.data?.accessToken ?: return null
|
||||
|
||||
val window =
|
||||
"window\\['show_storage'] =((.|\\n)*?<)".toRegex().find(response)?.groupValues?.get(
|
||||
1
|
||||
)
|
||||
?: return null
|
||||
// val id = "id_show:(.*?),".toRegex().find(response.text)?.groupValues?.get(1) ?: return null
|
||||
val season = "seasons:.*\\[((.|\\n)*?)]".toRegex().find(window)?.groupValues?.get(1)
|
||||
?: return null
|
||||
|
||||
fun String.fixSeasonJson(replace: String): String {
|
||||
return this.replace("$replace:", "\"$replace\":")
|
||||
}
|
||||
|
||||
val json = season
|
||||
.replace("\'", "\"")
|
||||
.fixSeasonJson("title")
|
||||
.fixSeasonJson("id_episode")
|
||||
.fixSeasonJson("episode")
|
||||
.fixSeasonJson("index")
|
||||
.fixSeasonJson("season")
|
||||
val realJson = "[" + json.substring(0, json.lastIndexOf(',')) + "]"
|
||||
|
||||
val episodes = mapper.readValue<List<LookMovieEpisode>>(realJson).map {
|
||||
val localData =
|
||||
LookMovieLinkLoad(
|
||||
"$mainUrl/manifests/shows/json/$accessToken/\$unixtime/${it.idEpisode}/master.m3u8",
|
||||
"https://lookmovie.io/api/v1/shows/episode-subtitles/?id_episode=${it.idEpisode}",
|
||||
false
|
||||
).toJson()
|
||||
|
||||
|
||||
Episode(
|
||||
localData,
|
||||
it.title,
|
||||
it.season.toIntOrNull(),
|
||||
it.episode.toIntOrNull(),
|
||||
)
|
||||
}.toList()
|
||||
|
||||
return TvSeriesLoadResponse(
|
||||
title,
|
||||
url,
|
||||
this.name,
|
||||
TvType.TvSeries,
|
||||
ArrayList(episodes),
|
||||
poster,
|
||||
year,
|
||||
descript,
|
||||
null,
|
||||
rating
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1786,7 +1786,7 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
|
|||
}
|
||||
result_description.setOnClickListener {
|
||||
val builder: AlertDialog.Builder =
|
||||
AlertDialog.Builder(requireContext())
|
||||
AlertDialog.Builder(requireContext(), R.style.AlertDialogCustom)
|
||||
builder.setMessage(d.plot)
|
||||
.setTitle(if (d.type == TvType.Torrent) R.string.torrent_plot else R.string.result_plot)
|
||||
.show()
|
||||
|
|
|
@ -11,7 +11,6 @@ import androidx.appcompat.app.AlertDialog
|
|||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.lagradost.cloudstream3.CommonActivity.showToast
|
||||
import com.lagradost.cloudstream3.R
|
||||
|
@ -24,7 +23,6 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.openSub
|
|||
import com.lagradost.cloudstream3.syncproviders.AuthAPI
|
||||
import com.lagradost.cloudstream3.syncproviders.InAppAuthAPI
|
||||
import com.lagradost.cloudstream3.syncproviders.OAuth2API
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.beneneCount
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||
|
@ -38,7 +36,7 @@ import kotlinx.android.synthetic.main.add_account_input.*
|
|||
class SettingsAccount : PreferenceFragmentCompat() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setUpToolbar(R.string.category_credits)
|
||||
setUpToolbar(R.string.category_account)
|
||||
}
|
||||
|
||||
private fun showLoginInfo(api: AccountManager, info: AuthAPI.LoginInfo) {
|
||||
|
@ -179,16 +177,7 @@ class SettingsAccount : PreferenceFragmentCompat() {
|
|||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
hideKeyboard()
|
||||
setPreferencesFromResource(R.xml.settings_credits_account, rootKey)
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
|
||||
getPref(R.string.legal_notice_key)?.setOnPreferenceClickListener {
|
||||
val builder: AlertDialog.Builder = AlertDialog.Builder(it.context)
|
||||
builder.setTitle(R.string.legal_notice)
|
||||
builder.setMessage(R.string.legal_notice_text)
|
||||
builder.show()
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
setPreferencesFromResource(R.xml.settings_account, rootKey)
|
||||
|
||||
val syncApis =
|
||||
listOf(
|
||||
|
@ -213,33 +202,5 @@ class SettingsAccount : PreferenceFragmentCompat() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
beneneCount = settingsManager.getInt(getString(R.string.benene_count), 0)
|
||||
getPref(R.string.benene_count)?.let { pref ->
|
||||
pref.summary =
|
||||
if (beneneCount <= 0) getString(R.string.benene_count_text_none) else getString(
|
||||
R.string.benene_count_text
|
||||
).format(
|
||||
beneneCount
|
||||
)
|
||||
|
||||
pref.setOnPreferenceClickListener {
|
||||
try {
|
||||
beneneCount++
|
||||
settingsManager.edit().putInt(getString(R.string.benene_count), beneneCount)
|
||||
.apply()
|
||||
it.summary = getString(R.string.benene_count_text).format(beneneCount)
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ class SettingsFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
fun PreferenceFragmentCompat?.setUpToolbar(@StringRes title : Int) {
|
||||
fun PreferenceFragmentCompat?.setUpToolbar(@StringRes title: Int) {
|
||||
if (this == null) return
|
||||
settings_toolbar?.apply {
|
||||
setTitle(title)
|
||||
|
@ -131,6 +131,7 @@ class SettingsFragment : Fragment() {
|
|||
}
|
||||
|
||||
listOf(
|
||||
Pair(settings_general, R.id.action_navigation_settings_to_navigation_settings_general),
|
||||
Pair(settings_player, R.id.action_navigation_settings_to_navigation_settings_player),
|
||||
Pair(settings_credits, R.id.action_navigation_settings_to_navigation_settings_account),
|
||||
Pair(settings_ui, R.id.action_navigation_settings_to_navigation_settings_ui),
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
package com.lagradost.cloudstream3.ui.settings
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.view.View
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.hippo.unifile.UniFile
|
||||
import com.lagradost.cloudstream3.AcraApplication
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.network.initClient
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getBasePath
|
||||
import java.io.File
|
||||
|
||||
class SettingsGeneral : PreferenceFragmentCompat() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setUpToolbar(R.string.category_general)
|
||||
}
|
||||
|
||||
// Open file picker
|
||||
private val pathPicker =
|
||||
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
|
||||
// It lies, it can be null if file manager quits.
|
||||
if (uri == null) return@registerForActivityResult
|
||||
val context = context ?: AcraApplication.context ?: return@registerForActivityResult
|
||||
// RW perms for the path
|
||||
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
|
||||
context.contentResolver.takePersistableUriPermission(uri, flags)
|
||||
|
||||
val file = UniFile.fromUri(context, uri)
|
||||
println("Selected URI path: $uri - Full path: ${file.filePath}")
|
||||
|
||||
// Stores the real URI using download_path_key
|
||||
// Important that the URI is stored instead of filepath due to permissions.
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.edit().putString(getString(R.string.download_path_key), uri.toString()).apply()
|
||||
|
||||
// From URI -> File path
|
||||
// File path here is purely for cosmetic purposes in settings
|
||||
(file.filePath ?: uri.toString()).let {
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.edit().putString(getString(R.string.download_path_pref), it).apply()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
hideKeyboard()
|
||||
setPreferencesFromResource(R.xml.settins_general, rootKey)
|
||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
|
||||
getPref(R.string.legal_notice_key)?.setOnPreferenceClickListener {
|
||||
val builder: AlertDialog.Builder =
|
||||
AlertDialog.Builder(it.context, R.style.AlertDialogCustom)
|
||||
builder.setTitle(R.string.legal_notice)
|
||||
builder.setMessage(R.string.legal_notice_text)
|
||||
builder.show()
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
|
||||
getPref(R.string.dns_key)?.setOnPreferenceClickListener {
|
||||
val prefNames = resources.getStringArray(R.array.dns_pref)
|
||||
val prefValues = resources.getIntArray(R.array.dns_pref_values)
|
||||
|
||||
val currentDns =
|
||||
settingsManager.getInt(getString(R.string.dns_pref), 0)
|
||||
|
||||
activity?.showBottomDialog(
|
||||
prefNames.toList(),
|
||||
prefValues.indexOf(currentDns),
|
||||
getString(R.string.dns_pref),
|
||||
true,
|
||||
{}) {
|
||||
settingsManager.edit().putInt(getString(R.string.dns_pref), prefValues[it]).apply()
|
||||
(context ?: AcraApplication.context)?.let { ctx -> app.initClient(ctx) }
|
||||
}
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
fun getDownloadDirs(): List<String> {
|
||||
return normalSafeApiCall {
|
||||
val defaultDir = VideoDownloadManager.getDownloadDir()?.filePath
|
||||
|
||||
// app_name_download_path = Cloudstream and does not change depending on release.
|
||||
// DOES NOT WORK ON SCOPED STORAGE.
|
||||
val secondaryDir =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) null else Environment.getExternalStorageDirectory().absolutePath +
|
||||
File.separator + resources.getString(R.string.app_name_download_path)
|
||||
val first = listOf(defaultDir, secondaryDir)
|
||||
(try {
|
||||
val currentDir = context?.getBasePath()?.let { it.first?.filePath ?: it.second }
|
||||
|
||||
(first +
|
||||
requireContext().getExternalFilesDirs("").mapNotNull { it.path } +
|
||||
currentDir)
|
||||
} catch (e: Exception) {
|
||||
first
|
||||
}).filterNotNull().distinct()
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
getPref(R.string.download_path_key)?.setOnPreferenceClickListener {
|
||||
val dirs = getDownloadDirs()
|
||||
|
||||
val currentDir =
|
||||
settingsManager.getString(getString(R.string.download_path_pref), null)
|
||||
?: VideoDownloadManager.getDownloadDir().toString()
|
||||
|
||||
activity?.showBottomDialog(
|
||||
dirs + listOf("Custom"),
|
||||
dirs.indexOf(currentDir),
|
||||
getString(R.string.download_path_pref),
|
||||
true,
|
||||
{}) {
|
||||
// Last = custom
|
||||
if (it == dirs.size) {
|
||||
try {
|
||||
pathPicker.launch(Uri.EMPTY)
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
} else {
|
||||
// Sets both visual and actual paths.
|
||||
// key = used path
|
||||
// pref = visual path
|
||||
settingsManager.edit()
|
||||
.putString(getString(R.string.download_path_key), dirs[it]).apply()
|
||||
settingsManager.edit()
|
||||
.putString(getString(R.string.download_path_pref), dirs[it]).apply()
|
||||
}
|
||||
}
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
|
||||
try {
|
||||
SettingsFragment.beneneCount =
|
||||
settingsManager.getInt(getString(R.string.benene_count), 0)
|
||||
getPref(R.string.benene_count)?.let { pref ->
|
||||
pref.summary =
|
||||
if (SettingsFragment.beneneCount <= 0) getString(R.string.benene_count_text_none) else getString(
|
||||
R.string.benene_count_text
|
||||
).format(
|
||||
SettingsFragment.beneneCount
|
||||
)
|
||||
|
||||
pref.setOnPreferenceClickListener {
|
||||
try {
|
||||
SettingsFragment.beneneCount++
|
||||
settingsManager.edit().putInt(
|
||||
getString(R.string.benene_count),
|
||||
SettingsFragment.beneneCount
|
||||
)
|
||||
.apply()
|
||||
it.summary =
|
||||
getString(R.string.benene_count_text).format(SettingsFragment.beneneCount)
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,21 +1,11 @@
|
|||
package com.lagradost.cloudstream3.ui.settings
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.view.View
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.hippo.unifile.UniFile
|
||||
import com.lagradost.cloudstream3.AcraApplication
|
||||
import com.lagradost.cloudstream3.R
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.network.initClient
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getFolderSize
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
|
||||
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.setUpToolbar
|
||||
|
@ -25,43 +15,12 @@ import com.lagradost.cloudstream3.utils.Qualities
|
|||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
|
||||
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager
|
||||
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getBasePath
|
||||
import java.io.File
|
||||
|
||||
class SettingsPlayer : PreferenceFragmentCompat() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
setUpToolbar(R.string.category_player)
|
||||
}
|
||||
// Open file picker
|
||||
private val pathPicker =
|
||||
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
|
||||
// It lies, it can be null if file manager quits.
|
||||
if (uri == null) return@registerForActivityResult
|
||||
val context = context ?: AcraApplication.context ?: return@registerForActivityResult
|
||||
// RW perms for the path
|
||||
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
|
||||
Intent.FLAG_GRANT_WRITE_URI_PERMISSION
|
||||
|
||||
context.contentResolver.takePersistableUriPermission(uri, flags)
|
||||
|
||||
val file = UniFile.fromUri(context, uri)
|
||||
println("Selected URI path: $uri - Full path: ${file.filePath}")
|
||||
|
||||
// Stores the real URI using download_path_key
|
||||
// Important that the URI is stored instead of filepath due to permissions.
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.edit().putString(getString(R.string.download_path_key), uri.toString()).apply()
|
||||
|
||||
// From URI -> File path
|
||||
// File path here is purely for cosmetic purposes in settings
|
||||
(file.filePath ?: uri.toString()).let {
|
||||
PreferenceManager.getDefaultSharedPreferences(context)
|
||||
.edit().putString(getString(R.string.download_path_pref), it).apply()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
hideKeyboard()
|
||||
setPreferencesFromResource(R.xml.settings_player, rootKey)
|
||||
|
@ -86,24 +45,6 @@ class SettingsPlayer : PreferenceFragmentCompat() {
|
|||
}
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
getPref(R.string.dns_key)?.setOnPreferenceClickListener {
|
||||
val prefNames = resources.getStringArray(R.array.dns_pref)
|
||||
val prefValues = resources.getIntArray(R.array.dns_pref_values)
|
||||
|
||||
val currentDns =
|
||||
settingsManager.getInt(getString(R.string.dns_pref), 0)
|
||||
|
||||
activity?.showBottomDialog(
|
||||
prefNames.toList(),
|
||||
prefValues.indexOf(currentDns),
|
||||
getString(R.string.dns_pref),
|
||||
true,
|
||||
{}) {
|
||||
settingsManager.edit().putInt(getString(R.string.dns_pref), prefValues[it]).apply()
|
||||
(context ?: AcraApplication.context)?.let { ctx -> app.initClient(ctx) }
|
||||
}
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
|
||||
getPref(R.string.prefer_limit_title_key)?.setOnPreferenceClickListener {
|
||||
val prefNames = resources.getStringArray(R.array.limit_title_pref_names)
|
||||
|
@ -242,60 +183,6 @@ class SettingsPlayer : PreferenceFragmentCompat() {
|
|||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
}
|
||||
fun getDownloadDirs(): List<String> {
|
||||
return normalSafeApiCall {
|
||||
val defaultDir = VideoDownloadManager.getDownloadDir()?.filePath
|
||||
|
||||
// app_name_download_path = Cloudstream and does not change depending on release.
|
||||
// DOES NOT WORK ON SCOPED STORAGE.
|
||||
val secondaryDir =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) null else Environment.getExternalStorageDirectory().absolutePath +
|
||||
File.separator + resources.getString(R.string.app_name_download_path)
|
||||
val first = listOf(defaultDir, secondaryDir)
|
||||
(try {
|
||||
val currentDir = context?.getBasePath()?.let { it.first?.filePath ?: it.second }
|
||||
|
||||
(first +
|
||||
requireContext().getExternalFilesDirs("").mapNotNull { it.path } +
|
||||
currentDir)
|
||||
} catch (e: Exception) {
|
||||
first
|
||||
}).filterNotNull().distinct()
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
getPref(R.string.download_path_key)?.setOnPreferenceClickListener {
|
||||
val dirs = getDownloadDirs()
|
||||
|
||||
val currentDir =
|
||||
settingsManager.getString(getString(R.string.download_path_pref), null)
|
||||
?: VideoDownloadManager.getDownloadDir().toString()
|
||||
|
||||
activity?.showBottomDialog(
|
||||
dirs + listOf("Custom"),
|
||||
dirs.indexOf(currentDir),
|
||||
getString(R.string.download_path_pref),
|
||||
true,
|
||||
{}) {
|
||||
// Last = custom
|
||||
if (it == dirs.size) {
|
||||
try {
|
||||
pathPicker.launch(Uri.EMPTY)
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
} else {
|
||||
// Sets both visual and actual paths.
|
||||
// key = used path
|
||||
// pref = visual path
|
||||
settingsManager.edit()
|
||||
.putString(getString(R.string.download_path_key), dirs[it]).apply()
|
||||
settingsManager.edit()
|
||||
.putString(getString(R.string.download_path_pref), dirs[it]).apply()
|
||||
}
|
||||
}
|
||||
return@setOnPreferenceClickListener true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,12 +1,11 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
app:tint="?attr/white">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,3v8h8L11,3L3,3zM9,9L5,9L5,5h4v4zM3,13v8h8v-8L3,13zM9,19L5,19v-4h4v4zM13,3v8h8L21,3h-8zM19,9h-4L15,5h4v4zM13,13v8h8v-8h-8zM19,19h-4v-4h4v4z"
|
||||
android:fillType="evenOdd"/>
|
||||
android:tint="?attr/white">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,3v8h8L11,3L3,3zM9,9L5,9L5,5h4v4zM3,13v8h8v-8L3,13zM9,19L5,19v-4h4v4zM13,3v8h8L21,3h-8zM19,9h-4L15,5h4v4zM13,13v8h8v-8h-8zM19,19h-4v-4h4v4z"
|
||||
android:fillType="evenOdd" />
|
||||
</vector>
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<EditText
|
||||
android:textColorHint="?attr/grayTextColor"
|
||||
android:hint="@string/example_username"
|
||||
android:autofillHints="username"
|
||||
android:id="@+id/login_username_input"
|
||||
|
@ -57,6 +58,7 @@
|
|||
tools:ignore="LabelFor" />
|
||||
|
||||
<EditText
|
||||
android:textColorHint="?attr/grayTextColor"
|
||||
android:autofillHints="emailAddress"
|
||||
android:hint="@string/example_email"
|
||||
android:id="@+id/login_email_input"
|
||||
|
@ -72,6 +74,7 @@
|
|||
tools:ignore="LabelFor" />
|
||||
|
||||
<EditText
|
||||
android:textColorHint="?attr/grayTextColor"
|
||||
android:hint="@string/example_ip"
|
||||
android:id="@+id/login_server_input"
|
||||
android:nextFocusRight="@id/cancel_btt"
|
||||
|
@ -85,6 +88,7 @@
|
|||
tools:ignore="LabelFor" />
|
||||
|
||||
<EditText
|
||||
android:textColorHint="?attr/grayTextColor"
|
||||
android:hint="@string/example_password"
|
||||
android:id="@+id/login_password_input"
|
||||
android:nextFocusRight="@id/cancel_btt"
|
||||
|
|
|
@ -117,7 +117,7 @@
|
|||
android:layout_gravity="bottom"
|
||||
android:paddingBottom="5dp"
|
||||
android:paddingTop="5dp"
|
||||
android:textColor="@color/textColor"
|
||||
android:textColor="?attr/textColor"
|
||||
android:id="@+id/imageText"
|
||||
android:minLines="2"
|
||||
android:maxLines="2"
|
||||
|
|
|
@ -52,8 +52,15 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:nextFocusDown="@id/settings_player"
|
||||
|
||||
android:id="@+id/settings_general"
|
||||
style="@style/SettingsItem"
|
||||
android:text="@string/category_general" />
|
||||
|
||||
<TextView
|
||||
android:nextFocusUp="@id/settings_general"
|
||||
android:nextFocusDown="@id/settings_lang"
|
||||
|
||||
android:id="@+id/settings_player"
|
||||
|
@ -89,7 +96,7 @@
|
|||
|
||||
android:id="@+id/settings_credits"
|
||||
style="@style/SettingsItem"
|
||||
android:text="@string/category_credits" />
|
||||
android:text="@string/category_account" />
|
||||
|
||||
<TextView
|
||||
android:padding="10dp"
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
<?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"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/primaryBlackBackground" >
|
||||
<ImageView
|
||||
android:id="@+id/imgPoster"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="fitCenter"
|
||||
android:adjustViewBounds="true"
|
||||
android:src="@drawable/default_cover"
|
||||
android:background="#fffff0"
|
||||
android:contentDescription="@string/poster_image"
|
||||
/>
|
||||
android:background="?attr/primaryBlackBackground">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imgPoster"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="fitCenter"
|
||||
android:adjustViewBounds="true"
|
||||
android:src="@drawable/default_cover"
|
||||
android:background="#fffff0"
|
||||
android:contentDescription="@string/poster_image" />
|
||||
</LinearLayout>
|
|
@ -44,6 +44,7 @@
|
|||
app:tint="?attr/textColor" />
|
||||
|
||||
<EditText
|
||||
android:textColorHint="?attr/grayTextColor"
|
||||
android:id="@+id/result_sync_current_episodes"
|
||||
style="@style/AppEditStyle"
|
||||
tools:hint="20"
|
||||
|
|
|
@ -11,70 +11,70 @@
|
|||
android:clickable="true"
|
||||
android:id="@+id/search_result_root">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_margin="2dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_margin="2dp"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:elevation="10dp"
|
||||
app:cardCornerRadius="@dimen/rounded_image_radius"
|
||||
android:id="@+id/background_card"
|
||||
app:cardBackgroundColor="?attr/primaryGrayBackground">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
tools:src="@drawable/example_poster"
|
||||
|
||||
android:duplicateParentState="true"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:elevation="10dp"
|
||||
app:cardCornerRadius="@dimen/rounded_image_radius"
|
||||
android:id="@+id/background_card"
|
||||
app:cardBackgroundColor="?attr/primaryGrayBackground">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
tools:src="@drawable/example_poster"
|
||||
|
||||
android:duplicateParentState="true"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/search_poster_img_des" />
|
||||
|
||||
<TextView
|
||||
tools:text="@string/quality_hd"
|
||||
android:id="@+id/text_quality"
|
||||
android:textColor="@color/textColor"
|
||||
style="@style/SearchBox"
|
||||
android:background="@drawable/type_bg_color" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="end"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:text="@string/app_dubbed_text"
|
||||
android:id="@+id/text_is_dub"
|
||||
android:layout_gravity="end"
|
||||
style="@style/SearchBox"
|
||||
android:background="@drawable/dub_bg_color" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_is_sub"
|
||||
android:text="@string/app_subbed_text"
|
||||
android:layout_gravity="end"
|
||||
style="@style/SearchBox"
|
||||
android:background="@drawable/sub_bg_color" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
android:foreground="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/search_poster_img_des" />
|
||||
|
||||
<TextView
|
||||
tools:text="The Perfect Run\nThe Perfect Run"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="13sp"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="bottom"
|
||||
android:paddingBottom="5dp"
|
||||
android:paddingTop="5dp"
|
||||
tools:text="@string/quality_hd"
|
||||
android:id="@+id/text_quality"
|
||||
android:textColor="@color/textColor"
|
||||
android:id="@+id/imageText"
|
||||
android:minLines="2"
|
||||
android:maxLines="2"
|
||||
android:paddingStart="5dp"
|
||||
android:paddingEnd="5dp"
|
||||
android:ellipsize="end" />
|
||||
style="@style/SearchBox"
|
||||
android:background="@drawable/type_bg_color" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="end"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:text="@string/app_dubbed_text"
|
||||
android:id="@+id/text_is_dub"
|
||||
android:layout_gravity="end"
|
||||
style="@style/SearchBox"
|
||||
android:background="@drawable/dub_bg_color" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_is_sub"
|
||||
android:text="@string/app_subbed_text"
|
||||
android:layout_gravity="end"
|
||||
style="@style/SearchBox"
|
||||
android:background="@drawable/sub_bg_color" />
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<TextView
|
||||
tools:text="The Perfect Run\nThe Perfect Run"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="13sp"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="bottom"
|
||||
android:paddingBottom="5dp"
|
||||
android:paddingTop="5dp"
|
||||
android:textColor="?attr/textColor"
|
||||
android:id="@+id/imageText"
|
||||
android:minLines="2"
|
||||
android:maxLines="2"
|
||||
android:paddingStart="5dp"
|
||||
android:paddingEnd="5dp"
|
||||
android:ellipsize="end" />
|
||||
</LinearLayout>
|
|
@ -119,6 +119,15 @@
|
|||
app:popEnterAnim="@anim/enter_anim"
|
||||
app:popExitAnim="@anim/exit_anim" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_settings_general"
|
||||
android:label="@string/title_settings"
|
||||
android:name="com.lagradost.cloudstream3.ui.settings.SettingsGeneral"
|
||||
app:enterAnim="@anim/enter_anim"
|
||||
app:exitAnim="@anim/exit_anim"
|
||||
app:popEnterAnim="@anim/enter_anim"
|
||||
app:popExitAnim="@anim/exit_anim" />
|
||||
|
||||
<fragment
|
||||
android:id="@+id/navigation_settings_lang"
|
||||
android:label="@string/title_settings"
|
||||
|
@ -290,6 +299,13 @@
|
|||
app:exitAnim="@anim/exit_anim"
|
||||
app:popEnterAnim="@anim/enter_anim"
|
||||
app:popExitAnim="@anim/exit_anim" />
|
||||
<action
|
||||
app:enterAnim="@anim/enter_anim"
|
||||
app:exitAnim="@anim/exit_anim"
|
||||
app:popEnterAnim="@anim/enter_anim"
|
||||
app:popExitAnim="@anim/exit_anim"
|
||||
android:id="@+id/action_navigation_settings_to_navigation_settings_general"
|
||||
app:destination="@id/navigation_settings_general" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
|
|
|
@ -246,7 +246,7 @@
|
|||
<string name="resize_fill">امتداد</string>
|
||||
<string name="resize_zoom">تكبير</string>
|
||||
|
||||
<string name="general">عام</string>
|
||||
<string name="category_general">عام</string>
|
||||
<string name="provider_lang_settings">لغات الموفر</string>
|
||||
<string name="app_layout">واجهة التطبيق</string>
|
||||
<string name="preferred_media_settings">النوع المفضل من المشاهدة</string>
|
||||
|
|
|
@ -238,7 +238,7 @@
|
|||
|
||||
<string name="search">Búsqueda</string>
|
||||
<string name="category_nginx">Nginx</string>
|
||||
<string name="category_credits">Créditos y cuenta</string>
|
||||
<string name="category_account">Créditos y cuenta</string>
|
||||
<string name="category_updates">Actualizaciones y copia de seguridad</string>
|
||||
<string name="nginx_credentials_title">Credencial Nginx</string>
|
||||
<string name="nginx_credentials_summary">Tienes que usar el siguiente formato minombredeusuariogenial:micontraseñasegura123</string>
|
||||
|
@ -408,7 +408,7 @@
|
|||
responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use
|
||||
CloudStream 3 at your own risk.
|
||||
</string>
|
||||
<string name="general">General</string>
|
||||
<string name="category_general">General</string>
|
||||
<string name="random_button_settings">Botón aleatorio</string>
|
||||
<string name="random_button_settings_desc">Mostrar botón aleatorio en la página de inicio</string>
|
||||
<string name="provider_lang_settings">Idiomas del proveedor</string>
|
||||
|
|
|
@ -193,7 +193,7 @@
|
|||
<string name="app_theme_settings">Thème de l\'application</string>
|
||||
<string name="player_speed_text_format" formatted="true">Vitesse (%.2fx)</string>
|
||||
<string name="use_system_brightness_settings">Utiliser la luminosité du système</string>
|
||||
<string name="general">Général</string>
|
||||
<string name="category_general">Général</string>
|
||||
<string name="dns_pref">DNS avec HTTPS</string>
|
||||
<string name="display_subbed_dubbed_settings">Afficher les animés en Anglais (Dub) / sous-titrés</string>
|
||||
<string name="phone_layout">Disposition en mode téléphone</string>
|
||||
|
|
|
@ -188,7 +188,7 @@
|
|||
|
||||
<string name="search">Cari</string>
|
||||
<string name="category_nginx">Nginx</string>
|
||||
<string name="category_credits">Kredit dan akun</string>
|
||||
<string name="category_account">Kredit dan akun</string>
|
||||
<string name="category_updates">Update dan cadangan</string>
|
||||
<string name="nginx_credentials_title">Kredensial Nginx</string>
|
||||
<string name="nginx_credentials_summary">Kamu harus menggunakan format berikut namaku:passwordku123</string>
|
||||
|
@ -359,7 +359,7 @@
|
|||
responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use
|
||||
CloudStream 3 at your own risk.
|
||||
</string>
|
||||
<string name="general">Umum</string>
|
||||
<string name="category_general">Umum</string>
|
||||
<string name="random_button_settings">Tombol Acak</string>
|
||||
<string name="random_button_settings_desc">Tampilkan tombol acak di Beranda</string>
|
||||
<string name="provider_lang_settings">Bahasa provider</string>
|
||||
|
|
|
@ -181,7 +181,7 @@
|
|||
|
||||
<string name="search">Cerca</string>
|
||||
<string name="category_nginx">Nginx</string>
|
||||
<string name="category_credits">Accounts e Crediti</string>
|
||||
<string name="category_account">Accounts e Crediti</string>
|
||||
<string name="category_updates">Aggiornamenti e Backup</string>
|
||||
<string name="nginx_credentials_title">Credenziali Nginx</string>
|
||||
<string name="nginx_credentials_summary">È necessario utilizzare il seguente formato mycoolusername:mysecurepassword123</string>
|
||||
|
@ -328,7 +328,7 @@
|
|||
<string name="resize_zoom">Zoom</string>
|
||||
|
||||
<string name="legal_notice">Disclaimer</string>
|
||||
<string name="general">Generale</string>
|
||||
<string name="category_general">Generale</string>
|
||||
<string name="random_button_settings">Random</string>
|
||||
<string name="random_button_settings_desc">Mostra pulsante Random nella homepage</string>
|
||||
<string name="provider_lang_settings">Lingua provider</string>
|
||||
|
|
|
@ -220,7 +220,7 @@
|
|||
<string name="resize_zoom">Зумирај</string>
|
||||
|
||||
<string name="legal_notice">Disclaimer</string>
|
||||
<string name="general">Генерално</string>
|
||||
<string name="category_general">Генерално</string>
|
||||
<string name="provider_lang_settings">Јазици на провајдерите</string>
|
||||
<string name="app_layout">Распоред на апликацијата</string>
|
||||
<string name="preferred_media_settings">Претпочитани медиуми</string>
|
||||
|
|
|
@ -188,7 +188,7 @@
|
|||
<string name="resize_zoom">uhuoh o a ohahuhohoa hah</string>
|
||||
<string name="provider_lang_settings">ua hu ouo o aoau hah ah</string>
|
||||
<string name="legal_notice">ah huu oouhhau aoaoaaohoo ha</string>
|
||||
<string name="general">a ahu uoo uoahuo uo</string>
|
||||
<string name="category_general">a ahu uoo uoahuo uo</string>
|
||||
<string name="app_layout">uo u ohouao</string>
|
||||
<string name="automatic">uuoouhh hhuhuuh ouhoaao hau aouo</string>
|
||||
<string name="tv_layout">uha uh huo uooaah u</string>
|
||||
|
|
|
@ -221,7 +221,7 @@
|
|||
<string name="resize_fit">Tilpass til skjermen</string>
|
||||
<string name="resize_fill">Tøye ut</string>
|
||||
<string name="resize_zoom">Zoome</string>
|
||||
<string name="general">Grunnleggende</string>
|
||||
<string name="category_general">Grunnleggende</string>
|
||||
<string name="provider_lang_settings">Leverandør Språk</string>
|
||||
<string name="app_layout">App Oppsett</string>
|
||||
<string name="automatic">Automatisk</string>
|
||||
|
|
|
@ -270,7 +270,7 @@
|
|||
<string name="legal_notice">Zastrzeżenie</string>
|
||||
|
||||
<string name="provider_lang_settings">Języki dostawców</string>
|
||||
<string name="general">Ogólne</string>
|
||||
<string name="category_general">Ogólne</string>
|
||||
<string name="app_layout">Układ aplikacji</string>
|
||||
<string name="preferred_media_settings">Preferowane media</string>
|
||||
|
||||
|
|
|
@ -258,7 +258,7 @@
|
|||
responsabilidade do usuário de evitar qualquer ação que possa violar as leis que regem sua localidade. Utilizar
|
||||
CloudStream 3 por sua própria conta e risco.
|
||||
</string>
|
||||
<string name="general">Geral</string>
|
||||
<string name="category_general">Geral</string>
|
||||
<string name="provider_lang_settings">Idiomas dos Origems</string>
|
||||
<string name="app_layout">Layout do App</string>
|
||||
<string name="preferred_media_settings">Mídia preferida</string>
|
||||
|
|
|
@ -259,7 +259,7 @@
|
|||
responsabilitatea utilizatorului de a evita orice acțiune care ar putea încălca legile care guvernează localitatea sa. Utilizați
|
||||
CloudStream 3 pe propriul risc.
|
||||
</string>
|
||||
<string name="general">Generală</string>
|
||||
<string name="category_general">Generală</string>
|
||||
<string name="provider_lang_settings">Limbile Furnizorului</string>
|
||||
<string name="app_layout">Aranjament-ul Aplicației</string>
|
||||
<string name="preferred_media_settings">Media Preferată</string>
|
||||
|
|
|
@ -199,7 +199,7 @@
|
|||
<string name="resume">Återuppta</string>
|
||||
<string name="storage_error">Ett nerladdningsfel uppstod, kolla om appen har lagringsbehörigheter</string>
|
||||
<string name="watch_quality_pref">Föredragen videokvalitet</string>
|
||||
<string name="general">Allmänna Inställningar</string>
|
||||
<string name="category_general">Allmänna Inställningar</string>
|
||||
<string name="subs_font_size">Textstorlek</string>
|
||||
<string name="use_system_brightness_settings">Använd system ljusstyrka</string>
|
||||
<string name="use_system_brightness_settings_des">Använder systemets ljusstyrka instället för en svart överlaga</string>
|
||||
|
|
|
@ -231,7 +231,7 @@
|
|||
<string name="resize_fill">Punan ang buong screen</string>
|
||||
<string name="resize_zoom">Zoom</string>
|
||||
|
||||
<string name="general">Pangkalahatan</string>
|
||||
<string name="category_general">Pangkalahatan</string>
|
||||
<string name="provider_lang_settings">Lenggwahe ng Provider</string>
|
||||
<string name="app_layout">App Layout</string>
|
||||
<string name="automatic">Awtomatik</string>
|
||||
|
|
|
@ -344,7 +344,7 @@
|
|||
responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use
|
||||
CloudStream 3 at your own risk.
|
||||
</string>
|
||||
<string name="general">Genel</string>
|
||||
<string name="category_general">Genel</string>
|
||||
<string name="provider_lang_settings">Sağlayıcı Dilleri</string>
|
||||
<string name="app_layout">Uygulama Düzeni</string>
|
||||
<string name="preferred_media_settings">Tercih Edilen Medya</string>
|
||||
|
|
|
@ -243,7 +243,7 @@
|
|||
<string name="resize_fill">Kéo dãn</string>
|
||||
<string name="resize_zoom">Phóng to</string>
|
||||
|
||||
<string name="general">Tổng quan</string>
|
||||
<string name="category_general">Tổng quan</string>
|
||||
<string name="provider_lang_settings">Ngôn ngữ nhà cung cấp</string>
|
||||
<string name="app_layout">Giao diện App</string>
|
||||
<string name="preferred_media_settings">Thể loại ưu tiên</string>
|
||||
|
|
|
@ -306,7 +306,7 @@
|
|||
responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use
|
||||
CloudStream 3 at your own risk.
|
||||
</string>
|
||||
<string name="general">全局</string>
|
||||
<string name="category_general">全局</string>
|
||||
<string name="provider_lang_settings">内容提供者语言</string>
|
||||
<string name="app_layout">应用布局</string>
|
||||
<string name="preferred_media_settings">首选媒体</string>
|
||||
|
|
|
@ -35,9 +35,6 @@
|
|||
<string name="provider_lang_key" translatable="false">provider_lang_key</string>
|
||||
<string name="dns_key" translatable="false">dns_key</string>
|
||||
<string name="download_path_key" translatable="false">download_path_key</string>
|
||||
<string name="nginx_url_key" translatable="false">nginx_url_key</string>
|
||||
<string name="nginx_credentials" translatable="false">nginx_credentials</string>
|
||||
<string name="nginx_info" translatable="false">nginx_info</string>
|
||||
<string name="app_name_download_path" translatable="false">Cloudstream</string>
|
||||
<string name="app_layout_key" translatable="false">app_layout_key</string>
|
||||
<string name="primary_color_key" translatable="false">primary_color_key</string>
|
||||
|
@ -241,11 +238,8 @@
|
|||
<string name="backup_failed_error_format">Error backing up %s</string>
|
||||
|
||||
<string name="search">Search</string>
|
||||
<string name="category_nginx">Nginx</string>
|
||||
<string name="category_credits">Credits and account</string>
|
||||
<string name="category_account">Accounts</string>
|
||||
<string name="category_updates">Updates and backup</string>
|
||||
<string name="nginx_credentials_title">Nginx Credential</string>
|
||||
<string name="nginx_credentials_summary">You have to use the following format mycoolusername:mysecurepassword123</string>
|
||||
<string name="nginx_info_title">What is Nginx ?</string>
|
||||
<string name="nginx_info_summary">Nginx is a software that can be used to display files from a server that you own. Click to see a Nginx setup guide</string>
|
||||
|
||||
|
@ -414,15 +408,15 @@
|
|||
responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use
|
||||
CloudStream 3 at your own risk.
|
||||
</string>
|
||||
<string name="general">General</string>
|
||||
<string name="category_general">General</string>
|
||||
<string name="random_button_settings">Random Button</string>
|
||||
<string name="random_button_settings_desc">Show random button on Homepage</string>
|
||||
<string name="provider_lang_settings">Provider languages</string>
|
||||
<string name="app_layout">App Layout</string>
|
||||
<string name="preferred_media_settings">Preferred media</string>
|
||||
<string name="subtitles_encoding">Subtitle encoding</string>
|
||||
<string name="category_preferred_media_and_lang">Preferred media and language</string>
|
||||
<string name="category_ui">User interface</string>
|
||||
<string name="category_preferred_media_and_lang">Language</string>
|
||||
<string name="category_ui">Layout</string>
|
||||
|
||||
<string name="automatic">Auto</string>
|
||||
<string name="tv_layout">TV layout</string>
|
||||
|
@ -535,4 +529,5 @@
|
|||
<string name="error_invalid_id">Invalid id</string>
|
||||
<string name="subtitles_remove_captions">Remove closed captions from subtitles</string>
|
||||
<string name="subtitles_remove_bloat">Remove bloat from subtitles</string>
|
||||
<string name="extras">Extras</string>
|
||||
</resources>
|
||||
|
|
27
app/src/main/res/xml/settings_account.xml
Normal file
27
app/src/main/res/xml/settings_account.xml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<Preference
|
||||
android:key="@string/mal_key"
|
||||
android:icon="@drawable/mal_logo" />
|
||||
|
||||
<Preference
|
||||
android:key="@string/anilist_key"
|
||||
android:icon="@drawable/ic_anilist_icon" />
|
||||
<Preference
|
||||
android:key="@string/opensubtitles_key"
|
||||
android:icon="@drawable/open_subtitles_icon" />
|
||||
<Preference
|
||||
android:key="@string/nginx_key"
|
||||
android:icon="@drawable/nginx" />
|
||||
|
||||
<Preference
|
||||
android:title="@string/nginx_info_title"
|
||||
android:icon="@drawable/nginx_question"
|
||||
android:summary="@string/nginx_info_summary">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="https://www.sarlays.com/use-nginx-with-cloudstream/" />
|
||||
</Preference>
|
||||
|
||||
</PreferenceScreen>
|
|
@ -12,16 +12,6 @@
|
|||
android:icon="@drawable/ic_outline_subtitles_24"
|
||||
app:summary="@string/chromecast_subtitles_settings_des" />
|
||||
|
||||
<Preference
|
||||
android:key="@string/dns_key"
|
||||
android:title="@string/dns_pref"
|
||||
android:summary="@string/dns_pref_summary"
|
||||
android:icon="@drawable/ic_baseline_dns_24" />
|
||||
|
||||
<Preference
|
||||
android:key="@string/download_path_key"
|
||||
android:title="@string/download_path_pref"
|
||||
android:icon="@drawable/netflix_download" />
|
||||
|
||||
<Preference
|
||||
android:key="@string/quality_pref_key"
|
||||
|
|
|
@ -1,29 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<Preference
|
||||
android:key="@string/mal_key"
|
||||
android:icon="@drawable/mal_logo" />
|
||||
|
||||
<Preference
|
||||
android:key="@string/anilist_key"
|
||||
android:icon="@drawable/ic_anilist_icon" />
|
||||
<Preference
|
||||
android:key="@string/opensubtitles_key"
|
||||
android:icon="@drawable/open_subtitles_icon" />
|
||||
<Preference
|
||||
android:key="@string/nginx_key"
|
||||
android:icon="@drawable/nginx" />
|
||||
android:key="@string/dns_key"
|
||||
android:title="@string/dns_pref"
|
||||
android:summary="@string/dns_pref_summary"
|
||||
android:icon="@drawable/ic_baseline_dns_24" />
|
||||
|
||||
<Preference
|
||||
android:key="@string/nginx_info"
|
||||
android:title="@string/nginx_info_title"
|
||||
android:icon="@drawable/nginx_question"
|
||||
android:summary="@string/nginx_info_summary">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="https://www.sarlays.com/use-nginx-with-cloudstream/" />
|
||||
</Preference>
|
||||
android:key="@string/download_path_key"
|
||||
android:title="@string/download_path_pref"
|
||||
android:icon="@drawable/netflix_download" />
|
||||
|
||||
<Preference
|
||||
android:key="@string/legal_notice_key"
|
Loading…
Reference in a new issue