feat: manual repository entries
Closes Dantotsu#298
This commit is contained in:
parent
ba1725224a
commit
ff3131d988
12 changed files with 369 additions and 109 deletions
|
@ -12,8 +12,8 @@ import ani.dantotsu.R
|
|||
class Xpandable @JvmOverloads constructor(
|
||||
context: Context, attrs: AttributeSet? = null
|
||||
) : LinearLayout(context, attrs) {
|
||||
var expanded: Boolean = false
|
||||
private var listener: OnChangeListener? = null
|
||||
private var expanded: Boolean = false
|
||||
private var listeners: ArrayList<OnChangeListener> = arrayListOf()
|
||||
|
||||
init {
|
||||
context.withStyledAttributes(attrs, R.styleable.Xpandable) {
|
||||
|
@ -50,7 +50,9 @@ class Xpandable @JvmOverloads constructor(
|
|||
}
|
||||
}
|
||||
postDelayed({
|
||||
listener?.onRetract()
|
||||
listeners.forEach{
|
||||
it.onRetract()
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
|
||||
|
@ -64,13 +66,19 @@ class Xpandable @JvmOverloads constructor(
|
|||
}
|
||||
}
|
||||
postDelayed({
|
||||
listener?.onExpand()
|
||||
listeners.forEach{
|
||||
it.onExpand()
|
||||
}
|
||||
}, 300)
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun setOnChangeListener(listener: OnChangeListener) {
|
||||
this.listener = listener
|
||||
fun addOnChangeListener(listener: OnChangeListener) {
|
||||
listeners.add(listener)
|
||||
}
|
||||
|
||||
fun removeListener(listener: OnChangeListener) {
|
||||
listeners.remove(listener)
|
||||
}
|
||||
|
||||
interface OnChangeListener {
|
||||
|
|
|
@ -475,7 +475,7 @@ class PlayerSettingsActivity : AppCompatActivity() {
|
|||
updateSubPreview()
|
||||
}
|
||||
}
|
||||
binding.subtitleTest.setOnChangeListener(object: Xpandable.OnChangeListener {
|
||||
binding.subtitleTest.addOnChangeListener(object: Xpandable.OnChangeListener {
|
||||
override fun onExpand() {
|
||||
updateSubPreview()
|
||||
}
|
||||
|
|
|
@ -13,12 +13,15 @@ import android.os.Build.VERSION.CODENAME
|
|||
import android.os.Build.VERSION.RELEASE
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.os.Bundle
|
||||
import android.view.HapticFeedbackConstants
|
||||
import android.view.KeyEvent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.EditText
|
||||
import android.widget.RadioButton
|
||||
import android.widget.RadioGroup
|
||||
import android.widget.TextView
|
||||
|
@ -29,6 +32,7 @@ import androidx.appcompat.app.AppCompatActivity
|
|||
import androidx.core.content.ContextCompat
|
||||
import android.view.HapticFeedbackConstants
|
||||
import androidx.core.view.ViewCompat.performHapticFeedback
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
|
@ -51,6 +55,7 @@ import ani.dantotsu.databinding.ActivitySettingsExtensionsBinding
|
|||
import ani.dantotsu.databinding.ActivitySettingsMangaBinding
|
||||
import ani.dantotsu.databinding.ActivitySettingsNotificationsBinding
|
||||
import ani.dantotsu.databinding.ActivitySettingsThemeBinding
|
||||
import ani.dantotsu.databinding.ItemRepositoryBinding
|
||||
import ani.dantotsu.download.DownloadsManager
|
||||
import ani.dantotsu.download.video.ExoplayerDownloadService
|
||||
import ani.dantotsu.downloadsPermission
|
||||
|
@ -89,13 +94,17 @@ import eltos.simpledialogfragment.SimpleDialog
|
|||
import eltos.simpledialogfragment.SimpleDialog.OnDialogResultListener.BUTTON_POSITIVE
|
||||
import eltos.simpledialogfragment.color.SimpleColorDialog
|
||||
import eu.kanade.domain.base.BasePreferences
|
||||
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
||||
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import kotlin.random.Random
|
||||
|
||||
|
||||
|
@ -115,6 +124,9 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
|
|||
private val extensionInstaller = Injekt.get<BasePreferences>().extensionInstaller()
|
||||
private var cursedCounter = 0
|
||||
|
||||
private val animeExtensionManager: AnimeExtensionManager by injectLazy()
|
||||
private val mangaExtensionManager: MangaExtensionManager by injectLazy()
|
||||
|
||||
@OptIn(UnstableApi::class)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
@ -583,6 +595,142 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
|
|||
}
|
||||
|
||||
bindingExtensions = ActivitySettingsExtensionsBinding.bind(binding.root).apply {
|
||||
|
||||
fun setExtensionOutput() {
|
||||
animeRepoInventory.removeAllViews()
|
||||
PrefManager.getVal<Set<String>>(PrefName.AnimeExtensionRepos).forEach { item ->
|
||||
val view = ItemRepositoryBinding.inflate(
|
||||
LayoutInflater.from(animeRepoInventory.context), animeRepoInventory, true
|
||||
)
|
||||
view.repositoryItem.text = item
|
||||
view.repositoryItem.setOnClickListener {
|
||||
snackString(getString(R.string.long_click_delete))
|
||||
}
|
||||
view.repositoryItem.setOnLongClickListener {
|
||||
val anime = PrefManager.getVal<Set<String>>(PrefName.AnimeExtensionRepos)
|
||||
.minus(item)
|
||||
PrefManager.setVal(PrefName.AnimeExtensionRepos, anime)
|
||||
it.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||
setExtensionOutput()
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
animeExtensionManager.findAvailableExtensions()
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
animeRepoInventory.isVisible = animeRepoInventory.childCount > 0
|
||||
mangaRepoInventory.removeAllViews()
|
||||
PrefManager.getVal<Set<String>>(PrefName.MangaExtensionRepos).forEach { item ->
|
||||
val view = ItemRepositoryBinding.inflate(
|
||||
LayoutInflater.from(mangaRepoInventory.context), mangaRepoInventory, true
|
||||
)
|
||||
view.repositoryItem.text = item
|
||||
view.repositoryItem.setOnClickListener {
|
||||
snackString(getString(R.string.long_click_delete))
|
||||
}
|
||||
view.repositoryItem.setOnLongClickListener {
|
||||
val anime = PrefManager.getVal<Set<String>>(PrefName.MangaExtensionRepos)
|
||||
.minus(item)
|
||||
PrefManager.setVal(PrefName.MangaExtensionRepos, anime)
|
||||
it.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
|
||||
setExtensionOutput()
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
mangaExtensionManager.findAvailableExtensions()
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
mangaRepoInventory.isVisible = mangaRepoInventory.childCount > 0
|
||||
}
|
||||
|
||||
fun processUserInput(input: String, mediaType: MediaType) {
|
||||
val entry = if (input.endsWith("/") || input.endsWith("index.min.json"))
|
||||
input.substring(0, input.lastIndexOf("/")) else input
|
||||
if (mediaType == MediaType.ANIME) {
|
||||
val anime = PrefManager.getVal<Set<String>>(PrefName.AnimeExtensionRepos).plus(entry)
|
||||
PrefManager.setVal(PrefName.AnimeExtensionRepos, anime)
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
animeExtensionManager.findAvailableExtensions()
|
||||
}
|
||||
}
|
||||
if (mediaType == MediaType.MANGA) {
|
||||
val manga = PrefManager.getVal<Set<String>>(PrefName.MangaExtensionRepos).plus(entry)
|
||||
PrefManager.setVal(PrefName.MangaExtensionRepos, manga)
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
mangaExtensionManager.findAvailableExtensions()
|
||||
}
|
||||
}
|
||||
setExtensionOutput()
|
||||
}
|
||||
|
||||
fun processEditorAction(dialog: AlertDialog, editText: EditText, mediaType: MediaType) {
|
||||
editText.setOnEditorActionListener { textView, action, keyEvent ->
|
||||
if (action == EditorInfo.IME_ACTION_SEARCH || action == EditorInfo.IME_ACTION_DONE ||
|
||||
(keyEvent?.action == KeyEvent.ACTION_UP
|
||||
&& keyEvent.keyCode == KeyEvent.KEYCODE_ENTER)) {
|
||||
processUserInput(textView.text.toString(), mediaType)
|
||||
dialog.dismiss()
|
||||
return@setOnEditorActionListener true
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
setExtensionOutput()
|
||||
animeAddRepository.setOnClickListener {
|
||||
val dialogView = layoutInflater.inflate(R.layout.dialog_user_agent, null)
|
||||
val editText = dialogView.findViewById<TextInputEditText>(R.id.userAgentTextBox).apply {
|
||||
hint = getString(R.string.anime_add_repository)
|
||||
}
|
||||
val alertDialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
|
||||
.setTitle(R.string.anime_add_repository)
|
||||
.setView(dialogView)
|
||||
.setPositiveButton(getString(R.string.ok)) { dialog, _ ->
|
||||
processUserInput(editText.text.toString(), MediaType.ANIME)
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNeutralButton(getString(R.string.reset)) { dialog, _ ->
|
||||
PrefManager.removeVal(PrefName.DefaultUserAgent)
|
||||
editText.setText("")
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
.create()
|
||||
|
||||
processEditorAction(alertDialog, editText, MediaType.ANIME)
|
||||
alertDialog.show()
|
||||
alertDialog.window?.setDimAmount(0.8f)
|
||||
}
|
||||
|
||||
mangaAddRepository.setOnClickListener {
|
||||
val dialogView = layoutInflater.inflate(R.layout.dialog_user_agent, null)
|
||||
val editText = dialogView.findViewById<TextInputEditText>(R.id.userAgentTextBox).apply {
|
||||
hint = getString(R.string.manga_add_repository)
|
||||
}
|
||||
val alertDialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
|
||||
.setTitle(R.string.manga_add_repository)
|
||||
.setView(dialogView)
|
||||
.setPositiveButton(getString(R.string.ok)) { dialog, _ ->
|
||||
processUserInput(editText.text.toString(), MediaType.MANGA)
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNeutralButton(getString(R.string.reset)) { dialog, _ ->
|
||||
PrefManager.removeVal(PrefName.DefaultUserAgent)
|
||||
editText.setText("")
|
||||
dialog.dismiss()
|
||||
}
|
||||
.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
|
||||
dialog.dismiss()
|
||||
}
|
||||
.create()
|
||||
|
||||
processEditorAction(alertDialog, editText, MediaType.MANGA)
|
||||
alertDialog.show()
|
||||
alertDialog.window?.setDimAmount(0.8f)
|
||||
}
|
||||
|
||||
settingsForceLegacyInstall.isChecked =
|
||||
extensionInstaller.get() == BasePreferences.ExtensionInstaller.LEGACY
|
||||
settingsForceLegacyInstall.setOnCheckedChangeListener { _, isChecked ->
|
||||
|
@ -1169,4 +1317,4 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
|
|||
?: "Unknown Architecture"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ enum class PrefName(val data: Pref) { //TODO: Split this into multiple files
|
|||
"Mozilla/5.0 (Linux; Android 13; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Mobile Safari/537.36"
|
||||
)
|
||||
),
|
||||
AnimeExtensionRepos(Pref(Location.General, Set::class, setOf<String>())),
|
||||
MangaExtensionRepos(Pref(Location.General, Set::class, setOf<String>())),
|
||||
SharedRepositories(Pref(Location.General, Boolean::class, false)),
|
||||
AnimeSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
||||
AnimeSearchHistory(Pref(Location.General, Set::class, setOf<String>())),
|
||||
MangaSourcesOrder(Pref(Location.General, List::class, listOf<String>())),
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package eu.kanade.tachiyomi.extension.anime.api
|
||||
|
||||
import android.content.Context
|
||||
import ani.dantotsu.settings.saving.PrefManager
|
||||
import ani.dantotsu.settings.saving.PrefName
|
||||
import ani.dantotsu.util.Logger
|
||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier
|
||||
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
|
||||
|
@ -32,42 +34,36 @@ internal class AnimeExtensionGithubApi {
|
|||
preferenceStore.getLong("last_ext_check", 0)
|
||||
}
|
||||
|
||||
private var requiresFallbackSource = false
|
||||
|
||||
suspend fun findExtensions(): List<AnimeExtension.Available> {
|
||||
return withIOContext {
|
||||
val githubResponse = if (requiresFallbackSource) {
|
||||
null
|
||||
} else {
|
||||
|
||||
val extensions: ArrayList<AnimeExtension.Available> = arrayListOf()
|
||||
|
||||
PrefManager.getVal<Set<String>>(PrefName.AnimeExtensionRepos).forEach {
|
||||
try {
|
||||
networkService.client
|
||||
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
|
||||
.awaitSuccess()
|
||||
val githubResponse =
|
||||
networkService.client
|
||||
.newCall(GET("${it}/index.min.json"))
|
||||
.awaitSuccess()
|
||||
|
||||
val repoExtensions = with(json) {
|
||||
githubResponse
|
||||
.parseAs<List<AnimeExtensionJsonObject>>()
|
||||
.toExtensions(it)
|
||||
}
|
||||
|
||||
// Sanity check - a small number of extensions probably means something broke
|
||||
// with the repo generator
|
||||
if (repoExtensions.size < 10) {
|
||||
throw Exception()
|
||||
}
|
||||
|
||||
extensions.addAll(repoExtensions)
|
||||
} catch (e: Throwable) {
|
||||
Logger.log("Failed to get extensions from GitHub")
|
||||
requiresFallbackSource = true
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
val response = githubResponse ?: run {
|
||||
networkService.client
|
||||
.newCall(GET("${FALLBACK_REPO_URL_PREFIX}index.min.json"))
|
||||
.awaitSuccess()
|
||||
}
|
||||
|
||||
val extensions = with(json) {
|
||||
response
|
||||
.parseAs<List<AnimeExtensionJsonObject>>()
|
||||
.toExtensions()
|
||||
}
|
||||
|
||||
// Sanity check - a small number of extensions probably means something broke
|
||||
// with the repo generator
|
||||
if (extensions.size < 10) {
|
||||
throw Exception()
|
||||
}
|
||||
|
||||
extensions
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +107,7 @@ internal class AnimeExtensionGithubApi {
|
|||
return extensionsWithUpdate
|
||||
}
|
||||
|
||||
private fun List<AnimeExtensionJsonObject>.toExtensions(): List<AnimeExtension.Available> {
|
||||
private fun List<AnimeExtensionJsonObject>.toExtensions(repository: String): List<AnimeExtension.Available> {
|
||||
return this
|
||||
.filter {
|
||||
val libVersion = it.extractLibVersion()
|
||||
|
@ -130,7 +126,8 @@ internal class AnimeExtensionGithubApi {
|
|||
hasChangelog = it.hasChangelog == 1,
|
||||
sources = it.sources?.toAnimeExtensionSources().orEmpty(),
|
||||
apkName = it.apk,
|
||||
iconUrl = "${getUrlPrefix()}icon/${it.pkg}.png",
|
||||
repository = repository,
|
||||
iconUrl = "${repository}/icon/${it.pkg}.png",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -147,15 +144,7 @@ internal class AnimeExtensionGithubApi {
|
|||
}
|
||||
|
||||
fun getApkUrl(extension: AnimeExtension.Available): String {
|
||||
return "${getUrlPrefix()}apk/${extension.apkName}"
|
||||
}
|
||||
|
||||
private fun getUrlPrefix(): String {
|
||||
return if (requiresFallbackSource) {
|
||||
FALLBACK_REPO_URL_PREFIX
|
||||
} else {
|
||||
REPO_URL_PREFIX
|
||||
}
|
||||
return "${extension.repository}/apk/${extension.apkName}"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,11 +152,6 @@ private fun AnimeExtensionJsonObject.extractLibVersion(): Double {
|
|||
return version.substringBeforeLast('.').toDouble()
|
||||
}
|
||||
|
||||
private const val REPO_URL_PREFIX =
|
||||
"https://raw.githubusercontent.com/aniyomiorg/aniyomi-extensions/repo/"
|
||||
private const val FALLBACK_REPO_URL_PREFIX =
|
||||
"https://gcore.jsdelivr.net/gh/aniyomiorg/aniyomi-extensions@repo/"
|
||||
|
||||
@Serializable
|
||||
private data class AnimeExtensionJsonObject(
|
||||
val name: String,
|
||||
|
|
|
@ -47,6 +47,7 @@ sealed class AnimeExtension {
|
|||
val sources: List<AvailableAnimeSources>,
|
||||
val apkName: String,
|
||||
val iconUrl: String,
|
||||
val repository: String
|
||||
) : AnimeExtension()
|
||||
|
||||
data class Untrusted(
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package eu.kanade.tachiyomi.extension.manga.api
|
||||
|
||||
import android.content.Context
|
||||
import ani.dantotsu.settings.saving.PrefManager
|
||||
import ani.dantotsu.settings.saving.PrefName
|
||||
import ani.dantotsu.util.Logger
|
||||
import eu.kanade.tachiyomi.extension.ExtensionUpdateNotifier
|
||||
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
|
||||
|
@ -32,42 +34,37 @@ internal class MangaExtensionGithubApi {
|
|||
preferenceStore.getLong("last_ext_check", 0)
|
||||
}
|
||||
|
||||
private var requiresFallbackSource = false
|
||||
|
||||
suspend fun findExtensions(): List<MangaExtension.Available> {
|
||||
return withIOContext {
|
||||
val githubResponse = if (requiresFallbackSource) {
|
||||
null
|
||||
} else {
|
||||
|
||||
val extensions: ArrayList<MangaExtension.Available> = arrayListOf()
|
||||
|
||||
|
||||
PrefManager.getVal<Set<String>>(PrefName.MangaExtensionRepos).forEach {
|
||||
try {
|
||||
networkService.client
|
||||
.newCall(GET("${REPO_URL_PREFIX}index.min.json"))
|
||||
.awaitSuccess()
|
||||
val githubResponse =
|
||||
networkService.client
|
||||
.newCall(GET("${it}/index.min.json"))
|
||||
.awaitSuccess()
|
||||
|
||||
val repoExtensions = with(json) {
|
||||
githubResponse
|
||||
.parseAs<List<ExtensionJsonObject>>()
|
||||
.toExtensions(it)
|
||||
}
|
||||
|
||||
// Sanity check - a small number of extensions probably means something broke
|
||||
// with the repo generator
|
||||
if (repoExtensions.size < 10) {
|
||||
throw Exception()
|
||||
}
|
||||
|
||||
extensions.addAll(repoExtensions)
|
||||
} catch (e: Throwable) {
|
||||
Logger.log("Failed to get extensions from GitHub")
|
||||
requiresFallbackSource = true
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
val response = githubResponse ?: run {
|
||||
networkService.client
|
||||
.newCall(GET("${FALLBACK_REPO_URL_PREFIX}index.min.json"))
|
||||
.awaitSuccess()
|
||||
}
|
||||
|
||||
val extensions = with(json) {
|
||||
response
|
||||
.parseAs<List<ExtensionJsonObject>>()
|
||||
.toExtensions()
|
||||
}
|
||||
|
||||
// Sanity check - a small number of extensions probably means something broke
|
||||
// with the repo generator
|
||||
if (extensions.size < 100) {
|
||||
throw Exception()
|
||||
}
|
||||
|
||||
extensions
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +107,7 @@ internal class MangaExtensionGithubApi {
|
|||
return extensionsWithUpdate
|
||||
}
|
||||
|
||||
private fun List<ExtensionJsonObject>.toExtensions(): List<MangaExtension.Available> {
|
||||
private fun List<ExtensionJsonObject>.toExtensions(repository: String): List<MangaExtension.Available> {
|
||||
return this
|
||||
.filter {
|
||||
val libVersion = it.extractLibVersion()
|
||||
|
@ -129,7 +126,8 @@ internal class MangaExtensionGithubApi {
|
|||
hasChangelog = it.hasChangelog == 1,
|
||||
sources = it.sources?.toExtensionSources().orEmpty(),
|
||||
apkName = it.apk,
|
||||
iconUrl = "${getUrlPrefix()}icon/${it.pkg}.png",
|
||||
repository = repository,
|
||||
iconUrl = "${repository}/icon/${it.pkg}.png",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -146,15 +144,7 @@ internal class MangaExtensionGithubApi {
|
|||
}
|
||||
|
||||
fun getApkUrl(extension: MangaExtension.Available): String {
|
||||
return "${getUrlPrefix()}apk/${extension.apkName}"
|
||||
}
|
||||
|
||||
private fun getUrlPrefix(): String {
|
||||
return if (requiresFallbackSource) {
|
||||
FALLBACK_REPO_URL_PREFIX
|
||||
} else {
|
||||
REPO_URL_PREFIX
|
||||
}
|
||||
return "${extension.repository}/apk/${extension.apkName}"
|
||||
}
|
||||
|
||||
private fun ExtensionJsonObject.extractLibVersion(): Double {
|
||||
|
@ -162,10 +152,6 @@ internal class MangaExtensionGithubApi {
|
|||
}
|
||||
}
|
||||
|
||||
private const val REPO_URL_PREFIX = "https://raw.githubusercontent.com/keiyoushi/extensions/main/"
|
||||
private const val FALLBACK_REPO_URL_PREFIX =
|
||||
"https://gcore.jsdelivr.net/gh/keiyoushi/extensions@main/"
|
||||
|
||||
@Serializable
|
||||
private data class ExtensionJsonObject(
|
||||
val name: String,
|
||||
|
|
|
@ -47,6 +47,7 @@ sealed class MangaExtension {
|
|||
val sources: List<AvailableMangaSources>,
|
||||
val apkName: String,
|
||||
val iconUrl: String,
|
||||
val repository: String
|
||||
) : MangaExtension()
|
||||
|
||||
data class Untrusted(
|
||||
|
|
|
@ -177,8 +177,7 @@
|
|||
android:layout_height="64dp"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingStart="48dp"
|
||||
android:paddingEnd="32dp"
|
||||
android:paddingHorizontal="32dp"
|
||||
android:text="@string/sub_text_example"
|
||||
android:textColor="?attr/colorSecondary"
|
||||
app:drawableEndCompat="@drawable/ic_round_arrow_drop_down_24"
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<ani.dantotsu.others.Xpandable
|
||||
android:id="@+id/extensionSettings"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
|
@ -18,14 +20,6 @@
|
|||
app:drawableEndCompat="@drawable/ic_round_arrow_drop_down_24"
|
||||
tools:ignore="TextContrastCheck" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="-16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="-16dp"
|
||||
android:background="?android:attr/listDivider" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/userAgent"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -38,8 +32,7 @@
|
|||
android:fontFamily="@font/poppins_bold"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:paddingStart="31dp"
|
||||
android:paddingEnd="31dp"
|
||||
android:paddingHorizontal="31dp"
|
||||
android:text="@string/user_agent"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
|
@ -55,7 +48,118 @@
|
|||
android:layout_height="1dp"
|
||||
android:layout_marginStart="-16dp"
|
||||
android:layout_marginEnd="-16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="?android:attr/listDivider" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/animeRepoHeading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/anime_repo_listing"
|
||||
android:textSize="14sp"
|
||||
tools:ignore="RtlSymmetry" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/animeRepoInventory"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:paddingStart="36dp"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlSymmetry"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/animeAddRepository"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:layout_marginStart="-31dp"
|
||||
android:layout_marginEnd="-31dp"
|
||||
android:background="@drawable/ui_bg"
|
||||
android:backgroundTint="?attr/colorSecondary"
|
||||
android:backgroundTintMode="src_atop"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:paddingHorizontal="31dp"
|
||||
android:text="@string/anime_add_repository"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_github"
|
||||
app:iconPadding="16dp"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorPrimary" />
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="-16dp"
|
||||
android:layout_marginEnd="-16dp"
|
||||
android:background="?android:attr/listDivider" />
|
||||
|
||||
<View
|
||||
android:id="@+id/mangaRepoHeadingDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="-16dp"
|
||||
android:layout_marginEnd="-16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="?android:attr/listDivider" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mangaRepoHeading"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:text="@string/manga_repo_listing"
|
||||
android:textSize="14sp"
|
||||
tools:ignore="RtlSymmetry" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/mangaRepoInventory"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:paddingStart="36dp"
|
||||
android:visibility="gone"
|
||||
tools:ignore="RtlSymmetry"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/mangaAddRepository"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:layout_marginStart="-31dp"
|
||||
android:layout_marginEnd="-31dp"
|
||||
android:background="@drawable/ui_bg"
|
||||
android:backgroundTint="?attr/colorSecondary"
|
||||
android:backgroundTintMode="src_atop"
|
||||
android:fontFamily="@font/poppins_bold"
|
||||
android:insetTop="0dp"
|
||||
android:insetBottom="0dp"
|
||||
android:paddingHorizontal="31dp"
|
||||
android:text="@string/manga_add_repository"
|
||||
android:textAlignment="viewStart"
|
||||
android:textAllCaps="false"
|
||||
android:textColor="?attr/colorOnBackground"
|
||||
app:cornerRadius="0dp"
|
||||
app:icon="@drawable/ic_github"
|
||||
app:iconPadding="16dp"
|
||||
app:iconSize="24dp"
|
||||
app:iconTint="?attr/colorPrimary" />
|
||||
|
||||
<View
|
||||
android:id="@+id/mangaRepoDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginStart="-16dp"
|
||||
android:layout_marginEnd="-16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="?android:attr/listDivider" />
|
||||
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
|
@ -113,4 +217,4 @@
|
|||
app:thumbTint="@color/button_switch_track" />
|
||||
|
||||
</ani.dantotsu.others.Xpandable>
|
||||
</merge>
|
||||
</merge>
|
||||
|
|
18
app/src/main/res/layout/item_repository.xml
Normal file
18
app/src/main/res/layout/item_repository.xml
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/repositoryItem"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/poppins_semi_bold"
|
||||
android:textSize="12sp"
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="?attr/colorOnBackground" />
|
||||
|
||||
</LinearLayout>
|
|
@ -252,7 +252,7 @@
|
|||
<string name="sub_window_color_info">"The subtitle window is the part left and right from them. (where the background isn\'t)"</string>
|
||||
<string name="sub_color_info"><b>Note:</b> Changing above settings only affects Soft-Subtitles!</string>
|
||||
<string name="sub_alpha">Subtitle Transparency</string>
|
||||
<string name="sub_text_example">Example Subtitle</string>
|
||||
<string name="sub_text_example">Example Sub</string>
|
||||
<string name="sub_font_select">Subtitle Font</string>
|
||||
<string name="subtitle_font_size">Subtitle Size</string>
|
||||
|
||||
|
@ -417,6 +417,7 @@
|
|||
<string name="crop_borders">Crop Borders</string>
|
||||
<string name="note">NOTE</string>
|
||||
|
||||
<string name="manage_extension_repos">Manage Extension Repos</string>
|
||||
<string name="installing_extension">Installing extension</string>
|
||||
<string name="installation_failed">Installation failed: %1$s</string>
|
||||
<string name="installation_complete">Installation complete</string>
|
||||
|
@ -859,6 +860,13 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
|
|||
<string name="title_color">Title Color</string>
|
||||
<string name="stat_text_color">Stats Text Color</string>
|
||||
<string name="placeholder">Placeholder</string>
|
||||
|
||||
<string name="anime_repo_listing">Anime Extension Repos</string>
|
||||
<string name="anime_add_repository">Add Anime Repo</string>
|
||||
<string name="manga_repo_listing">Manga Extension Repos</string>
|
||||
<string name="manga_add_repository">Add Manga Repo</string>
|
||||
<string name="long_click_delete">Long click to delete</string>
|
||||
|
||||
<string name="trending_movies">Trending Movies</string>
|
||||
<string name="include_list">Include list</string>
|
||||
<string name="top_rated">Top rated</string>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue