feat: repo editor in extension window (#332)

* fix: error checking in repo editor

* feat: edit repos from extension page
This commit is contained in:
TwistedUmbrellaX 2024-04-07 22:27:27 -04:00 committed by GitHub
parent f96d2ffaa5
commit 29e115ce41
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 253 additions and 99 deletions

View file

@ -1,34 +1,54 @@
package ani.dantotsu.settings
import android.app.AlertDialog
import android.os.Build
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.HapticFeedbackConstants
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.widget.AutoCompleteTextView
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import androidx.viewpager2.widget.ViewPager2
import ani.dantotsu.R
import ani.dantotsu.copyToClipboard
import ani.dantotsu.currContext
import ani.dantotsu.databinding.ActivityExtensionsBinding
import ani.dantotsu.databinding.DialogRepositoriesBinding
import ani.dantotsu.databinding.ItemRepositoryBinding
import ani.dantotsu.initActivity
import ani.dantotsu.media.MediaType
import ani.dantotsu.navBarHeight
import ani.dantotsu.others.AndroidBug5497Workaround
import ani.dantotsu.others.LanguageMapper
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.snackString
import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager
import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import uy.kohesive.injekt.injectLazy
class ExtensionsActivity : AppCompatActivity() {
lateinit var binding: ActivityExtensionsBinding
private val animeExtensionManager: AnimeExtensionManager by injectLazy()
private val mangaExtensionManager: MangaExtensionManager by injectLazy()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -87,6 +107,13 @@ class ExtensionsActivity : AppCompatActivity() {
viewPager.updateLayoutParams<ViewGroup.LayoutParams> {
height = ViewGroup.LayoutParams.MATCH_PARENT
}
if (tab.text?.contains("Anime") == true) {
generateRepositoryButton(MediaType.ANIME)
}
if (tab.text?.contains("Manga") == true) {
generateRepositoryButton(MediaType.MANGA)
}
}
override fun onTabUnselected(tab: TabLayout.Tab) {
@ -162,10 +189,123 @@ class ExtensionsActivity : AppCompatActivity() {
topMargin = statusBarHeight
bottomMargin = navBarHeight
}
}
private 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()
}
}
}
private fun getSavedRepositories(repoInventory: ViewGroup, type: MediaType) {
repoInventory.removeAllViews()
val prefName: PrefName? = when (type) {
MediaType.ANIME -> { PrefName.AnimeExtensionRepos }
MediaType.MANGA -> { PrefName.MangaExtensionRepos }
else -> { null }
}
prefName?.let { repoList ->
PrefManager.getVal<Set<String>>(repoList).forEach { item ->
val view = ItemRepositoryBinding.inflate(
LayoutInflater.from(repoInventory.context), repoInventory, true
)
view.repositoryItem.text = item.removePrefix("https://raw.githubusercontent.com")
view.repositoryItem.setOnClickListener {
AlertDialog.Builder(this@ExtensionsActivity, R.style.MyPopup)
.setTitle(R.string.rem_repository)
.setMessage(item)
.setPositiveButton(getString(R.string.ok)) { dialog, _ ->
val repos = PrefManager.getVal<Set<String>>(prefName).minus(item)
PrefManager.setVal(prefName, repos)
repoInventory.removeView(view.root)
CoroutineScope(Dispatchers.IO).launch {
when (type) {
MediaType.ANIME -> { animeExtensionManager.findAvailableExtensions() }
MediaType.MANGA -> { mangaExtensionManager.findAvailableExtensions() }
else -> { }
}
}
dialog.dismiss()
}
.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
dialog.dismiss()
}
.create()
.show()
}
view.repositoryItem.setOnLongClickListener {
it.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
copyToClipboard(item, true)
true
}
}
}
}
private fun processEditorAction(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)
) {
return@setOnEditorActionListener if (textView.text.isNullOrBlank()) {
false
} else {
processUserInput(textView.text.toString(), mediaType)
true
}
}
false
}
}
private fun generateRepositoryButton(type: MediaType) {
val hintResource: Int? = when (type) {
MediaType.ANIME -> { R.string.anime_add_repository }
MediaType.MANGA -> { R.string.manga_add_repository }
else -> { null }
}
hintResource?.let { res ->
binding.openSettingsButton.setOnClickListener {
val dialogView = DialogRepositoriesBinding.inflate(
LayoutInflater.from(binding.openSettingsButton.context), null, false
)
dialogView.repositoryTextBox.hint = getString(res)
dialogView.repoInventory.apply {
getSavedRepositories(this, type)
}
val alertDialog = AlertDialog.Builder(this@ExtensionsActivity, R.style.MyPopup)
.setTitle(R.string.edit_repositories)
.setView(dialogView.root)
.setPositiveButton(getString(R.string.add)) { dialog, _ ->
if (!dialogView.repositoryTextBox.text.isNullOrBlank())
processUserInput(dialogView.repositoryTextBox.text.toString(), type)
}
.setNegativeButton(getString(R.string.close)) { dialog, _ ->
dialog.dismiss()
}
.create()
processEditorAction(dialogView.repositoryTextBox, type)
alertDialog.show()
alertDialog.window?.setDimAmount(0.8f)
}
}
}
}
interface SearchQueryHandler {

View file

@ -593,71 +593,50 @@ 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.replace("https://raw.githubusercontent.com/", "")
view.repositoryItem.setOnClickListener {
AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
.setTitle("Delete Anime Repository")
.setMessage(item)
.setPositiveButton(getString(R.string.ok)) { dialog, _ ->
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()
}
dialog.dismiss()
}
.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
dialog.dismiss()
}
.create()
.show()
}
view.repositoryItem.setOnLongClickListener {
copyToClipboard(item, true)
true
}
fun setExtensionOutput(repoInventory: ViewGroup, type: MediaType) {
repoInventory.removeAllViews()
val prefName: PrefName? = when (type) {
MediaType.ANIME -> { PrefName.AnimeExtensionRepos }
MediaType.MANGA -> { PrefName.MangaExtensionRepos }
else -> { null }
}
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.replace("https://raw.githubusercontent.com/", "")
view.repositoryItem.setOnClickListener {
AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
.setTitle("Delete Manga Repository")
.setMessage(item)
.setPositiveButton(getString(R.string.ok)) { dialog, _ ->
val manga = PrefManager.getVal<Set<String>>(PrefName.MangaExtensionRepos).minus(item)
PrefManager.setVal(PrefName.MangaExtensionRepos, manga)
it.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
setExtensionOutput()
CoroutineScope(Dispatchers.IO).launch {
mangaExtensionManager.findAvailableExtensions()
prefName?.let { repoList ->
PrefManager.getVal<Set<String>>(repoList).forEach { item ->
val view = ItemRepositoryBinding.inflate(
LayoutInflater.from(repoInventory.context), repoInventory, true
)
view.repositoryItem.text = item.removePrefix("https://raw.githubusercontent.com")
view.repositoryItem.setOnClickListener {
AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
.setTitle(R.string.rem_repository)
.setMessage(item)
.setPositiveButton(getString(R.string.ok)) { dialog, _ ->
val repos = PrefManager.getVal<Set<String>>(repoList).minus(item)
PrefManager.setVal(repoList, repos)
setExtensionOutput(repoInventory, type)
CoroutineScope(Dispatchers.IO).launch {
when (type) {
MediaType.ANIME -> { animeExtensionManager.findAvailableExtensions() }
MediaType.MANGA -> { mangaExtensionManager.findAvailableExtensions() }
else -> { }
}
}
dialog.dismiss()
}
dialog.dismiss()
}
.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
dialog.dismiss()
}
.create()
.show()
}
view.repositoryItem.setOnLongClickListener {
copyToClipboard(item, true)
true
.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
dialog.dismiss()
}
.create()
.show()
}
view.repositoryItem.setOnLongClickListener {
it.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
copyToClipboard(item, true)
true
}
}
repoInventory.isVisible = repoInventory.childCount > 0
}
mangaRepoInventory.isVisible = mangaRepoInventory.childCount > 0
}
fun processUserInput(input: String, mediaType: MediaType) {
@ -670,6 +649,7 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
CoroutineScope(Dispatchers.IO).launch {
animeExtensionManager.findAvailableExtensions()
}
setExtensionOutput(animeRepoInventory, MediaType.ANIME)
}
if (mediaType == MediaType.MANGA) {
val manga =
@ -678,8 +658,8 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
CoroutineScope(Dispatchers.IO).launch {
mangaExtensionManager.findAvailableExtensions()
}
setExtensionOutput(mangaRepoInventory, MediaType.MANGA)
}
setExtensionOutput()
}
fun processEditorAction(dialog: AlertDialog, editText: EditText, mediaType: MediaType) {
@ -688,15 +668,20 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
(keyEvent?.action == KeyEvent.ACTION_UP
&& keyEvent.keyCode == KeyEvent.KEYCODE_ENTER)
) {
processUserInput(textView.text.toString(), mediaType)
dialog.dismiss()
return@setOnEditorActionListener true
return@setOnEditorActionListener if (textView.text.isNullOrBlank()) {
false
} else {
processUserInput(textView.text.toString(), mediaType)
dialog.dismiss()
true
}
}
false
}
}
setExtensionOutput()
setExtensionOutput(animeRepoInventory, MediaType.ANIME)
setExtensionOutput(mangaRepoInventory, MediaType.MANGA)
animeAddRepository.setOnClickListener {
val dialogView = layoutInflater.inflate(R.layout.dialog_user_agent, null)
val editText =
@ -704,16 +689,11 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
hint = getString(R.string.anime_add_repository)
}
val alertDialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
.setTitle(R.string.add_repository)
.setMessage("Add additional repo for anime extensions")
.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("")
if (!editText.text.isNullOrBlank())
processUserInput(editText.text.toString(), MediaType.ANIME)
dialog.dismiss()
}
.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
@ -733,16 +713,11 @@ class SettingsActivity : AppCompatActivity(), SimpleDialog.OnDialogResultListene
hint = getString(R.string.manga_add_repository)
}
val alertDialog = AlertDialog.Builder(this@SettingsActivity, R.style.MyPopup)
.setTitle(R.string.add_repository)
.setTitle(R.string.manga_add_repository)
.setView(dialogView)
.setMessage("Add additional repo for manga extensions")
.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("")
if (!editText.text.isNullOrBlank())
processUserInput(editText.text.toString(), MediaType.MANGA)
dialog.dismiss()
}
.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->

View file

@ -35,16 +35,31 @@
android:textColor="?attr/colorPrimary"
android:textSize="16sp" />
<ImageButton
android:id="@+id/languageselect"
android:layout_width="48dp"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/sort_by"
app:srcCompat="@drawable/ic_round_translate_24"
app:tint="?attr/colorOnBackground" />
android:layout_marginHorizontal="16dp"
android:orientation="horizontal">
<ImageButton
android:id="@+id/openSettingsButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/sort_by"
app:srcCompat="@drawable/ic_github"
app:tint="?attr/colorOnBackground" />
<ImageButton
android:id="@+id/languageselect"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackground"
android:contentDescription="@string/sort_by"
app:srcCompat="@drawable/ic_round_translate_24"
app:tint="?attr/colorOnBackground" />
</LinearLayout>
</LinearLayout>

View file

@ -0,0 +1,26 @@
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<LinearLayout
android:id="@+id/repoInventory"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/repositoryTextBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:boxCornerRadiusBottomEnd="8dp"
app:boxCornerRadiusBottomStart="8dp"
app:boxCornerRadiusTopEnd="8dp"
app:boxCornerRadiusTopStart="8dp"
android:imeOptions="actionDone"
app:hintAnimationEnabled="true" />
</LinearLayout>

View file

@ -14,7 +14,7 @@
<string name="github" translatable="false">https://github.com/rebelonion/Dantotsu</string>
<string name="telegram" translatable="false" tools:ignore="Typos">https://t.me/+gzBCQExtLQo1YTNh </string>
<string name="coffee" translatable="false">https://www.buymeacoffee.com/rebelonion</string>
<string name="anilist_link">https://anilist.co/user/%1$s/</string>
<string name="myanilist_link">https://myanimelist.net/profile/%1$s/</string>
<string name="discord_link">https://discord.com/users/%1$s/</string>
@ -864,13 +864,11 @@ Non quae tempore quo provident laudantium qui illo dolor vel quia dolor et exerc
<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="add_repository">Add Repo</string>
<string name="long_click_delete">Long click to delete</string>
<string name="edit_repositories">Edit repositories</string>
<string name="rem_repository">Remove repository?</string>
<string name="trending_movies">Trending Movies</string>
<string name="include_list">Include list</string>
<string name="top_rated">Top rated</string>