Merge pull request #458 from Bnyro/custom

Custom instance
This commit is contained in:
Bnyro 2022-06-11 15:58:03 +02:00 committed by GitHub
commit 79c6e21def
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 316 additions and 22 deletions

View File

@ -53,7 +53,7 @@ class MainActivity : AppCompatActivity() {
CronetHelper.initCronet(this.applicationContext) CronetHelper.initCronet(this.applicationContext)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
RetrofitInstance.url = RetrofitInstance.url =
sharedPreferences.getString("instance", "https://pipedapi.kavin.rocks/")!! sharedPreferences.getString("selectInstance", "https://pipedapi.kavin.rocks/")!!
SponsorBlockSettings.sponsorBlockEnabled = SponsorBlockSettings.sponsorBlockEnabled =
sharedPreferences.getBoolean("sb_enabled_key", false) sharedPreferences.getBoolean("sb_enabled_key", false)
SponsorBlockSettings.sponsorNotificationsEnabled = SponsorBlockSettings.sponsorNotificationsEnabled =

View File

@ -0,0 +1,90 @@
package com.github.libretube.dialogs
import android.app.Dialog
import android.os.Bundle
import android.util.Log
import android.util.TypedValue
import android.view.View
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.core.text.HtmlCompat
import androidx.fragment.app.DialogFragment
import androidx.preference.PreferenceManager
import com.github.libretube.R
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.textfield.TextInputEditText
class CustomInstanceDialog : DialogFragment() {
val TAG = "CustomInstanceDialog"
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return activity?.let {
val builder = MaterialAlertDialogBuilder(it)
val inflater = requireActivity().layoutInflater
val view: View = inflater.inflate(R.layout.dialog_custom_instance, null)
val instanceNameEditText = view.findViewById<TextInputEditText>(R.id.instanceName)
val instanceApiUrlEditText = view.findViewById<TextInputEditText>(R.id.instanceApiUrl)
val addInstanceButton = view.findViewById<Button>(R.id.addInstance)
val cancelButton = view.findViewById<Button>(R.id.cancel)
cancelButton.setOnClickListener {
dismiss()
}
addInstanceButton.setOnClickListener {
val instanceName = instanceNameEditText.text.toString()
val instanceApiUrl = instanceApiUrlEditText.text.toString()
if (instanceName != "" && instanceApiUrl != "") {
val sharedPreferences = PreferenceManager
.getDefaultSharedPreferences(requireContext())
// get the names of the other custom instances
var customInstancesNames = try {
sharedPreferences
.getStringSet("custom_instances_name", HashSet())!!.toList()
} catch (e: Exception) {
emptyList()
}
// get the urls of the other custom instances
var customInstancesUrls = try {
sharedPreferences
.getStringSet("custom_instances_url", HashSet())!!.toList()
} catch (e: Exception) {
emptyList()
}
// append new instance to the list
customInstancesNames += instanceName
customInstancesUrls += instanceApiUrl
Log.e(TAG, customInstancesNames.toString())
// save them to the shared preferences
sharedPreferences.edit()
.putStringSet("custom_instances_name", HashSet(customInstancesNames))
.putStringSet("custom_instances_url", HashSet(customInstancesUrls))
.apply()
activity?.recreate()
dismiss()
} else {
Toast.makeText(
context, context?.getString(R.string.empty_instance), Toast.LENGTH_SHORT
).show()
}
}
val typedValue = TypedValue()
this.requireActivity().theme.resolveAttribute(R.attr.colorPrimaryDark, typedValue, true)
val hexColor = String.format("#%06X", (0xFFFFFF and typedValue.data))
val appName = HtmlCompat.fromHtml(
"Libre<span style='color:$hexColor';>Tube</span>",
HtmlCompat.FROM_HTML_MODE_COMPACT
)
view.findViewById<TextView>(R.id.title).text = appName
builder.setView(view)
builder.create()
} ?: throw IllegalStateException("Activity cannot be null")
}
}

View File

@ -16,7 +16,7 @@ class ShareDialog(private val videoId: String) : DialogFragment() {
val sharedPreferences = val sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(requireContext()) PreferenceManager.getDefaultSharedPreferences(requireContext())
val instancePref = sharedPreferences.getString( val instancePref = sharedPreferences.getString(
"instance", "selectInstance",
"https://pipedapi.kavin.rocks" "https://pipedapi.kavin.rocks"
)!! )!!
val instance = "&instance=${URLEncoder.encode(instancePref, "UTF-8")}" val instance = "&instance=${URLEncoder.encode(instancePref, "UTF-8")}"

View File

@ -13,13 +13,16 @@ import android.widget.TextView
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.app.ActivityCompat.recreate
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.dialogs.CustomInstanceDialog
import com.github.libretube.dialogs.LoginDialog import com.github.libretube.dialogs.LoginDialog
import com.github.libretube.requireMainActivityRestart import com.github.libretube.requireMainActivityRestart
import com.github.libretube.util.RetrofitInstance import com.github.libretube.util.RetrofitInstance
@ -27,6 +30,7 @@ import java.io.IOException
import java.io.InputStream import java.io.InputStream
import java.util.zip.ZipEntry import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream import java.util.zip.ZipInputStream
import org.chromium.base.ThreadUtils.runOnUiThread
import org.json.JSONObject import org.json.JSONObject
import org.json.JSONTokener import org.json.JSONTokener
import retrofit2.HttpException import retrofit2.HttpException
@ -110,19 +114,32 @@ class InstanceSettings : PreferenceFragmentCompat() {
val topBarTextView = activity?.findViewById<TextView>(R.id.topBar_textView) val topBarTextView = activity?.findViewById<TextView>(R.id.topBar_textView)
topBarTextView?.text = getString(R.string.instance) topBarTextView?.text = getString(R.string.instance)
val instance = findPreference<ListPreference>("instance_server") val instance = findPreference<ListPreference>("selectInstance")
fetchInstance() // fetchInstance()
initCustomInstances()
instance?.setOnPreferenceChangeListener { _, newValue -> instance?.setOnPreferenceChangeListener { _, newValue ->
requireMainActivityRestart = true
RetrofitInstance.url = newValue.toString() RetrofitInstance.url = newValue.toString()
RetrofitInstance.lazyMgr.reset() RetrofitInstance.lazyMgr.reset()
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE) logout()
if (sharedPref?.getString("token", "") != "") { true
with(sharedPref!!.edit()) { }
putString("token", "")
apply() val customInstance = findPreference<Preference>("customInstance")
} customInstance?.setOnPreferenceClickListener {
Toast.makeText(context, R.string.loggedout, Toast.LENGTH_SHORT).show() val newFragment = CustomInstanceDialog()
} newFragment.show(childFragmentManager, "CustomInstanceDialog")
true
}
val clearCustomInstances = findPreference<Preference>("clearCustomInstances")
clearCustomInstances?.setOnPreferenceClickListener {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
sharedPreferences.edit()
.remove("custom_instances_name")
.remove("custom_instances_url")
.commit()
activity?.recreate()
true true
} }
@ -188,6 +205,55 @@ class InstanceSettings : PreferenceFragmentCompat() {
} }
} }
private fun initCustomInstances() {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
// get the names of the custom instances
val customInstancesNames = try {
sharedPreferences
.getStringSet("custom_instances_name", HashSet())!!.toList()
} catch (e: Exception) {
emptyList()
}
// get the urls of the custom instances
val customInstancesUrls = try {
sharedPreferences
.getStringSet("custom_instances_url", HashSet())!!.toList()
} catch (e: Exception) {
emptyList()
}
val instanceNames = resources.getStringArray(R.array.instances) + customInstancesNames
val instanceValues = resources.getStringArray(R.array.instancesValue) + customInstancesUrls
// add custom instances to the list preference
val instance = findPreference<ListPreference>("selectInstance")
instance?.entries = instanceNames
instance?.entryValues = instanceValues
instance?.summaryProvider =
Preference.SummaryProvider<ListPreference> { preference ->
val text = preference.entry
if (TextUtils.isEmpty(text)) {
"kavin.rocks (Official)"
} else {
text
}
}
}
private fun logout() {
val sharedPref = context?.getSharedPreferences("token", Context.MODE_PRIVATE)
val token = sharedPref?.getString("token", "")
if (token != "") {
with(sharedPref!!.edit()) {
putString("token", "")
apply()
}
Toast.makeText(context, R.string.loggedout, Toast.LENGTH_SHORT).show()
}
}
private fun fetchInstance() { private fun fetchInstance() {
lifecycleScope.launchWhenCreated { lifecycleScope.launchWhenCreated {
val response = try { val response = try {
@ -209,10 +275,13 @@ class InstanceSettings : PreferenceFragmentCompat() {
listEntries.add(item.name!!) listEntries.add(item.name!!)
listEntryValues.add(item.api_url!!) listEntryValues.add(item.api_url!!)
} }
// add custom instances to the list
val entries = listEntries.toTypedArray<CharSequence>() val entries = listEntries.toTypedArray<CharSequence>()
val entryValues = listEntryValues.toTypedArray<CharSequence>() val entryValues = listEntryValues.toTypedArray<CharSequence>()
runOnUiThread { runOnUiThread {
val instance = findPreference<ListPreference>("instance_server") val instance = findPreference<ListPreference>("selectInstance")
instance?.entries = entries instance?.entries = entries
instance?.entryValues = entryValues instance?.entryValues = entryValues
instance?.summaryProvider = instance?.summaryProvider =

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?android:attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/black"
android:pathData="M4,6L2,6v14c0,1.1 0.9,2 2,2h14v-2L4,20L4,6zM20,2L8,2c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM19,11h-4v4h-2v-4L9,11L9,9h4L13,5h2v4h4v2z" />
</vector>

View File

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/app_name"
android:gravity="center"
android:layout_margin="10dp"
android:textSize="20sp" />
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintEnabled="false"
android:layout_marginTop="16dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="4dp"
app:boxCornerRadiusBottomStart="15dp"
app:boxCornerRadiusBottomEnd="15dp"
app:boxCornerRadiusTopEnd="15dp"
app:boxCornerRadiusTopStart="15dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/instanceName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/instance_name"
android:inputType="text"
android:padding="12dp" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:hintEnabled="false"
android:layout_marginTop="16dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="10dp"
app:boxCornerRadiusBottomStart="15dp"
app:boxCornerRadiusBottomEnd="15dp"
app:boxCornerRadiusTopEnd="15dp"
app:boxCornerRadiusTopStart="15dp"
>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/instanceApiUrl"
android:inputType="text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/instance_api_url"
android:padding="12dp" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="end">
<Button
android:id="@+id/cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/cancel"
android:layout_gravity="end"
android:backgroundTint="@android:color/transparent"
android:textColor="?attr/colorPrimary"
android:textSize="14sp"
android:padding="8dp"
android:layout_marginBottom="8dp"
style="?android:attr/buttonBarButtonStyle" />
<Button
android:id="@+id/addInstance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/addInstance"
android:layout_gravity="end"
android:backgroundTint="@android:color/transparent"
android:textColor="?attr/colorPrimary"
android:textSize="14sp"
android:padding="8dp"
android:layout_marginEnd="8dp"
android:layout_marginBottom="8dp"
style="?android:attr/buttonBarButtonStyle" />
</LinearLayout>
</LinearLayout>

View File

@ -2,17 +2,27 @@
<resources> <resources>
<string-array name="instances"> <string-array name="instances">
<item>kavin.rocks (Official)</item> <item>kavin.rocks (Official)</item>
<item>silkky.cloud</item>
<item>tokhmi.xyz</item> <item>tokhmi.xyz</item>
<item>moomoo.me</item> <item>moomoo.me</item>
<item>mint.lgbt</item> <item>mint.lgbt</item>
<item>il.ax</item>
<item>syncpundit.com</item>
<item>mha.fi</item>
<item>shimul.me</item>
<item>jae.fi</item>
<item>privacy.com.de</item>
</string-array> </string-array>
<string-array name="instancesValue"> <string-array name="instancesValue">
<item>https://pipedapi.kavin.rocks/</item> <item>https://pipedapi.kavin.rocks/</item>
<item>https://api.piped.silkky.cloud</item>
<item>https://pipedapi.tokhmi.xyz/</item> <item>https://pipedapi.tokhmi.xyz/</item>
<item>https://pipedapi.moomoo.me</item> <item>https://pipedapi.moomoo.me/</item>
<item>https://pa.mint.lgbt</item> <item>https://pa.mint.lgbt/</item>
<item>https://pa.il.ax/</item>
<item>https://pipedapi.syncpundit.com/</item>
<item>https://api-piped.mha.fi/</item>
<item>https://api-piped.shimul.me/</item>
<item>https://api.yt.jae.fi/</item>
<item>https://piped-api.privacy.com.de/</item>
</string-array> </string-array>
<string-array name="shareHostsList"> <string-array name="shareHostsList">
<item>youtube.com"</item> <item>youtube.com"</item>

View File

@ -24,7 +24,7 @@
<string name="already_logged_in">Already logged in. You may log out of your account.</string> <string name="already_logged_in">Already logged in. You may log out of your account.</string>
<string name="login_first">Please log in and try again.</string> <string name="login_first">Please log in and try again.</string>
<string name="instances">Choose an instance</string> <string name="instances">Choose an instance</string>
<string name="customInstance">Add a custom instance</string> <string name="customInstance">Custom instance</string>
<string name="region">Region</string> <string name="region">Region</string>
<string name="login_register">Log in/register</string> <string name="login_register">Log in/register</string>
<string name="please_login">Please log in or register in the settings first.</string> <string name="please_login">Please log in or register in the settings first.</string>
@ -162,4 +162,10 @@
<string name="flameIcon">Flying flame</string> <string name="flameIcon">Flying flame</string>
<string name="birdIcon">Boosted bird</string> <string name="birdIcon">Boosted bird</string>
<string name="instance_summary">Piped, login, subscriptions</string> <string name="instance_summary">Piped, login, subscriptions</string>
<string name="customInstance_summary">Add a custom instance (on your own risk)</string>
<string name="instance_name">Instance name</string>
<string name="instance_api_url">Instance API url</string>
<string name="addInstance">Add Instance</string>
<string name="empty_instance">You have to fill in the name and the API url.</string>
<string name="clear_customInstances">Clear custom instances</string>
</resources> </resources>

View File

@ -9,13 +9,19 @@
app:defaultValue="https://pipedapi.kavin.rocks/" app:defaultValue="https://pipedapi.kavin.rocks/"
app:entries="@array/instances" app:entries="@array/instances"
app:entryValues="@array/instancesValue" app:entryValues="@array/instancesValue"
app:key="instance_server" app:key="selectInstance"
app:title="@string/instances" /> app:title="@string/instances" />
<EditTextPreference <Preference
app:isPreferenceVisible="false"
app:key="customInstance" app:key="customInstance"
app:title="@string/customInstance" /> app:title="@string/customInstance"
app:summary="@string/customInstance_summary"
android:icon="@drawable/ic_add_instance" />
<Preference
app:key="clearCustomInstances"
app:title="@string/clear_customInstances"
android:icon="@drawable/ic_trash" />
<Preference <Preference
android:icon="@drawable/ic_login" android:icon="@drawable/ic_login"