settings update

This commit is contained in:
LagradOst 2022-05-15 20:38:32 +02:00
parent 8d14046c4a
commit 88e1719085
27 changed files with 1655 additions and 1183 deletions

View file

@ -36,7 +36,7 @@ android {
targetSdkVersion 30
versionCode 47
versionName "2.9.25"
versionName "2.10.25"
resValue "string", "app_version",
"${defaultConfig.versionName}${versionNameSuffix ?: ""}"
@ -89,12 +89,13 @@ repositories {
dependencies {
implementation 'com.google.android.mediahome:video:1.0.0'
implementation 'androidx.test.ext:junit-ktx:1.1.3'
testImplementation 'org.json:json:20180813'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'com.google.android.material:material:1.5.0' // dont change this to 1.6.0 it looks ugly af
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.0-beta01'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.0-beta01'
@ -108,8 +109,6 @@ dependencies {
// implementation 'org.jsoup:jsoup:1.13.1'
// implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.12.3"
implementation "com.google.android.material:material:1.5.0"
implementation "androidx.preference:preference-ktx:1.2.0"
implementation 'com.github.bumptech.glide:glide:4.13.1'

View file

@ -128,7 +128,15 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
R.id.navigation_search,
R.id.navigation_downloads,
R.id.navigation_settings,
R.id.navigation_download_child
R.id.navigation_download_child,
R.id.navigation_subtitles,
R.id.navigation_chrome_subtitles,
R.id.navigation_settings_nginx,
R.id.navigation_settings_player,
R.id.navigation_settings_updates,
R.id.navigation_settings_ui,
R.id.navigation_settings_account,
R.id.navigation_settings_lang,
).contains(destination.id)
val landscape = when (resources.configuration.orientation) {

View file

@ -9,7 +9,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.NavHostFragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.R
@ -22,6 +21,7 @@ import com.lagradost.cloudstream3.utils.DOWNLOAD_EPISODE_CACHE
import com.lagradost.cloudstream3.utils.DataStore
import com.lagradost.cloudstream3.utils.UIHelper.fixPaddingStatusbar
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.UIHelper.navigate
import com.lagradost.cloudstream3.utils.VideoDownloadHelper
import com.lagradost.cloudstream3.utils.VideoDownloadManager
import kotlinx.android.synthetic.main.fragment_downloads.*
@ -57,7 +57,7 @@ class DownloadFragment : Fragment() {
}
override fun onDestroy() {
if(downloadDeleteEventListener != null) {
if (downloadDeleteEventListener != null) {
VideoDownloadManager.downloadDeleteEvent -= downloadDeleteEventListener!!
downloadDeleteEventListener = null
}
@ -80,17 +80,26 @@ class DownloadFragment : Fragment() {
}
observe(downloadsViewModel.availableBytes) {
download_free_txt?.text =
getString(R.string.storage_size_format).format(getString(R.string.free_storage), getBytesAsText(it))
getString(R.string.storage_size_format).format(
getString(R.string.free_storage),
getBytesAsText(it)
)
download_free?.setLayoutWidth(it)
}
observe(downloadsViewModel.usedBytes) {
download_used_txt?.text =
getString(R.string.storage_size_format).format(getString(R.string.used_storage), getBytesAsText(it))
getString(R.string.storage_size_format).format(
getString(R.string.used_storage),
getBytesAsText(it)
)
download_used?.setLayoutWidth(it)
}
observe(downloadsViewModel.downloadBytes) {
download_app_txt?.text =
getString(R.string.storage_size_format).format(getString(R.string.app_storage), getBytesAsText(it))
getString(R.string.storage_size_format).format(
getString(R.string.app_storage),
getBytesAsText(it)
)
download_app?.setLayoutWidth(it)
download_storage_appbar?.visibility = View.VISIBLE
}
@ -112,16 +121,21 @@ class DownloadFragment : Fragment() {
if (click.data.type.isMovieType()) {
//wont be called
} else {
val folder = DataStore.getFolderName(DOWNLOAD_EPISODE_CACHE, click.data.id.toString())
val navHostFragment = activity?.supportFragmentManager?.findFragmentById(R.id.nav_host_fragment) as? NavHostFragment?
navHostFragment?.navController?.navigate(
R.id.navigation_download_child,
val folder = DataStore.getFolderName(
DOWNLOAD_EPISODE_CACHE,
click.data.id.toString()
)
activity?.navigate(
R.id.action_navigation_downloads_to_navigation_download_child,
DownloadChildFragment.newInstance(click.data.name, folder)
)
}
}
1 -> {
(activity as AppCompatActivity?)?.loadResult(click.data.url, click.data.apiName)
(activity as AppCompatActivity?)?.loadResult(
click.data.url,
click.data.apiName
)
}
}

View file

@ -1027,7 +1027,6 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
// init variables
setPlayBackSpeed(getKey(PLAYBACK_SPEED_KEY) ?: 1.0f)
fastForwardTime = getKey(PLAYBACK_FASTFORWARD) ?: 10000L
// handle tv controls
playerEventListener = { eventType ->
@ -1086,6 +1085,10 @@ open class FullScreenPlayer : AbstractPlayerFragment() {
context?.let { ctx ->
val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)
fastForwardTime =
settingsManager.getInt(ctx.getString(R.string.double_tap_seek_time_key), 10)
.toLong() * 1000L
navigationBarHeight = ctx.getNavigationBarHeight()
statusBarHeight = ctx.getStatusBarHeight()

View file

@ -52,6 +52,9 @@ class GeneratorPlayer : FullScreenPlayer() {
}
}
private var titleRez = 3
private var limitTitle = 0
private lateinit var viewModel: PlayerGeneratorViewModel //by activityViewModels()
private lateinit var sync: SyncViewModel
private var currentLinks: Set<Pair<ExtractorLink?, ExtractorUri?>> = setOf()
@ -550,12 +553,7 @@ class GeneratorPlayer : FullScreenPlayer() {
tvType = meta.tvType
}
}
//Get limit of characters on Video Title
var limitTitle = 0
context?.let {
val settingsManager = PreferenceManager.getDefaultSharedPreferences(it)
limitTitle = settingsManager.getInt(getString(R.string.prefer_limit_title_key), 0)
}
//Generate video title
var playerVideoTitle = if (headerName != null) {
(headerName +
@ -577,7 +575,7 @@ class GeneratorPlayer : FullScreenPlayer() {
val differenceInLength = playerVideoTitle.length - limitTitle
val margin = 3 //If the difference is smaller than or equal to this value, ignore it
if (limitTitle > 0 && differenceInLength > margin) {
playerVideoTitle = playerVideoTitle.substring(0, limitTitle-1) + "..."
playerVideoTitle = playerVideoTitle.substring(0, limitTitle - 1) + "..."
}
}
@ -589,13 +587,21 @@ class GeneratorPlayer : FullScreenPlayer() {
fun setPlayerDimen(widthHeight: Pair<Int, Int>?) {
val extra = if (widthHeight != null) {
val (width, height) = widthHeight
" - ${width}x${height}"
"${width}x${height}"
} else {
""
}
player_video_title_rez?.text =
(currentSelectedLink?.first?.name ?: currentSelectedLink?.second?.name
?: "NULL") + extra
val source = currentSelectedLink?.first?.name ?: currentSelectedLink?.second?.name
?: "NULL"
player_video_title_rez?.text = when (titleRez) {
0 -> ""
1 -> extra
2 -> source
3 -> "$source - $extra"
else -> ""
}
}
override fun playerDimensionsLoaded(widthHeight: Pair<Int, Int>) {
@ -631,6 +637,12 @@ class GeneratorPlayer : FullScreenPlayer() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
context?.let { ctx ->
val settingsManager = PreferenceManager.getDefaultSharedPreferences(ctx)
titleRez = settingsManager.getInt(getString(R.string.prefer_limit_title_rez_key), 3)
limitTitle = settingsManager.getInt(getString(R.string.prefer_limit_title_key), 0)
}
unwrapBundle(savedInstanceState)
unwrapBundle(arguments)

View file

@ -57,7 +57,7 @@ const val PLAYBACK_SPEED = "playback_speed"
const val RESIZE_MODE_KEY = "resize_mode" // Last used resize mode
const val PLAYBACK_SPEED_KEY = "playback_speed" // Last used playback speed
const val PREFERRED_SUBS_KEY = "preferred_subtitles" // Last used resize mode
const val PLAYBACK_FASTFORWARD = "playback_fastforward" // Last used resize mode
//const val PLAYBACK_FASTFORWARD = "playback_fastforward" // Last used resize mode
/** Abstract Exoplayer logic, can be expanded to other players */
interface IPlayer {

View file

@ -1729,13 +1729,11 @@ class ResultFragment : Fragment(), PanelsChildGestureRegionObserver.GestureRegio
setRecommendations(d.recommendations, null)
setActors(d.actors)
if (SettingsFragment.accountEnabled) {
if (syncModel.addSyncs(d.syncData)) {
syncModel.updateMetaAndUser()
syncModel.updateSynced()
} else {
syncModel.addFromUrl(d.url)
}
if (syncModel.addSyncs(d.syncData)) {
syncModel.updateMetaAndUser()
syncModel.updateSynced()
} else {
syncModel.addFromUrl(d.url)
}
result_meta_site?.text = d.apiName

View file

@ -0,0 +1,149 @@
package com.lagradost.cloudstream3.ui.settings
import android.content.Context
import android.os.Bundle
import android.widget.ImageView
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.syncproviders.AccountManager
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.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.UIHelper.setImage
class SettingsAccount : PreferenceFragmentCompat() {
private fun showLoginInfo(api: AccountManager, info: OAuth2API.LoginInfo) {
val builder =
AlertDialog.Builder(context ?: return, R.style.AlertDialogCustom)
.setView(R.layout.account_managment)
val dialog = builder.show()
dialog.findViewById<ImageView>(R.id.account_profile_picture)?.setImage(info.profilePicture)
dialog.findViewById<TextView>(R.id.account_logout)?.setOnClickListener {
api.logOut()
dialog.dismissSafe(activity)
}
(info.name ?: context?.getString(R.string.no_data))?.let {
dialog.findViewById<TextView>(R.id.account_name)?.text = it
}
dialog.findViewById<TextView>(R.id.account_site)?.text = api.name
dialog.findViewById<TextView>(R.id.account_switch_account)?.setOnClickListener {
dialog.dismissSafe(activity)
showAccountSwitch(it.context, api)
}
}
private fun showAccountSwitch(context: Context, api: AccountManager) {
val accounts = api.getAccounts() ?: return
val builder =
AlertDialog.Builder(context, R.style.AlertDialogCustom).setView(R.layout.account_switch)
val dialog = builder.show()
dialog.findViewById<TextView>(R.id.account_add)?.setOnClickListener {
try {
api.authenticate()
} catch (e: Exception) {
logError(e)
}
}
val ogIndex = api.accountIndex
val items = ArrayList<OAuth2API.LoginInfo>()
for (index in accounts) {
api.accountIndex = index
val accountInfo = api.loginInfo()
if (accountInfo != null) {
items.add(accountInfo)
}
}
api.accountIndex = ogIndex
val adapter = AccountAdapter(items, R.layout.account_single) {
dialog?.dismissSafe(activity)
api.changeAccount(it.card.accountIndex)
}
val list = dialog.findViewById<RecyclerView>(R.id.account_list)
list?.adapter = adapter
}
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
}
val syncApis =
listOf(
Pair(R.string.mal_key, OAuth2API.malApi), Pair(
R.string.anilist_key,
OAuth2API.aniListApi
)
)
for ((key, api) in syncApis) {
getPref(key)?.apply {
title =
getString(R.string.login_format).format(api.name, getString(R.string.account))
setOnPreferenceClickListener { _ ->
val info = api.loginInfo()
if (info != null) {
showLoginInfo(api, info)
} else {
try {
api.authenticate()
} catch (e: Exception) {
logError(e)
}
}
return@setOnPreferenceClickListener true
}
}
}
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()
}
}
}

View file

@ -1,75 +1,52 @@
package com.lagradost.cloudstream3.ui.settings
import android.app.UiModeManager
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.content.Intent
import android.content.res.Configuration
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.RecyclerView
import com.hippo.unifile.UniFile
import com.lagradost.cloudstream3.APIHolder.apis
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
import com.lagradost.cloudstream3.AcraApplication
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
import com.lagradost.cloudstream3.CommonActivity.setLocale
import com.lagradost.cloudstream3.CommonActivity.showToast
import com.lagradost.cloudstream3.DubStatus
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.syncproviders.AccountManager
import com.lagradost.cloudstream3.syncproviders.OAuth2API
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.aniListApi
import com.lagradost.cloudstream3.syncproviders.OAuth2API.Companion.malApi
import com.lagradost.cloudstream3.ui.APIRepository
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
import com.lagradost.cloudstream3.ui.subtitles.ChromecastSubtitlesFragment
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
import com.lagradost.cloudstream3.utils.BackupUtils.backup
import com.lagradost.cloudstream3.utils.BackupUtils.restorePrompt
import com.lagradost.cloudstream3.utils.HOMEPAGE_API
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
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.SingleSelectionHelper.showMultiDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showNginxTextInputDialog
import com.lagradost.cloudstream3.utils.SubtitleHelper
import com.lagradost.cloudstream3.utils.SubtitleHelper.getFlagFromIso
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.UIHelper.setImage
import com.lagradost.cloudstream3.utils.VideoDownloadManager
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getBasePath
import com.lagradost.cloudstream3.utils.VideoDownloadManager.getDownloadDir
import kotlinx.android.synthetic.main.logcat.*
import okhttp3.internal.closeQuietly
import java.io.BufferedReader
import com.lagradost.cloudstream3.utils.UIHelper.navigate
import kotlinx.android.synthetic.main.main_settings.*
import java.io.File
import java.io.InputStreamReader
import java.io.OutputStream
import kotlin.concurrent.thread
class SettingsFragment : PreferenceFragmentCompat() {
class SettingsFragment : Fragment() {
companion object {
var beneneCount = 0
fun PreferenceFragmentCompat?.getPref(id: Int): Preference? {
if (this == null) return null
return try {
findPreference(getString(id))
} catch (e: Exception) {
logError(e)
null
}
}
fun getFolderSize(dir: File): Long {
var size: Long = 0
dir.listFiles()?.let {
for (file in it) {
size += if (file.isFile) {
// System.out.println(file.getName() + " " + file.length());
file.length()
} else getFolderSize(file)
}
}
return size
}
private fun Context.getLayoutInt(): Int {
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
return settingsManager.getInt(this.getString(R.string.app_layout_key), -1)
@ -98,762 +75,47 @@ class SettingsFragment : PreferenceFragmentCompat() {
private fun Context.isAutoTv(): Boolean {
val uiModeManager = getSystemService(Context.UI_MODE_SERVICE) as UiModeManager?
// AFT = Fire TV
return uiModeManager?.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION || Build.MODEL.contains("AFT")
}
const val accountEnabled = true
}
private var beneneCount = 0
// 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()
}
}
// idk, if you find a way of automating this it would be great
// https://www.iemoji.com/view/emoji/1794/flags/antarctica
// Emoji Character Encoding Data --> C/C++/Java Src
// https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes leave blank for auto
private val languages = arrayListOf(
Triple("", "Spanish", "es"),
Triple("", "English", "en"),
Triple("", "Viet Nam", "vi"),
Triple("", "Dutch", "nl"),
Triple("", "French", "fr"),
Triple("", "Greek", "el"),
Triple("", "Swedish", "sv"),
Triple("", "Tagalog", "tl"),
Triple("", "Polish", "pl"),
Triple("", "Hindi", "hi"),
Triple("", "Malayalam", "ml"),
Triple("", "Norsk", "no"),
Triple("", "German", "de"),
Triple("", "Arabic", "ar"),
Triple("", "Turkish", "tr"),
Triple("", "Macedonian", "mk"),
Triple("", "Portuguese (Brazil)", "pt"),
Triple("", "Romanian", "ro"),
Triple("", "Italian", "it"),
Triple("", "Chinese", "zh"),
).sortedBy { it.second } //ye, we go alphabetical, so ppl don't put their lang on top
private fun showAccountSwitch(context: Context, api: AccountManager) {
val accounts = api.getAccounts() ?: return
val builder =
AlertDialog.Builder(context, R.style.AlertDialogCustom).setView(R.layout.account_switch)
val dialog = builder.show()
dialog.findViewById<TextView>(R.id.account_add)?.setOnClickListener {
try {
api.authenticate()
} catch (e: Exception) {
logError(e)
}
}
val ogIndex = api.accountIndex
val items = ArrayList<OAuth2API.LoginInfo>()
for (index in accounts) {
api.accountIndex = index
val accountInfo = api.loginInfo()
if (accountInfo != null) {
items.add(accountInfo)
}
}
api.accountIndex = ogIndex
val adapter = AccountAdapter(items, R.layout.account_single) {
dialog?.dismissSafe(activity)
api.changeAccount(it.card.accountIndex)
}
val list = dialog.findViewById<RecyclerView>(R.id.account_list)
list?.adapter = adapter
}
private fun showLoginInfo(api: AccountManager, info: OAuth2API.LoginInfo) {
val builder =
AlertDialog.Builder(context ?: return, R.style.AlertDialogCustom)
.setView(R.layout.account_managment)
val dialog = builder.show()
dialog.findViewById<ImageView>(R.id.account_profile_picture)?.setImage(info.profilePicture)
dialog.findViewById<TextView>(R.id.account_logout)?.setOnClickListener {
api.logOut()
dialog.dismissSafe(activity)
}
(info.name ?: context?.getString(R.string.no_data))?.let {
dialog.findViewById<TextView>(R.id.account_name)?.text = it
}
dialog.findViewById<TextView>(R.id.account_site)?.text = api.name
dialog.findViewById<TextView>(R.id.account_switch_account)?.setOnClickListener {
dialog.dismissSafe(activity)
showAccountSwitch(it.context, api)
return uiModeManager?.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION || Build.MODEL.contains(
"AFT"
)
}
}
private fun getPref(id: Int): Preference? {
return try {
findPreference(getString(id))
} catch (e: Exception) {
logError(e)
null
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
return inflater.inflate(R.layout.main_settings, container, false)
}
private fun getFolderSize(dir: File): Long {
var size: Long = 0
dir.listFiles()?.let {
for (file in it) {
size += if (file.isFile) {
// System.out.println(file.getName() + " " + file.length());
file.length()
} else getFolderSize(file)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
fun navigate(id: Int) {
activity?.navigate(id, Bundle())
}
return size
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
hideKeyboard()
setPreferencesFromResource(R.xml.settings, rootKey)
val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())
getPref(R.string.video_buffer_length_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.video_buffer_length_names)
val prefValues = resources.getIntArray(R.array.video_buffer_length_values)
val currentPrefSize =
settingsManager.getInt(getString(R.string.video_buffer_length_key), 0)
activity?.showDialog(
prefNames.toList(),
prefValues.indexOf(currentPrefSize),
getString(R.string.video_buffer_length_settings),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.video_buffer_length_key), prefValues[it])
.apply()
}
return@setOnPreferenceClickListener true
settings_player?.setOnClickListener {
navigate(R.id.action_navigation_settings_to_navigation_settings_player)
}
getPref(R.string.video_buffer_size_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.video_buffer_size_names)
val prefValues = resources.getIntArray(R.array.video_buffer_size_values)
val currentPrefSize =
settingsManager.getInt(getString(R.string.video_buffer_size_key), 0)
activity?.showDialog(
prefNames.toList(),
prefValues.indexOf(currentPrefSize),
getString(R.string.video_buffer_size_settings),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.video_buffer_size_key), prefValues[it])
.apply()
}
return@setOnPreferenceClickListener true
settings_credits?.setOnClickListener {
navigate(R.id.action_navigation_settings_to_navigation_settings_account)
}
getPref(R.string.video_buffer_clear_key)?.let { pref ->
val cacheDir = context?.cacheDir ?: return@let
fun updateSummery() {
try {
pref.summary =
getString(R.string.mb_format).format(getFolderSize(cacheDir) / (1024L * 1024L))
} catch (e: Exception) {
logError(e)
}
}
updateSummery()
pref.setOnPreferenceClickListener {
try {
cacheDir.deleteRecursively()
updateSummery()
} catch (e: Exception) {
logError(e)
}
return@setOnPreferenceClickListener true
}
settings_ui?.setOnClickListener {
navigate(R.id.action_navigation_settings_to_navigation_settings_ui)
}
getPref(R.string.video_buffer_disk_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.video_buffer_size_names)
val prefValues = resources.getIntArray(R.array.video_buffer_size_values)
val currentPrefSize =
settingsManager.getInt(getString(R.string.video_buffer_disk_key), 0)
activity?.showDialog(
prefNames.toList(),
prefValues.indexOf(currentPrefSize),
getString(R.string.video_buffer_disk_settings),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.video_buffer_disk_key), prefValues[it])
.apply()
}
return@setOnPreferenceClickListener true
settings_lang?.setOnClickListener {
navigate(R.id.action_navigation_settings_to_navigation_settings_lang)
}
getPref(R.string.subtitle_settings_key)?.setOnPreferenceClickListener {
SubtitlesFragment.push(activity, false)
return@setOnPreferenceClickListener true
settings_nginx?.setOnClickListener {
navigate(R.id.action_navigation_settings_to_navigation_settings_nginx)
}
getPref(R.string.subtitle_settings_chromecast_key)?.setOnPreferenceClickListener {
ChromecastSubtitlesFragment.push(activity, false)
return@setOnPreferenceClickListener true
}
getPref(R.string.poster_ui_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.poster_ui_options)
val keys = resources.getStringArray(R.array.poster_ui_options_values)
val prefValues = keys.map {
settingsManager.getBoolean(it, true)
}.mapIndexedNotNull { index, b ->
if (b) {
index
} else null
}
activity?.showMultiDialog(
prefNames.toList(),
prefValues,
getString(R.string.poster_ui_settings),
{}) { list ->
val edit = settingsManager.edit()
for ((i, key) in keys.withIndex()) {
edit.putBoolean(key, list.contains(i))
}
edit.apply()
SearchResultBuilder.updateCache(it.context)
}
return@setOnPreferenceClickListener true
}
val syncApis =
listOf(Pair(R.string.mal_key, malApi), Pair(R.string.anilist_key, aniListApi))
for ((key, api) in syncApis) {
getPref(key)?.apply {
isVisible = accountEnabled
title =
getString(R.string.login_format).format(api.name, getString(R.string.account))
setOnPreferenceClickListener { _ ->
val info = api.loginInfo()
if (info != null) {
showLoginInfo(api, info)
} else {
try {
api.authenticate()
} catch (e: Exception) {
logError(e)
}
}
return@setOnPreferenceClickListener true
}
}
}
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
}
getPref(R.string.display_sub_key)?.setOnPreferenceClickListener {
activity?.getApiDubstatusSettings()?.let { current ->
val dublist = DubStatus.values()
val names = dublist.map { it.name }
val currentList = ArrayList<Int>()
for (i in current) {
currentList.add(dublist.indexOf(i))
}
activity?.showMultiDialog(
names,
currentList,
getString(R.string.display_subbed_dubbed_settings),
{}) { selectedList ->
APIRepository.dubStatusActive = selectedList.map { dublist[it] }.toHashSet()
settingsManager.edit().putStringSet(
this.getString(R.string.display_sub_key),
selectedList.map { names[it] }.toMutableSet()
).apply()
}
}
return@setOnPreferenceClickListener true
}
getPref(R.string.provider_lang_key)?.setOnPreferenceClickListener {
activity?.getApiProviderLangSettings()?.let { current ->
val allLangs = HashSet<String>()
for (api in apis) {
allLangs.add(api.lang)
}
val currentList = ArrayList<Int>()
for (i in current) {
currentList.add(allLangs.indexOf(i))
}
val names = allLangs.map {
val emoji = getFlagFromIso(it)
val name = SubtitleHelper.fromTwoLettersToLanguage(it)
val fullName = "$emoji $name"
Pair(it, fullName)
}
activity?.showMultiDialog(
names.map { it.second },
currentList,
getString(R.string.provider_lang_settings),
{}) { selectedList ->
settingsManager.edit().putStringSet(
this.getString(R.string.provider_lang_key),
selectedList.map { names[it].first }.toMutableSet()
).apply()
//APIRepository.providersActive = it.context.getApiSettings()
}
}
return@setOnPreferenceClickListener true
}
fun getDownloadDirs(): List<String> {
return normalSafeApiCall {
val defaultDir = 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)
?: 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
}
getPref(R.string.nginx_url_key)?.setOnPreferenceClickListener {
activity?.showNginxTextInputDialog(
settingsManager.getString(getString(R.string.nginx_url_pref), "Nginx server url")
.toString(),
settingsManager.getString(getString(R.string.nginx_url_key), "")
.toString(), // key: the actual you use rn
android.text.InputType.TYPE_TEXT_VARIATION_URI, // uri
{}) {
settingsManager.edit()
.putString(getString(R.string.nginx_url_key), it)
.apply() // change the stored url in nginx_url_key to it
}
return@setOnPreferenceClickListener true
}
getPref(R.string.nginx_credentials)?.setOnPreferenceClickListener {
activity?.showNginxTextInputDialog(
settingsManager.getString(
getString(R.string.nginx_credentials_title),
"Nginx Credentials"
).toString(),
settingsManager.getString(getString(R.string.nginx_credentials), "")
.toString(), // key: the actual you use rn
android.text.InputType.TYPE_TEXT_VARIATION_URI,
{}) {
settingsManager.edit()
.putString(getString(R.string.nginx_credentials), it)
.apply() // change the stored url in nginx_url_key to it
}
return@setOnPreferenceClickListener true
}
getPref(R.string.prefer_media_type_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.media_type_pref)
val prefValues = resources.getIntArray(R.array.media_type_pref_values)
val currentPrefMedia =
settingsManager.getInt(getString(R.string.prefer_media_type_key), 0)
activity?.showBottomDialog(
prefNames.toList(),
prefValues.indexOf(currentPrefMedia),
getString(R.string.preferred_media_settings),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.prefer_media_type_key), prefValues[it])
.apply()
removeKey(HOMEPAGE_API)
(context ?: AcraApplication.context)?.let { ctx -> app.initClient(ctx) }
}
return@setOnPreferenceClickListener true
}
getPref(R.string.show_logcat_key)?.setOnPreferenceClickListener { pref ->
val builder =
AlertDialog.Builder(pref.context, R.style.AlertDialogCustom)
.setView(R.layout.logcat)
val dialog = builder.create()
dialog.show()
val log = StringBuilder()
try {
//https://developer.android.com/studio/command-line/logcat
val process = Runtime.getRuntime().exec("logcat -d")
val bufferedReader = BufferedReader(
InputStreamReader(process.inputStream)
)
var line: String?
while (bufferedReader.readLine().also { line = it } != null) {
log.append(line)
}
} catch (e: Exception) {
logError(e) // kinda ironic
}
val text = log.toString()
dialog.text1?.text = text
dialog.copy_btt?.setOnClickListener {
val serviceClipboard =
(activity?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager?)
?: return@setOnClickListener
val clip = ClipData.newPlainText("logcat", text)
serviceClipboard.setPrimaryClip(clip)
dialog.dismissSafe(activity)
}
dialog.clear_btt?.setOnClickListener {
Runtime.getRuntime().exec("logcat -c")
dialog.dismissSafe(activity)
}
dialog.save_btt?.setOnClickListener {
var fileStream: OutputStream? = null
try {
fileStream =
VideoDownloadManager.setupStream(
it.context,
"logcat",
null,
"txt",
false
).fileStream
fileStream?.writer()?.write(text)
} catch (e: Exception) {
logError(e)
} finally {
fileStream?.closeQuietly()
dialog.dismissSafe(activity)
}
}
dialog.close_btt?.setOnClickListener {
dialog.dismissSafe(activity)
}
return@setOnPreferenceClickListener true
}
getPref(R.string.app_layout_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.app_layout)
val prefValues = resources.getIntArray(R.array.app_layout_values)
val currentLayout =
settingsManager.getInt(getString(R.string.app_layout_key), -1)
activity?.showBottomDialog(
prefNames.toList(),
prefValues.indexOf(currentLayout),
getString(R.string.app_layout),
true,
{}) {
try {
settingsManager.edit()
.putInt(getString(R.string.app_layout_key), prefValues[it])
.apply()
activity?.recreate()
} catch (e: Exception) {
logError(e)
}
}
return@setOnPreferenceClickListener true
}
getPref(R.string.backup_key)?.setOnPreferenceClickListener {
activity?.backup()
return@setOnPreferenceClickListener true
}
getPref(R.string.restore_key)?.setOnPreferenceClickListener {
activity?.restorePrompt()
return@setOnPreferenceClickListener true
}
getPref(R.string.primary_color_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.themes_overlay_names)
val prefValues = resources.getStringArray(R.array.themes_overlay_names_values)
val currentLayout =
settingsManager.getString(getString(R.string.primary_color_key), prefValues.first())
activity?.showDialog(
prefNames.toList(),
prefValues.indexOf(currentLayout),
getString(R.string.primary_color_settings),
true,
{}) {
try {
settingsManager.edit()
.putString(getString(R.string.primary_color_key), prefValues[it])
.apply()
activity?.recreate()
} catch (e: Exception) {
logError(e)
}
}
return@setOnPreferenceClickListener true
}
getPref(R.string.app_theme_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.themes_names)
val prefValues = resources.getStringArray(R.array.themes_names_values)
val currentLayout =
settingsManager.getString(getString(R.string.app_theme_key), prefValues.first())
activity?.showBottomDialog(
prefNames.toList(),
prefValues.indexOf(currentLayout),
getString(R.string.app_theme_settings),
true,
{}) {
try {
settingsManager.edit()
.putString(getString(R.string.app_theme_key), prefValues[it])
.apply()
activity?.recreate()
} catch (e: Exception) {
logError(e)
}
}
return@setOnPreferenceClickListener true
}
getPref(R.string.quality_pref_key)?.setOnPreferenceClickListener {
val prefValues = Qualities.values().map { it.value }.reversed().toMutableList()
prefValues.remove(Qualities.Unknown.value)
val prefNames = prefValues.map { Qualities.getStringByInt(it) }
val currentQuality =
settingsManager.getInt(
getString(R.string.quality_pref_key),
Qualities.values().last().value
)
activity?.showBottomDialog(
prefNames.toList(),
prefValues.indexOf(currentQuality),
getString(R.string.watch_quality_pref),
true,
{}) {
settingsManager.edit().putInt(getString(R.string.quality_pref_key), prefValues[it])
.apply()
}
return@setOnPreferenceClickListener true
}
getPref(R.string.prefer_limit_title_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.limit_title_pref_names)
val prefValues = resources.getIntArray(R.array.limit_title_pref_values)
val current = settingsManager.getInt(getString(R.string.prefer_limit_title_key), 0)
activity?.showBottomDialog(
prefNames.toList(),
prefValues.indexOf(current),
getString(R.string.limit_title),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.prefer_limit_title_key), prefValues[it])
.apply()
}
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
}
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()
}
getPref(R.string.manual_check_update_key)?.setOnPreferenceClickListener {
thread {
if (!requireActivity().runAutoUpdate(false)) {
activity?.runOnUiThread {
showToast(activity, R.string.no_update_found, Toast.LENGTH_SHORT)
}
}
}
return@setOnPreferenceClickListener true
}
getPref(R.string.locale_key)?.setOnPreferenceClickListener { pref ->
val tempLangs = languages.toMutableList()
if (beneneCount > 100) {
tempLangs.add(Triple("\uD83E\uDD8D", "mmmm... monke", "mo"))
}
val current = getCurrentLocale()
val languageCodes = tempLangs.map { it.third }
val languageNames = tempLangs.map { (emoji, name, iso) ->
val flag = emoji.ifBlank { getFlagFromIso(iso) ?: "ERROR" }
"$flag $name"
}
val index = languageCodes.indexOf(current)
activity?.showDialog(
languageNames, index, getString(R.string.app_language), true, { }
) { languageIndex ->
try {
val code = languageCodes[languageIndex]
setLocale(activity, code)
settingsManager.edit().putString(getString(R.string.locale_key), code).apply()
activity?.recreate()
} catch (e: Exception) {
logError(e)
}
}
return@setOnPreferenceClickListener true
settings_updates?.setOnClickListener {
navigate(R.id.action_navigation_settings_to_navigation_settings_updates)
}
}
private fun getCurrentLocale(): String {
val res = requireContext().resources
// Change locale settings in the app.
// val dm = res.displayMetrics
val conf = res.configuration
return conf?.locale?.language ?: "en"
}
}
}

View file

@ -0,0 +1,175 @@
package com.lagradost.cloudstream3.ui.settings
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
import com.lagradost.cloudstream3.APIHolder.getApiProviderLangSettings
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.network.initClient
import com.lagradost.cloudstream3.ui.APIRepository
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
import com.lagradost.cloudstream3.utils.HOMEPAGE_API
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog
import com.lagradost.cloudstream3.utils.SubtitleHelper
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
class SettingsLang : PreferenceFragmentCompat() {
// idk, if you find a way of automating this it would be great
// https://www.iemoji.com/view/emoji/1794/flags/antarctica
// Emoji Character Encoding Data --> C/C++/Java Src
// https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes leave blank for auto
private val languages = arrayListOf(
Triple("", "Spanish", "es"),
Triple("", "English", "en"),
Triple("", "Viet Nam", "vi"),
Triple("", "Dutch", "nl"),
Triple("", "French", "fr"),
Triple("", "Greek", "el"),
Triple("", "Swedish", "sv"),
Triple("", "Tagalog", "tl"),
Triple("", "Polish", "pl"),
Triple("", "Hindi", "hi"),
Triple("", "Malayalam", "ml"),
Triple("", "Norsk", "no"),
Triple("", "German", "de"),
Triple("", "Arabic", "ar"),
Triple("", "Turkish", "tr"),
Triple("", "Macedonian", "mk"),
Triple("\uD83C\uDDE7\uD83C\uDDF7", "Portuguese (Brazil)", "pt"),
Triple("", "Romanian", "ro"),
Triple("", "Italian", "it"),
Triple("", "Chinese", "zh"),
).sortedBy { it.second } //ye, we go alphabetical, so ppl don't put their lang on top
private fun getCurrentLocale(): String {
val res = requireContext().resources
// Change locale settings in the app.
// val dm = res.displayMetrics
val conf = res.configuration
return conf?.locale?.language ?: "en"
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
hideKeyboard()
setPreferencesFromResource(R.xml.settings_media_lang, rootKey)
val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())
getPref(R.string.display_sub_key)?.setOnPreferenceClickListener {
activity?.getApiDubstatusSettings()?.let { current ->
val dublist = DubStatus.values()
val names = dublist.map { it.name }
val currentList = ArrayList<Int>()
for (i in current) {
currentList.add(dublist.indexOf(i))
}
activity?.showMultiDialog(
names,
currentList,
getString(R.string.display_subbed_dubbed_settings),
{}) { selectedList ->
APIRepository.dubStatusActive = selectedList.map { dublist[it] }.toHashSet()
settingsManager.edit().putStringSet(
this.getString(R.string.display_sub_key),
selectedList.map { names[it] }.toMutableSet()
).apply()
}
}
return@setOnPreferenceClickListener true
}
getPref(R.string.prefer_media_type_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.media_type_pref)
val prefValues = resources.getIntArray(R.array.media_type_pref_values)
val currentPrefMedia =
settingsManager.getInt(getString(R.string.prefer_media_type_key), 0)
activity?.showBottomDialog(
prefNames.toList(),
prefValues.indexOf(currentPrefMedia),
getString(R.string.preferred_media_settings),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.prefer_media_type_key), prefValues[it])
.apply()
AcraApplication.removeKey(HOMEPAGE_API)
(context ?: AcraApplication.context)?.let { ctx -> app.initClient(ctx) }
}
return@setOnPreferenceClickListener true
}
getPref(R.string.locale_key)?.setOnPreferenceClickListener { pref ->
val tempLangs = languages.toMutableList()
//if (beneneCount > 100) {
// tempLangs.add(Triple("\uD83E\uDD8D", "mmmm... monke", "mo"))
//}
val current = getCurrentLocale()
val languageCodes = tempLangs.map { it.third }
val languageNames = tempLangs.map { (emoji, name, iso) ->
val flag = emoji.ifBlank { SubtitleHelper.getFlagFromIso(iso) ?: "ERROR" }
"$flag $name"
}
val index = languageCodes.indexOf(current)
activity?.showDialog(
languageNames, index, getString(R.string.app_language), true, { }
) { languageIndex ->
try {
val code = languageCodes[languageIndex]
CommonActivity.setLocale(activity, code)
settingsManager.edit().putString(getString(R.string.locale_key), code).apply()
activity?.recreate()
} catch (e: Exception) {
logError(e)
}
}
return@setOnPreferenceClickListener true
}
getPref(R.string.provider_lang_key)?.setOnPreferenceClickListener {
activity?.getApiProviderLangSettings()?.let { current ->
val allLangs = HashSet<String>()
for (api in APIHolder.apis) {
allLangs.add(api.lang)
}
val currentList = ArrayList<Int>()
for (i in current) {
currentList.add(allLangs.indexOf(i))
}
val names = allLangs.map {
val emoji = SubtitleHelper.getFlagFromIso(it)
val name = SubtitleHelper.fromTwoLettersToLanguage(it)
val fullName = "$emoji $name"
Pair(it, fullName)
}
activity?.showMultiDialog(
names.map { it.second },
currentList,
getString(R.string.provider_lang_settings),
{}) { selectedList ->
settingsManager.edit().putStringSet(
this.getString(R.string.provider_lang_key),
selectedList.map { names[it].first }.toMutableSet()
).apply()
//APIRepository.providersActive = it.context.getApiSettings()
}
}
return@setOnPreferenceClickListener true
}
}
}

View file

@ -0,0 +1,54 @@
package com.lagradost.cloudstream3.ui.settings
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.lagradost.cloudstream3.AcraApplication
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.network.initClient
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
import com.lagradost.cloudstream3.utils.HOMEPAGE_API
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showNginxTextInputDialog
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
class SettingsNginx : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
hideKeyboard()
setPreferencesFromResource(R.xml.settings_nginx, rootKey)
val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())
getPref(R.string.nginx_credentials)?.setOnPreferenceClickListener {
activity?.showNginxTextInputDialog(
settingsManager.getString(
getString(R.string.nginx_credentials_title),
"Nginx Credentials"
).toString(),
settingsManager.getString(getString(R.string.nginx_credentials), "")
.toString(), // key: the actual you use rn
android.text.InputType.TYPE_TEXT_VARIATION_URI,
{}) {
settingsManager.edit()
.putString(getString(R.string.nginx_credentials), it)
.apply() // change the stored url in nginx_url_key to it
}
return@setOnPreferenceClickListener true
}
getPref(R.string.nginx_url_key)?.setOnPreferenceClickListener {
activity?.showNginxTextInputDialog(
settingsManager.getString(getString(R.string.nginx_url_pref), "Nginx server url")
.toString(),
settingsManager.getString(getString(R.string.nginx_url_key), "")
.toString(), // key: the actual you use rn
android.text.InputType.TYPE_TEXT_VARIATION_URI, // uri
{}) {
settingsManager.edit()
.putString(getString(R.string.nginx_url_key), it)
.apply() // change the stored url in nginx_url_key to it
}
return@setOnPreferenceClickListener true
}
}
}

View file

@ -0,0 +1,295 @@
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 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.subtitles.ChromecastSubtitlesFragment
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
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() {
// 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)
val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())
getPref(R.string.video_buffer_length_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.video_buffer_length_names)
val prefValues = resources.getIntArray(R.array.video_buffer_length_values)
val currentPrefSize =
settingsManager.getInt(getString(R.string.video_buffer_length_key), 0)
activity?.showDialog(
prefNames.toList(),
prefValues.indexOf(currentPrefSize),
getString(R.string.video_buffer_length_settings),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.video_buffer_length_key), prefValues[it])
.apply()
}
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)
val prefValues = resources.getIntArray(R.array.limit_title_pref_values)
val current = settingsManager.getInt(getString(R.string.prefer_limit_title_key), 0)
activity?.showBottomDialog(
prefNames.toList(),
prefValues.indexOf(current),
getString(R.string.limit_title),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.prefer_limit_title_key), prefValues[it])
.apply()
}
return@setOnPreferenceClickListener true
}
/*(getPref(R.string.double_tap_seek_time_key) as? SeekBarPreference?)?.let {
}*/
getPref(R.string.prefer_limit_title_rez_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.limit_title_rez_pref_names)
val prefValues = resources.getIntArray(R.array.limit_title_rez_pref_values)
val current = settingsManager.getInt(getString(R.string.prefer_limit_title_rez_key), 3)
activity?.showBottomDialog(
prefNames.toList(),
prefValues.indexOf(current),
getString(R.string.limit_title_rez),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.prefer_limit_title_rez_key), prefValues[it])
.apply()
}
return@setOnPreferenceClickListener true
}
getPref(R.string.quality_pref_key)?.setOnPreferenceClickListener {
val prefValues = Qualities.values().map { it.value }.reversed().toMutableList()
prefValues.remove(Qualities.Unknown.value)
val prefNames = prefValues.map { Qualities.getStringByInt(it) }
val currentQuality =
settingsManager.getInt(
getString(R.string.quality_pref_key),
Qualities.values().last().value
)
activity?.showBottomDialog(
prefNames.toList(),
prefValues.indexOf(currentQuality),
getString(R.string.watch_quality_pref),
true,
{}) {
settingsManager.edit().putInt(getString(R.string.quality_pref_key), prefValues[it])
.apply()
}
return@setOnPreferenceClickListener true
}
getPref(R.string.subtitle_settings_key)?.setOnPreferenceClickListener {
SubtitlesFragment.push(activity, false)
return@setOnPreferenceClickListener true
}
getPref(R.string.subtitle_settings_chromecast_key)?.setOnPreferenceClickListener {
ChromecastSubtitlesFragment.push(activity, false)
return@setOnPreferenceClickListener true
}
getPref(R.string.video_buffer_disk_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.video_buffer_size_names)
val prefValues = resources.getIntArray(R.array.video_buffer_size_values)
val currentPrefSize =
settingsManager.getInt(getString(R.string.video_buffer_disk_key), 0)
activity?.showDialog(
prefNames.toList(),
prefValues.indexOf(currentPrefSize),
getString(R.string.video_buffer_disk_settings),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.video_buffer_disk_key), prefValues[it])
.apply()
}
return@setOnPreferenceClickListener true
}
getPref(R.string.video_buffer_size_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.video_buffer_size_names)
val prefValues = resources.getIntArray(R.array.video_buffer_size_values)
val currentPrefSize =
settingsManager.getInt(getString(R.string.video_buffer_size_key), 0)
activity?.showDialog(
prefNames.toList(),
prefValues.indexOf(currentPrefSize),
getString(R.string.video_buffer_size_settings),
true,
{}) {
settingsManager.edit()
.putInt(getString(R.string.video_buffer_size_key), prefValues[it])
.apply()
}
return@setOnPreferenceClickListener true
}
getPref(R.string.video_buffer_clear_key)?.let { pref ->
val cacheDir = context?.cacheDir ?: return@let
fun updateSummery() {
try {
pref.summary =
getString(R.string.mb_format).format(getFolderSize(cacheDir) / (1024L * 1024L))
} catch (e: Exception) {
logError(e)
}
}
updateSummery()
pref.setOnPreferenceClickListener {
try {
cacheDir.deleteRecursively()
updateSummery()
} catch (e: Exception) {
logError(e)
}
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
}
}
}

View file

@ -0,0 +1,123 @@
package com.lagradost.cloudstream3.ui.settings
import android.os.Bundle
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.search.SearchResultBuilder
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showBottomDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showDialog
import com.lagradost.cloudstream3.utils.SingleSelectionHelper.showMultiDialog
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
class SettingsUI : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
hideKeyboard()
setPreferencesFromResource(R.xml.settins_ui, rootKey)
val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())
getPref(R.string.poster_ui_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.poster_ui_options)
val keys = resources.getStringArray(R.array.poster_ui_options_values)
val prefValues = keys.map {
settingsManager.getBoolean(it, true)
}.mapIndexedNotNull { index, b ->
if (b) {
index
} else null
}
activity?.showMultiDialog(
prefNames.toList(),
prefValues,
getString(R.string.poster_ui_settings),
{}) { list ->
val edit = settingsManager.edit()
for ((i, key) in keys.withIndex()) {
edit.putBoolean(key, list.contains(i))
}
edit.apply()
SearchResultBuilder.updateCache(it.context)
}
return@setOnPreferenceClickListener true
}
getPref(R.string.app_layout_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.app_layout)
val prefValues = resources.getIntArray(R.array.app_layout_values)
val currentLayout =
settingsManager.getInt(getString(R.string.app_layout_key), -1)
activity?.showBottomDialog(
prefNames.toList(),
prefValues.indexOf(currentLayout),
getString(R.string.app_layout),
true,
{}) {
try {
settingsManager.edit()
.putInt(getString(R.string.app_layout_key), prefValues[it])
.apply()
activity?.recreate()
} catch (e: Exception) {
logError(e)
}
}
return@setOnPreferenceClickListener true
}
getPref(R.string.app_theme_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.themes_names)
val prefValues = resources.getStringArray(R.array.themes_names_values)
val currentLayout =
settingsManager.getString(getString(R.string.app_theme_key), prefValues.first())
activity?.showBottomDialog(
prefNames.toList(),
prefValues.indexOf(currentLayout),
getString(R.string.app_theme_settings),
true,
{}) {
try {
settingsManager.edit()
.putString(getString(R.string.app_theme_key), prefValues[it])
.apply()
activity?.recreate()
} catch (e: Exception) {
logError(e)
}
}
return@setOnPreferenceClickListener true
}
getPref(R.string.primary_color_key)?.setOnPreferenceClickListener {
val prefNames = resources.getStringArray(R.array.themes_overlay_names)
val prefValues = resources.getStringArray(R.array.themes_overlay_names_values)
val currentLayout =
settingsManager.getString(getString(R.string.primary_color_key), prefValues.first())
activity?.showDialog(
prefNames.toList(),
prefValues.indexOf(currentLayout),
getString(R.string.primary_color_settings),
true,
{}) {
try {
settingsManager.edit()
.putString(getString(R.string.primary_color_key), prefValues[it])
.apply()
activity?.recreate()
} catch (e: Exception) {
logError(e)
}
}
return@setOnPreferenceClickListener true
}
}
}

View file

@ -0,0 +1,118 @@
package com.lagradost.cloudstream3.ui.settings
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.lagradost.cloudstream3.CommonActivity
import com.lagradost.cloudstream3.R
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.ui.settings.SettingsFragment.Companion.getPref
import com.lagradost.cloudstream3.utils.BackupUtils.backup
import com.lagradost.cloudstream3.utils.BackupUtils.restorePrompt
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe
import com.lagradost.cloudstream3.utils.UIHelper.hideKeyboard
import com.lagradost.cloudstream3.utils.VideoDownloadManager
import kotlinx.android.synthetic.main.logcat.*
import okhttp3.internal.closeQuietly
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.OutputStream
import kotlin.concurrent.thread
class SettingsUpdates : PreferenceFragmentCompat() {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
hideKeyboard()
setPreferencesFromResource(R.xml.settings_updates, rootKey)
val settingsManager = PreferenceManager.getDefaultSharedPreferences(requireContext())
getPref(R.string.backup_key)?.setOnPreferenceClickListener {
activity?.backup()
return@setOnPreferenceClickListener true
}
getPref(R.string.restore_key)?.setOnPreferenceClickListener {
activity?.restorePrompt()
return@setOnPreferenceClickListener true
}
getPref(R.string.show_logcat_key)?.setOnPreferenceClickListener { pref ->
val builder =
AlertDialog.Builder(pref.context, R.style.AlertDialogCustom)
.setView(R.layout.logcat)
val dialog = builder.create()
dialog.show()
val log = StringBuilder()
try {
//https://developer.android.com/studio/command-line/logcat
val process = Runtime.getRuntime().exec("logcat -d")
val bufferedReader = BufferedReader(
InputStreamReader(process.inputStream)
)
var line: String?
while (bufferedReader.readLine().also { line = it } != null) {
log.append(line)
}
} catch (e: Exception) {
logError(e) // kinda ironic
}
val text = log.toString()
dialog.text1?.text = text
dialog.copy_btt?.setOnClickListener {
val serviceClipboard =
(activity?.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager?)
?: return@setOnClickListener
val clip = ClipData.newPlainText("logcat", text)
serviceClipboard.setPrimaryClip(clip)
dialog.dismissSafe(activity)
}
dialog.clear_btt?.setOnClickListener {
Runtime.getRuntime().exec("logcat -c")
dialog.dismissSafe(activity)
}
dialog.save_btt?.setOnClickListener {
var fileStream: OutputStream? = null
try {
fileStream =
VideoDownloadManager.setupStream(
it.context,
"logcat",
null,
"txt",
false
).fileStream
fileStream?.writer()?.write(text)
} catch (e: Exception) {
logError(e)
} finally {
fileStream?.closeQuietly()
dialog.dismissSafe(activity)
}
}
dialog.close_btt?.setOnClickListener {
dialog.dismissSafe(activity)
}
return@setOnPreferenceClickListener true
}
getPref(R.string.manual_check_update_key)?.setOnPreferenceClickListener {
thread {
if (!requireActivity().runAutoUpdate(false)) {
activity?.runOnUiThread {
CommonActivity.showToast(activity, R.string.no_update_found, Toast.LENGTH_SHORT)
}
}
}
return@setOnPreferenceClickListener true
}
}
}

View file

@ -302,7 +302,8 @@ object UIHelper {
return result
}
fun Context.fixPaddingStatusbar(v: View) {
fun Context?.fixPaddingStatusbar(v: View?) {
if (v == null || this == null) return
v.setPadding(
v.paddingLeft,
v.paddingTop + getStatusBarHeight(),
@ -385,7 +386,7 @@ object UIHelper {
}
fun hideKeyboard(view: View?) {
if(view == null) return
if (view == null) return
val inputMethodManager =
view.context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager?

View file

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:background="?attr/primaryBlackBackground"
android:layout_height="match_parent">
<ScrollView
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:nextFocusDown="@id/settings_lang"
android:id="@+id/settings_player"
style="@style/SettingsItem"
android:text="@string/category_player" />
<TextView
android:nextFocusUp="@id/settings_player"
android:nextFocusDown="@id/settings_ui"
android:id="@+id/settings_lang"
style="@style/SettingsItem"
android:text="@string/category_preferred_media_and_lang" />
<TextView
android:nextFocusUp="@id/settings_lang"
android:nextFocusDown="@id/settings_nginx"
android:id="@+id/settings_ui"
style="@style/SettingsItem"
android:text="@string/category_ui" />
<TextView
android:nextFocusUp="@id/settings_ui"
android:nextFocusDown="@id/settings_updates"
android:id="@+id/settings_nginx"
style="@style/SettingsItem"
android:text="@string/category_nginx" />
<TextView
android:nextFocusUp="@id/settings_nginx"
android:nextFocusDown="@id/settings_credits"
android:id="@+id/settings_updates"
style="@style/SettingsItem"
android:text="@string/category_updates" />
<TextView
android:nextFocusUp="@id/settings_updates"
android:id="@+id/settings_credits"
style="@style/SettingsItem"
android:text="@string/category_credits" />
<TextView
android:padding="10dp"
android:gravity="center"
android:layout_gravity="center"
android:textColor="?attr/textColor"
android:text="@string/app_version"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -86,6 +86,69 @@
android:defaultValue="true" />
</action>
<fragment
android:id="@+id/navigation_settings_player"
android:name="com.lagradost.cloudstream3.ui.settings.SettingsPlayer"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim">
<action
android:id="@+id/action_navigation_settings_player_to_navigation_subtitles"
app:destination="@id/navigation_subtitles"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
<action
android:id="@+id/action_navigation_settings_player_to_navigation_chrome_subtitles"
app:destination="@id/navigation_chrome_subtitles"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
</fragment>
<fragment
android:id="@+id/navigation_settings_ui"
android:name="com.lagradost.cloudstream3.ui.settings.SettingsUI"
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:name="com.lagradost.cloudstream3.ui.settings.SettingsLang"
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_nginx"
android:name="com.lagradost.cloudstream3.ui.settings.SettingsNginx"
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_updates"
android:name="com.lagradost.cloudstream3.ui.settings.SettingsUpdates"
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_account"
android:name="com.lagradost.cloudstream3.ui.settings.SettingsAccount"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
<action
android:id="@+id/global_to_navigation_quick_search"
app:destination="@id/navigation_quick_search"
@ -103,30 +166,6 @@
android:defaultValue="@null" />
</action>
<action
android:id="@+id/global_to_navigation_settings"
app:destination="@id/navigation_settings"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
<action
android:id="@+id/global_to_navigation_downloads"
app:destination="@id/navigation_downloads"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
<action
android:id="@+id/global_to_navigation_search"
app:destination="@id/navigation_search"
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_home"
android:name="com.lagradost.cloudstream3.ui.home.HomeFragment"
@ -135,7 +174,22 @@
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
app:popExitAnim="@anim/exit_anim">
<action
android:id="@+id/action_navigation_home_to_navigation_results"
app:destination="@id/navigation_results"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
<action
android:id="@+id/action_navigation_home_to_navigation_quick_search"
app:destination="@id/navigation_quick_search"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
</fragment>
<fragment
android:id="@+id/navigation_search"
@ -145,7 +199,15 @@
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
app:popExitAnim="@anim/exit_anim">
<action
android:id="@+id/action_navigation_search_to_navigation_results"
app:destination="@id/navigation_results"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
</fragment>
<fragment
android:id="@+id/navigation_downloads"
@ -159,7 +221,11 @@
<action
android:id="@+id/action_navigation_downloads_to_navigation_download_child"
app:destination="@id/navigation_download_child">
app:destination="@id/navigation_download_child"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim">
<argument
android:name="name"
app:argType="string" />
@ -167,6 +233,20 @@
android:name="folder"
app:argType="string" />
</action>
<action
android:id="@+id/action_navigation_downloads_to_navigation_results"
app:destination="@id/navigation_results"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
<action
android:id="@+id/action_navigation_downloads_to_navigation_player"
app:destination="@id/navigation_player"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
</fragment>
<fragment
android:id="@+id/navigation_settings"
@ -176,7 +256,50 @@
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
app:popExitAnim="@anim/exit_anim">
<action
android:id="@+id/action_navigation_settings_to_navigation_settings_nginx"
app:destination="@id/navigation_settings_nginx"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
<action
android:id="@+id/action_navigation_settings_to_navigation_settings_ui"
app:destination="@id/navigation_settings_ui"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
<action
android:id="@+id/action_navigation_settings_to_navigation_settings_lang"
app:destination="@id/navigation_settings_lang"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
<action
android:id="@+id/action_navigation_settings_to_navigation_settings_player"
app:destination="@id/navigation_settings_player"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
<action
android:id="@+id/action_navigation_settings_to_navigation_settings_updates"
app:destination="@id/navigation_settings_updates"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
<action
android:id="@+id/action_navigation_settings_to_navigation_settings_account"
app:destination="@id/navigation_settings_account"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
</fragment>
<fragment
android:id="@+id/navigation_subtitles"
@ -215,8 +338,15 @@
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim"
android:label="@string/title_settings" />
app:popExitAnim="@anim/exit_anim">
<action
android:id="@+id/action_navigation_download_child_to_navigation_player"
app:destination="@id/navigation_player"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
</fragment>
<fragment
android:id="@+id/navigation_results"
@ -225,7 +355,22 @@
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
app:popExitAnim="@anim/exit_anim">
<action
android:id="@+id/action_navigation_results_to_navigation_quick_search"
app:destination="@id/navigation_quick_search"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
<action
android:id="@+id/action_navigation_results_to_navigation_player"
app:destination="@id/navigation_player"
app:enterAnim="@anim/enter_anim"
app:exitAnim="@anim/exit_anim"
app:popEnterAnim="@anim/enter_anim"
app:popExitAnim="@anim/exit_anim" />
</fragment>
<fragment
android:id="@+id/navigation_player"

View file

@ -182,7 +182,7 @@
<string name="backup_failed_error_format">Yedekleme hatası %s</string>
<string name="search">Ara</string>
<string name="nginx_category">Nginx Ayarları</string>
<string name="category_nginx">Nginx Ayarları</string>
<string name="nginx_credentials_title">Nginx Kimlik Bilgileri</string>
<string name="nginx_credentials_summary">Örnekteki formatta yazmalısın havalıkullanıcıadım:güvenlişifrem123</string>
<string name="nginx_info_title">Nginx nedir?</string>

View file

@ -42,6 +42,20 @@
<item>3</item>
</array>
<array name="limit_title_rez_pref_names">
<item>@string/resolution_and_title</item>
<item>@string/title</item>
<item>@string/resolution</item>
<item>@string/none</item>
</array>
<array name="limit_title_rez_pref_values">
<item>3</item>
<item>2</item>
<item>1</item>
<item>0</item>
</array>
<array name="limit_title_pref_names">
<item>@string/none</item>
<item>16 characters</item>
@ -59,6 +73,15 @@
<item>-1</item>
</array>
<array name="skip_sec_values">
<item>5</item>
<item>10</item>
<item>15</item>
<item>20</item>
<item>25</item>
<item>30</item>
</array>
<array name="video_buffer_length_names">
<item>@string/automatic</item>
<item>1min</item>

View file

@ -14,6 +14,7 @@
<string name="subtitle_settings_chromecast_key" translatable="false">subtitle_settings_chromecast_key</string>
<string name="quality_pref_key" translatable="false">quality_pref_key</string>
<string name="prefer_limit_title_key" translatable="false">prefer_limit_title_key</string>
<string name="prefer_limit_title_rez_key" translatable="false">prefer_limit_title_rez_key</string>
<string name="video_buffer_size_key" translatable="false">video_buffer_size_key</string>
<string name="video_buffer_length_key" translatable="false">video_buffer_length_key</string>
<string name="video_buffer_clear_key" translatable="false">video_buffer_clear_key</string>
@ -26,6 +27,7 @@
<string name="pip_enabled_key" translatable="false">pip_enabled_key</string>
<string name="double_tap_enabled_key" translatable="false">double_tap_enabled_key</string>
<string name="double_tap_pause_enabled_key" translatable="false">double_tap_pause_enabled_key</string>
<string name="double_tap_seek_time_key" translatable="false">double_tap_seek_time_key</string>
<string name="swipe_vertical_enabled_key" translatable="false">swipe_vertical_enabled_key</string>
<string name="display_sub_key" translatable="false">display_sub_key</string>
<string name="show_fillers_key" translatable="false">show_fillers_key</string>
@ -213,6 +215,7 @@
<string name="swipe_to_change_settings_des">Swipe on the left or right side to change brightness or volume</string>
<string name="double_tap_to_seek_settings">Double tap to seek</string>
<string name="double_tap_to_pause_settings">Double tap to pause</string>
<string name="double_tap_to_seek_amount_settings">Player seek amount</string>
<string name="double_tap_to_seek_settings_des">Tap twice on the right or left side to seek forwards or backwards
</string>
<string name="double_tap_to_pause_settings_des">Tap in the middle to pause</string>
@ -236,7 +239,9 @@
<string name="backup_failed_error_format">Error backing up %s</string>
<string name="search">Search</string>
<string name="nginx_category">Nginx Settings</string>
<string name="category_nginx">Nginx</string>
<string name="category_credits">Credits and account</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>
@ -365,7 +370,9 @@
<string name="skip_update">Skip this Update</string>
<string name="update">Update</string>
<string name="watch_quality_pref">Preferred watch quality</string>
<string name="limit_title">Video player title max chars.</string>
<string name="limit_title">Video player title max chars</string>
<string name="limit_title_rez">Video player resolution</string>
<string name="video_buffer_size_settings">Video buffer size</string>
<string name="video_buffer_length_settings">Video buffer length</string>
<string name="video_buffer_disk_settings">Video cache on disk</string>
@ -408,9 +415,11 @@
<string name="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="provider_lang_settings">Provider languages</string>
<string name="app_layout">App Layout</string>
<string name="preferred_media_settings">Preferred Media</string>
<string name="preferred_media_settings">Preferred media</string>
<string name="category_preferred_media_and_lang">Preferred media and language</string>
<string name="category_ui">User interface</string>
<string name="automatic">Auto</string>
<string name="tv_layout">TV layout</string>
@ -507,4 +516,8 @@
<string name="quality_webrip">Web</string>
<string name="poster_image">Poster Image</string>
<string name="category_player">Player</string>
<string name="resolution_and_title">Resolution and title</string>
<string name="title">Title</string>
<string name="resolution">Resolution</string>
</resources>

View file

@ -1,313 +0,0 @@
<?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">
<PreferenceCategory />
<PreferenceCategory
android:key="video"
android:title="Player"
app:isPreferenceVisible="true">
<Preference
android:key="@string/subtitle_settings_key"
android:title="@string/player_subtitles_settings"
android:icon="@drawable/ic_outline_subtitles_24"
app:summary="@string/player_subtitles_settings_des" />
<Preference
android:key="@string/subtitle_settings_chromecast_key"
android:title="@string/chromecast_subtitles_settings"
android:icon="@drawable/ic_outline_subtitles_24"
app:summary="@string/chromecast_subtitles_settings_des" />
<Preference
android:key="@string/quality_pref_key"
android:title="@string/watch_quality_pref"
android:icon="@drawable/ic_baseline_hd_24" />
<Preference
android:key="@string/prefer_limit_title_key"
android:title="@string/limit_title"
android:icon="@drawable/ic_baseline_text_format_24" />
<SwitchPreference
android:icon="@drawable/ic_baseline_picture_in_picture_alt_24"
app:key="@string/pip_enabled_key"
android:title="@string/picture_in_picture"
android:summary="@string/picture_in_picture_des"
app:defaultValue="true" />
<SwitchPreference
android:icon="@drawable/ic_baseline_aspect_ratio_24"
app:key="@string/player_resize_enabled_key"
android:title="@string/player_size_settings"
android:summary="@string/player_size_settings_des"
app:defaultValue="true" />
<SwitchPreference
android:icon="@drawable/ic_baseline_speed_24"
app:key="@string/playback_speed_enabled_key"
android:title="@string/eigengraumode_settings"
android:summary="@string/eigengraumode_settings_des"
app:defaultValue="false" />
<SwitchPreference
android:icon="@drawable/ic_baseline_ondemand_video_24"
app:key="@string/swipe_enabled_key"
android:title="@string/swipe_to_seek_settings"
android:summary="@string/swipe_to_seek_settings_des"
app:defaultValue="true" />
<SwitchPreference
android:icon="@drawable/ic_baseline_ondemand_video_24"
app:key="@string/swipe_vertical_enabled_key"
android:title="@string/swipe_to_change_settings"
android:summary="@string/swipe_to_change_settings_des"
app:defaultValue="true" />
<SwitchPreference
android:icon="@drawable/ic_baseline_touch_app_24"
app:key="@string/double_tap_enabled_key"
android:title="@string/double_tap_to_seek_settings"
android:summary="@string/double_tap_to_seek_settings_des"
app:defaultValue="false" />
<SwitchPreference
android:icon="@drawable/netflix_pause"
app:key="@string/double_tap_pause_enabled_key"
android:title="@string/double_tap_to_pause_settings"
android:summary="@string/double_tap_to_pause_settings_des"
app:defaultValue="false" />
<SwitchPreference
android:icon="@drawable/baseline_sync_24"
app:key="@string/episode_sync_enabled_key"
android:title="@string/episode_sync_settings"
android:summary="@string/episode_sync_settings_des"
app:defaultValue="true" />
<Preference
android:key="@string/video_buffer_disk_key"
android:title="@string/video_buffer_disk_settings"
android:summary="@string/video_disk_description"
android:icon="@drawable/ic_baseline_storage_24" />
<Preference
android:key="@string/video_buffer_size_key"
android:title="@string/video_buffer_size_settings"
android:summary="@string/video_ram_description"
android:icon="@drawable/ic_baseline_storage_24" />
<Preference
android:key="@string/video_buffer_length_key"
android:title="@string/video_buffer_length_settings"
android:summary="@string/video_ram_description"
android:icon="@drawable/ic_baseline_storage_24" />
<Preference
android:key="@string/video_buffer_clear_key"
android:title="@string/video_buffer_clear_settings"
android:icon="@drawable/ic_baseline_delete_outline_24" />
<!--
<SwitchPreference
android:icon="@drawable/ic_baseline_brightness_7_24"
app:key="@string/use_system_brightness_key"
android:title="@string/use_system_brightness_settings"
android:summary="@string/use_system_brightness_settings_des"
app:defaultValue="false"
/>
-->
</PreferenceCategory>
<PreferenceCategory
android:key="general"
android:title="@string/general"
app:isPreferenceVisible="true">
<SwitchPreference
android:icon="@drawable/ic_baseline_play_arrow_24"
app:key="@string/random_button_key"
android:title="@string/random_button_settings"
android:summary="@string/random_button_settings_desc"
app:defaultValue="false" />
<Preference
android:icon="@drawable/ic_baseline_language_24"
android:key="@string/provider_lang_key"
android:title="@string/provider_lang_settings" />
<Preference
android:key="@string/locale_key"
android:title="@string/app_language"
android:icon="@drawable/ic_baseline_language_24" />
<Preference
android:key="@string/prefer_media_type_key"
android:title="@string/preferred_media_settings"
android:icon="@drawable/ic_baseline_play_arrow_24" />
<Preference
android:key="@string/display_sub_key"
android:title="@string/display_subbed_dubbed_settings"
android:icon="@drawable/ic_outline_voice_over_off_24" />
<SwitchPreference
android:key="@string/show_fillers_key"
android:icon="@drawable/ic_baseline_skip_next_24"
android:title="@string/show_fillers_settings"
android:defaultValue="false" />
<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:icon="@drawable/ic_baseline_tv_24"
android:key="@string/app_layout_key"
android:title="@string/app_layout" />
<Preference
android:icon="@drawable/ic_baseline_color_lens_24"
android:key="@string/primary_color_key"
android:title="@string/primary_color_settings" />
<Preference
android:icon="@drawable/ic_baseline_color_lens_24"
android:key="@string/app_theme_key"
android:title="@string/app_theme_settings" />
<SwitchPreference
android:defaultValue="true"
android:icon="@drawable/baseline_grid_view_24"
android:key="@string/bottom_title_key"
android:summary="@string/bottom_title_settings_des"
android:title="@string/bottom_title_settings" />
<Preference
android:icon="@drawable/ic_baseline_tv_24"
android:key="@string/poster_ui_key"
android:title="@string/poster_ui_settings" />
</PreferenceCategory>
<PreferenceCategory
android:key="search"
android:title="@string/search"
app:isPreferenceVisible="true">
<SwitchPreference
android:icon="@drawable/search_icon"
app:key="advanced_search"
android:title="@string/advanced_search"
android:summary="@string/advanced_search_des"
app:defaultValue="true" />
</PreferenceCategory>
<PreferenceCategory
android:key="@string/nginx_category"
android:title="@string/nginx_category"
app:isPreferenceVisible="true">
<Preference
android:key="@string/nginx_url_key"
android:title="@string/nginx_url_pref"
android:icon="@drawable/ic_baseline_play_arrow_24" />
<Preference
android:key="@string/nginx_credentials"
android:title="@string/nginx_credentials_title"
android:icon="@drawable/video_locked"
android:summary="@string/nginx_credentials_summary"/>
<Preference
android:key="@string/nginx_info"
android:title="@string/nginx_info_title"
android:icon="@drawable/ic_baseline_play_arrow_24"
android:summary="@string/nginx_info_summary" >
<intent
android:action="android.intent.action.VIEW"
android:data="https://www.sarlays.com/use-nginx-with-cloudstream/" />
</Preference>
</PreferenceCategory>
<PreferenceCategory
android:key="info"
android:title="@string/settings_info"
app:isPreferenceVisible="true">
<Preference
android:key="@string/legal_notice_key"
android:title="@string/legal_notice"
android:icon="@drawable/ic_baseline_warning_24" />
<SwitchPreference
android:key="acra.disable"
android:icon="@drawable/ic_baseline_bug_report_24"
android:title="@string/pref_disable_acra"
android:summaryOff="@string/bug_report_settings_off"
android:summaryOn="@string/bug_report_settings_on"
android:defaultValue="false" />
<SwitchPreference
app:key="@string/auto_update_key"
android:title="@string/updates_settings"
android:summary="@string/updates_settings_des"
app:defaultValue="true"
android:icon="@drawable/ic_baseline_notifications_active_24" />
<SwitchPreference
app:key="@string/prerelease_update_key"
android:title="@string/uprereleases_settings"
android:summary="@string/uprereleases_settings_des"
app:defaultValue="false"
android:icon="@drawable/ic_baseline_developer_mode_24" />
<Preference
android:title="@string/check_for_update"
app:summary="@string/app_version"
app:key="@string/manual_check_update_key"
app:icon="@drawable/ic_baseline_system_update_24" />
<Preference
android:icon="@drawable/baseline_save_as_24"
android:key="@string/backup_key"
android:title="@string/backup_settings" />
<Preference
android:icon="@drawable/baseline_restore_page_24"
android:key="@string/restore_key"
android:title="@string/restore_settings" />
<Preference
android:key="@string/show_logcat_key"
android:title="@string/show_log_cat"
android:icon="@drawable/baseline_description_24" />
<!--<SwitchPreference
android:defaultValue="false"
android:key="@string/log_enabled_key"
android:title="@string/toggle_logcat"
android:summary="@string/toggle_logcat_des"
android:icon="@drawable/baseline_description_24" />-->
<SwitchPreference
android:icon="@drawable/netflix_download"
android:key="@string/killswitch_key"
android:defaultValue="true"
android:summary="@string/killswitch_settings_des"
android:title="@string/killswitch_settings" />
<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:title="@string/github"
android:icon="@drawable/ic_github_logo"
app:summary="https://github.com/LagradOst/CloudStream-3">
<intent
android:action="android.intent.action.VIEW"
android:data="https://github.com/LagradOst/CloudStream-3" />
</Preference>
<Preference
android:title="@string/lightnovel"
android:icon="@drawable/quick_novel_icon"
app:summary="https://github.com/LagradOst/QuickNovel">
<intent
android:action="android.intent.action.VIEW"
android:data="https://github.com/LagradOst/QuickNovel" />
</Preference>
<Preference
android:title="@string/discord"
android:icon="@drawable/ic_baseline_discord_24"
app:summary="https://discord.gg/5Hus6fM">
<intent
android:action="android.intent.action.VIEW"
android:data="https://discord.gg/5Hus6fM" />
</Preference>
<Preference
android:key="@string/benene_count"
android:title="@string/benene"
android:icon="@drawable/benene"
app:summary="@string/benene_des" />
</PreferenceCategory>
</PreferenceScreen>

View file

@ -0,0 +1,47 @@
<?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">
<PreferenceCategory app:icon="@color/transparent" />
<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/legal_notice_key"
android:title="@string/legal_notice"
android:icon="@drawable/ic_baseline_warning_24" />
<Preference
android:title="@string/github"
android:icon="@drawable/ic_github_logo"
app:summary="https://github.com/LagradOst/CloudStream-3">
<intent
android:action="android.intent.action.VIEW"
android:data="https://github.com/LagradOst/CloudStream-3" />
</Preference>
<Preference
android:title="@string/lightnovel"
android:icon="@drawable/quick_novel_icon"
app:summary="https://github.com/LagradOst/QuickNovel">
<intent
android:action="android.intent.action.VIEW"
android:data="https://github.com/LagradOst/QuickNovel" />
</Preference>
<Preference
android:title="@string/discord"
android:icon="@drawable/ic_baseline_discord_24"
app:summary="https://discord.gg/5Hus6fM">
<intent
android:action="android.intent.action.VIEW"
android:data="https://discord.gg/5Hus6fM" />
</Preference>
<Preference
android:key="@string/benene_count"
android:title="@string/benene"
android:icon="@drawable/benene"
app:summary="@string/benene_des" />
</PreferenceScreen>

View file

@ -0,0 +1,23 @@
<?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">
<PreferenceCategory app:icon="@color/transparent" />
<Preference
android:key="@string/locale_key"
android:title="@string/app_language"
android:icon="@drawable/ic_baseline_language_24" />
<Preference
android:icon="@drawable/ic_baseline_language_24"
android:key="@string/provider_lang_key"
android:title="@string/provider_lang_settings" />
<Preference
android:key="@string/prefer_media_type_key"
android:title="@string/preferred_media_settings"
android:icon="@drawable/ic_baseline_play_arrow_24" />
<Preference
android:key="@string/display_sub_key"
android:title="@string/display_subbed_dubbed_settings"
android:icon="@drawable/ic_outline_voice_over_off_24" />
</PreferenceScreen>

View file

@ -0,0 +1,24 @@
<?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">
<PreferenceCategory app:icon="@color/transparent" />
<Preference
android:key="@string/nginx_url_key"
android:title="@string/nginx_url_pref"
android:icon="@drawable/ic_baseline_play_arrow_24" />
<Preference
android:key="@string/nginx_credentials"
android:title="@string/nginx_credentials_title"
android:icon="@drawable/video_locked"
android:summary="@string/nginx_credentials_summary" />
<Preference
android:key="@string/nginx_info"
android:title="@string/nginx_info_title"
android:icon="@drawable/ic_baseline_play_arrow_24"
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>

View file

@ -0,0 +1,127 @@
<?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">
<PreferenceCategory app:icon="@color/transparent" />
<Preference
android:key="@string/subtitle_settings_key"
android:title="@string/player_subtitles_settings"
android:icon="@drawable/ic_outline_subtitles_24"
app:summary="@string/player_subtitles_settings_des" />
<Preference
android:key="@string/subtitle_settings_chromecast_key"
android:title="@string/chromecast_subtitles_settings"
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"
android:title="@string/watch_quality_pref"
android:icon="@drawable/ic_baseline_hd_24" />
<Preference
android:key="@string/prefer_limit_title_key"
android:title="@string/limit_title"
android:icon="@drawable/ic_baseline_text_format_24" />
<Preference
android:key="@string/prefer_limit_title_rez_key"
android:title="@string/limit_title_rez"
android:icon="@drawable/ic_baseline_text_format_24" />
<SwitchPreference
android:icon="@drawable/ic_baseline_picture_in_picture_alt_24"
app:key="@string/pip_enabled_key"
android:title="@string/picture_in_picture"
android:summary="@string/picture_in_picture_des"
app:defaultValue="true" />
<SwitchPreference
android:icon="@drawable/ic_baseline_aspect_ratio_24"
app:key="@string/player_resize_enabled_key"
android:title="@string/player_size_settings"
android:summary="@string/player_size_settings_des"
app:defaultValue="true" />
<SwitchPreference
android:icon="@drawable/ic_baseline_speed_24"
app:key="@string/playback_speed_enabled_key"
android:title="@string/eigengraumode_settings"
android:summary="@string/eigengraumode_settings_des"
app:defaultValue="false" />
<SwitchPreference
android:icon="@drawable/ic_baseline_ondemand_video_24"
app:key="@string/swipe_enabled_key"
android:title="@string/swipe_to_seek_settings"
android:summary="@string/swipe_to_seek_settings_des"
app:defaultValue="true" />
<SwitchPreference
android:icon="@drawable/ic_baseline_ondemand_video_24"
app:key="@string/swipe_vertical_enabled_key"
android:title="@string/swipe_to_change_settings"
android:summary="@string/swipe_to_change_settings_des"
app:defaultValue="true" />
<SwitchPreference
android:icon="@drawable/ic_baseline_touch_app_24"
app:key="@string/double_tap_enabled_key"
android:title="@string/double_tap_to_seek_settings"
android:summary="@string/double_tap_to_seek_settings_des"
app:defaultValue="false" />
<SwitchPreference
android:icon="@drawable/netflix_pause"
app:key="@string/double_tap_pause_enabled_key"
android:title="@string/double_tap_to_pause_settings"
android:summary="@string/double_tap_to_pause_settings_des"
app:defaultValue="false" />
<SeekBarPreference
app:icon="@drawable/go_forward_30"
app:adjustable="true"
android:defaultValue="10"
app:min="5"
app:seekBarIncrement="5"
app:showSeekBarValue="true"
android:max="60"
app:key="@string/double_tap_seek_time_key"
android:title="@string/double_tap_to_seek_amount_settings"
app:defaultValue="false" />
<SwitchPreference
android:icon="@drawable/baseline_sync_24"
app:key="@string/episode_sync_enabled_key"
android:title="@string/episode_sync_settings"
android:summary="@string/episode_sync_settings_des"
app:defaultValue="true" />
<Preference
android:key="@string/video_buffer_disk_key"
android:title="@string/video_buffer_disk_settings"
android:summary="@string/video_disk_description"
android:icon="@drawable/ic_baseline_storage_24" />
<Preference
android:key="@string/video_buffer_size_key"
android:title="@string/video_buffer_size_settings"
android:summary="@string/video_ram_description"
android:icon="@drawable/ic_baseline_storage_24" />
<Preference
android:key="@string/video_buffer_length_key"
android:title="@string/video_buffer_length_settings"
android:summary="@string/video_ram_description"
android:icon="@drawable/ic_baseline_storage_24" />
<Preference
android:key="@string/video_buffer_clear_key"
android:title="@string/video_buffer_clear_settings"
android:icon="@drawable/ic_baseline_delete_outline_24" />
</PreferenceScreen>

View file

@ -0,0 +1,51 @@
<?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">
<PreferenceCategory app:icon="@color/transparent" />
<Preference
android:title="@string/check_for_update"
app:summary="@string/app_version"
app:key="@string/manual_check_update_key"
app:icon="@drawable/ic_baseline_system_update_24" />
<Preference
android:icon="@drawable/baseline_save_as_24"
android:key="@string/backup_key"
android:title="@string/backup_settings" />
<Preference
android:icon="@drawable/baseline_restore_page_24"
android:key="@string/restore_key"
android:title="@string/restore_settings" />
<Preference
android:key="@string/show_logcat_key"
android:title="@string/show_log_cat"
android:icon="@drawable/baseline_description_24" />
<SwitchPreference
android:key="acra.disable"
android:icon="@drawable/ic_baseline_bug_report_24"
android:title="@string/pref_disable_acra"
android:summaryOff="@string/bug_report_settings_off"
android:summaryOn="@string/bug_report_settings_on"
android:defaultValue="false" />
<SwitchPreference
app:key="@string/auto_update_key"
android:title="@string/updates_settings"
android:summary="@string/updates_settings_des"
app:defaultValue="true"
android:icon="@drawable/ic_baseline_notifications_active_24" />
<SwitchPreference
app:key="@string/prerelease_update_key"
android:title="@string/uprereleases_settings"
android:summary="@string/uprereleases_settings_des"
app:defaultValue="false"
android:icon="@drawable/ic_baseline_developer_mode_24" />
<SwitchPreference
android:icon="@drawable/netflix_download"
android:key="@string/killswitch_key"
android:defaultValue="true"
android:summary="@string/killswitch_settings_des"
android:title="@string/killswitch_settings" />
</PreferenceScreen>

View file

@ -0,0 +1,45 @@
<?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">
<PreferenceCategory app:icon="@color/transparent" />
<Preference
android:icon="@drawable/ic_baseline_color_lens_24"
android:key="@string/primary_color_key"
android:title="@string/primary_color_settings" />
<Preference
android:icon="@drawable/ic_baseline_color_lens_24"
android:key="@string/app_theme_key"
android:title="@string/app_theme_settings" />
<Preference
android:icon="@drawable/ic_baseline_tv_24"
android:key="@string/app_layout_key"
android:title="@string/app_layout" />
<Preference
android:icon="@drawable/ic_baseline_tv_24"
android:key="@string/poster_ui_key"
android:title="@string/poster_ui_settings" />
<SwitchPreference
android:icon="@drawable/search_icon"
app:key="advanced_search"
android:title="@string/advanced_search"
android:summary="@string/advanced_search_des"
app:defaultValue="true" />
<SwitchPreference
android:defaultValue="true"
android:icon="@drawable/baseline_grid_view_24"
android:key="@string/bottom_title_key"
android:summary="@string/bottom_title_settings_des"
android:title="@string/bottom_title_settings" />
<SwitchPreference
android:key="@string/show_fillers_key"
android:icon="@drawable/ic_baseline_skip_next_24"
android:title="@string/show_fillers_settings"
android:defaultValue="false" />
<SwitchPreference
android:icon="@drawable/ic_baseline_play_arrow_24"
app:key="@string/random_button_key"
android:title="@string/random_button_settings"
android:summary="@string/random_button_settings_desc"
app:defaultValue="false" />
</PreferenceScreen>