diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 68841a8d..738d7be6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -200,6 +200,7 @@ android:parentActivityName=".MainActivity" /> + diff --git a/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt b/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt index bacc5e22..df97b2ec 100644 --- a/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt +++ b/app/src/main/java/ani/dantotsu/parsers/AniyomiAdapter.kt @@ -53,8 +53,11 @@ class DynamicAnimeParser(extension: AnimeExtension.Installed) : AnimeParser() { override val name = extension.name override val saveName = extension.name - override val hostUrl = extension.sources.first().name + override val hostUrl = + (extension.sources.first() as? AnimeHttpSource)?.baseUrl ?: extension.sources.first().name override val isNSFW = extension.isNsfw + override val icon = extension.icon + override var selectDub: Boolean get() = getDub() set(value) { @@ -324,8 +327,10 @@ class DynamicMangaParser(extension: MangaExtension.Installed) : MangaParser() { override val name = extension.name override val saveName = extension.name - override val hostUrl = extension.sources.first().name + override val hostUrl = + (extension.sources.first() as? HttpSource)?.baseUrl ?: extension.sources.first().name override val isNSFW = extension.isNsfw + override val icon = extension.icon override suspend fun loadChapters( mangaLink: String, diff --git a/app/src/main/java/ani/dantotsu/parsers/BaseParser.kt b/app/src/main/java/ani/dantotsu/parsers/BaseParser.kt index 2d83ab06..3ddfbb09 100644 --- a/app/src/main/java/ani/dantotsu/parsers/BaseParser.kt +++ b/app/src/main/java/ani/dantotsu/parsers/BaseParser.kt @@ -1,17 +1,21 @@ package ani.dantotsu.parsers +import android.graphics.drawable.Drawable import ani.dantotsu.FileUrl import ani.dantotsu.R import ani.dantotsu.currContext import ani.dantotsu.media.Media +import ani.dantotsu.okHttpClient import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.util.Logger import eu.kanade.tachiyomi.animesource.model.SAnime import eu.kanade.tachiyomi.source.model.SManga import me.xdrop.fuzzywuzzy.FuzzySearch +import okhttp3.Request import java.io.Serializable import java.net.URLDecoder import java.net.URLEncoder +import kotlin.system.measureTimeMillis abstract class BaseParser { @@ -41,6 +45,11 @@ abstract class BaseParser { * **/ open val language = "English" + /** + * Icon of the site, can be null + */ + open val icon: Drawable? = null + /** * Search for Anime/Manga/Novel, returns a List of Responses * @@ -133,10 +142,39 @@ abstract class BaseParser { return response } + /** + * ping the site to check if it's working or not. + * @return Triple : First Int is the status code, Second Int is the response time in milliseconds, Third String is the response message. + */ + fun ping(): Triple { + val client = okHttpClient + var statusCode = 0 + var responseTime: Int? = null + var responseMessage = "" + try { + val request = Request.Builder() + .url(hostUrl) + .build() + responseTime = measureTimeMillis { + client.newCall(request).execute().use { response -> + statusCode = response.code + responseMessage = response.message + } + }.toInt() + } catch (e: Exception) { + Logger.log("Failed to ping $name") + statusCode = -1 + responseMessage = if (e.message.isNullOrEmpty()) "None" else e.message!! + Logger.log(e) + } + return Triple(statusCode, responseTime, responseMessage) + } /** * Used to get an existing Search Response which was selected by the user. - * **/ + * @param mediaId : The mediaId of the Media object. + * @return ShowResponse? : The ShowResponse object if found, else null. + */ open suspend fun loadSavedShowResponse(mediaId: Int): ShowResponse? { checkIfVariablesAreEmpty() return PrefManager.getNullableCustomVal( @@ -148,7 +186,10 @@ abstract class BaseParser { /** * Used to save Shows Response using `saveName`. - * **/ + * @param mediaId : The mediaId of the Media object. + * @param response : The ShowResponse object to save. + * @param selected : Boolean : If the ShowResponse was selected by the user or not. + */ open fun saveShowResponse(mediaId: Int, response: ShowResponse?, selected: Boolean = false) { if (response != null) { checkIfVariablesAreEmpty() diff --git a/app/src/main/java/ani/dantotsu/parsers/ExtensionSelectItem.kt b/app/src/main/java/ani/dantotsu/parsers/ExtensionSelectItem.kt new file mode 100644 index 00000000..8c9c20d5 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/parsers/ExtensionSelectItem.kt @@ -0,0 +1,38 @@ +package ani.dantotsu.parsers + +import android.graphics.drawable.Drawable +import android.view.View +import ani.dantotsu.R +import ani.dantotsu.databinding.ItemExtensionSelectBinding +import com.xwray.groupie.viewbinding.BindableItem + +class ExtensionSelectItem( + private val name: String, + private val image: Drawable?, + private var isSelected: Boolean, + val selectCallback: (String, Boolean) -> Unit +) : BindableItem() { + private lateinit var binding: ItemExtensionSelectBinding + + override fun bind(viewBinding: ItemExtensionSelectBinding, position: Int) { + binding = viewBinding + binding.extensionNameTextView.text = name + image?.let { + binding.extensionIconImageView.setImageDrawable(it) + } + binding.extensionCheckBox.setOnCheckedChangeListener(null) + binding.extensionCheckBox.isChecked = isSelected + binding.extensionCheckBox.setOnCheckedChangeListener { _, isChecked -> + isSelected = isChecked + selectCallback(name, isChecked) + } + } + + override fun getLayout(): Int { + return R.layout.item_extension_select + } + + override fun initializeViewBinding(view: View): ItemExtensionSelectBinding { + return ItemExtensionSelectBinding.bind(view) + } +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/parsers/ExtensionTestItem.kt b/app/src/main/java/ani/dantotsu/parsers/ExtensionTestItem.kt new file mode 100644 index 00000000..c87bf268 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/parsers/ExtensionTestItem.kt @@ -0,0 +1,367 @@ +package ani.dantotsu.parsers + +import android.content.Context +import android.view.View +import androidx.core.view.isVisible +import ani.dantotsu.R +import ani.dantotsu.databinding.ItemExtensionTestBinding +import ani.dantotsu.getThemeColor +import com.xwray.groupie.viewbinding.BindableItem +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext + +class ExtensionTestItem( + private var extensionType: String, + private var testType: String, + private var extension: BaseParser, + private var searchString: String = "Chainsaw Man" +) : BindableItem() { + private lateinit var binding: ItemExtensionTestBinding + private lateinit var context: Context + private var job: Job? = null + private var isRunning = false + private var pingResult: Triple? = null + private var searchResultSize: Int? = null + private var episodeResultSize: Int? = null + private var serverResultSize: Int? = null + + override fun bind(viewBinding: ItemExtensionTestBinding, position: Int) { + binding = viewBinding + context = binding.root.context + binding.extensionIconImageView.setImageDrawable(extension.icon) + binding.extensionNameTextView.text = extension.name + binding.extensionLoading.isVisible = isRunning + hideAllResults() + + pingResult() + searchResult() + episodeResult() + serverResult() + } + + override fun getLayout(): Int { + return R.layout.item_extension_test + } + + override fun initializeViewBinding(view: View): ItemExtensionTestBinding { + return ItemExtensionTestBinding.bind(view) + } + + private fun hideAllResults() { + if (::binding.isInitialized.not()) return + binding.searchResultText.isVisible = false + binding.episodeResultText.isVisible = false + binding.serverResultText.isVisible = false + } + + fun cancelJob() { + job?.cancel() + job = null + binding.extensionLoading.isVisible = false + } + + fun startTest() { + pingResult = null + searchResultSize = null + episodeResultSize = null + serverResultSize = null + isRunning = true + hideAllResults() + job?.cancel() + job = Job() + CoroutineScope(Dispatchers.IO + job!!).launch { + when (extensionType) { + "anime" -> { + val extension = extension as AnimeParser + runAnimeTest(extension) + } + + "manga" -> { + val extension = extension as MangaParser + runMangaTest(extension) + } + + "novel" -> { + val extension = extension as NovelParser + runNovelTest(extension) + } + } + } + } + + private suspend fun runAnimeTest(extension: AnimeParser) { + pingResult = extension.ping() + withContext(Dispatchers.Main) { + pingResult() + } + if (testType == "ping") { + done() + return + } + val searchResult = extension.search(searchString) + searchResultSize = searchResult.size + withContext(Dispatchers.Main) { + searchResult() + } + if (searchResultSize == 0 || testType == "basic") { + done() + return + } + val episodeResult = extension.loadEpisodes("", null, searchResult.first().sAnime!!) + episodeResultSize = episodeResult.size + withContext(Dispatchers.Main) { + episodeResult() + } + if (episodeResultSize == 0) { + done() + return + } + val serverResult = extension.loadVideoServers("", null, episodeResult.first().sEpisode!!) + serverResultSize = serverResult.size + withContext(Dispatchers.Main) { + serverResult() + } + + done() + } + + private suspend fun runMangaTest(extension: MangaParser) { + pingResult = extension.ping() + withContext(Dispatchers.Main) { + pingResult() + } + if (testType == "ping") { + done() + return + } + val searchResult = extension.search(searchString) + searchResultSize = searchResult.size + withContext(Dispatchers.Main) { + searchResult() + } + if (searchResultSize == 0 || testType == "basic") { + done() + return + } + val chapterResult = extension.loadChapters("", null, searchResult.first().sManga!!) + episodeResultSize = chapterResult.size + withContext(Dispatchers.Main) { + episodeResult() + } + if (episodeResultSize == 0) { + done() + return + } + val serverResult = extension.loadImages("", chapterResult.first().sChapter) + serverResultSize = serverResult.size + withContext(Dispatchers.Main) { + serverResult() + } + + withContext(Dispatchers.Main) { + if (::binding.isInitialized ) + binding.extensionLoading.isVisible = false + isRunning = false + } + } + + private suspend fun runNovelTest(extension: NovelParser) { + withContext(Dispatchers.Main) { + pingResult() + } + if (testType == "ping") { + done() + return + } + val searchResult = extension.search(searchString) + searchResultSize = searchResult.size + withContext(Dispatchers.Main) { + searchResult() + } + if (searchResultSize == 0 || testType == "basic") { + done() + return + } + val chapterResult = extension.loadBook(searchResult.first().link, null) + episodeResultSize = chapterResult.links.size + withContext(Dispatchers.Main) { + episodeResult() + serverResult() + } + + withContext(Dispatchers.Main) { + if (::binding.isInitialized ) + binding.extensionLoading.isVisible = false + isRunning = false + } + } + + private fun done() { + if (::binding.isInitialized.not()) return + binding.extensionLoading.isVisible = false + isRunning = false + } + + private fun pingResult() { + if (::binding.isInitialized.not()) return + if (extensionType == "novel") { + binding.pingResultText.isVisible = true + binding.pingResultText.text = context.getString(R.string.test_not_supported) + binding.pingResultText.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_round_info_24, 0, 0, 0 + ) + return + } + if (pingResult == null) { + binding.pingResultText.isVisible = false + return + } else { + binding.pingResultText.isVisible = true + } + binding.pingResultText.setTextColor( + context.getThemeColor(com.google.android.material.R.attr.colorPrimary) + ) + val (code, time, message) = pingResult!! + if (code == 200) { + binding.pingResultText.text = context.getString(R.string.ping_success, time.toString()) + binding.pingResultText.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_circle_check, 0, 0, 0 + ) + return + } + binding.pingResultText.text = + context.getString(R.string.ping_error, code.toString(), message) + binding.pingResultText.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_circle_cancel, 0, 0, 0 + ) + binding.pingResultText.setTextColor( + context.getThemeColor(com.google.android.material.R.attr.colorError) + ) + } + + private fun searchResult() { + if (::binding.isInitialized.not()) return + if (searchResultSize == null) { + binding.searchResultText.isVisible = false + return + } + binding.searchResultText.setTextColor( + context.getThemeColor(com.google.android.material.R.attr.colorPrimary) + ) + binding.searchResultText.isVisible = true + if (searchResultSize == 0) { + val text = context.getString(R.string.title_search_test, + context.getString(R.string.no_results_found)) + binding.searchResultText.text = text + binding.searchResultText.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_circle_cancel, 0, 0, 0 + ) + binding.searchResultText.setTextColor( + context.getThemeColor(com.google.android.material.R.attr.colorError) + ) + return + } + val text = context.getString(R.string.title_search_test, + context.getString(R.string.results_found, searchResultSize.toString())) + binding.searchResultText.text = text + binding.searchResultText.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_circle_check, 0, 0, 0 + ) + } + + private fun episodeResult() { + if (::binding.isInitialized.not()) return + if (episodeResultSize == null) { + binding.episodeResultText.isVisible = false + return + } + binding.episodeResultText.setTextColor( + context.getThemeColor(com.google.android.material.R.attr.colorPrimary) + ) + binding.episodeResultText.isVisible = true + if (episodeResultSize == 0) { + val text = when(extensionType) { + "anime" -> context.getString(R.string.episode_search_test, + context.getString(R.string.no_results_found)) + "manga" -> context.getString(R.string.chapter_search_test, + context.getString(R.string.no_results_found)) + else -> context.getString(R.string.book_search_test, + context.getString(R.string.no_results_found)) + } + binding.episodeResultText.text = text + binding.episodeResultText.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_circle_cancel, 0, 0, 0 + ) + binding.episodeResultText.setTextColor( + context.getThemeColor(com.google.android.material.R.attr.colorError) + ) + return + } + val text = when(extensionType) { + "anime" -> context.getString(R.string.episode_search_test, + context.getString(R.string.results_found, episodeResultSize.toString())) + "manga" -> context.getString(R.string.chapter_search_test, + context.getString(R.string.results_found, episodeResultSize.toString())) + else -> context.getString(R.string.book_search_test, + context.getString(R.string.results_found, episodeResultSize.toString())) + } + binding.episodeResultText.text = text + binding.episodeResultText.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_circle_check, 0, 0, 0 + ) + } + + private fun serverResult() { + if (::binding.isInitialized.not()) return + if (extensionType == "novel") { + binding.pingResultText.isVisible = true + binding.pingResultText.text = context.getString(R.string.test_not_supported) + binding.pingResultText.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_round_info_24, 0, 0, 0 + ) + return + } + if (serverResultSize == null) { + binding.serverResultText.isVisible = false + return + } + binding.serverResultText.setTextColor( + context.getThemeColor(com.google.android.material.R.attr.colorPrimary) + ) + binding.serverResultText.isVisible = true + if (serverResultSize == 0) { + val text = when(extensionType) { + "anime" -> context.getString(R.string.video_search_test, + context.getString(R.string.no_results_found)) + "manga" -> context.getString(R.string.image_search_test, + context.getString(R.string.no_results_found)) + else -> context.getString(R.string.book_search_test, + context.getString(R.string.no_results_found)) + } + binding.serverResultText.text = text + binding.serverResultText.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_circle_cancel, 0, 0, 0 + ) + binding.serverResultText.setTextColor( + context.getThemeColor(com.google.android.material.R.attr.colorError) + ) + return + } + val text = when(extensionType) { + "anime" -> context.getString(R.string.video_search_test, + context.getString(R.string.results_found, serverResultSize.toString())) + "manga" -> context.getString(R.string.image_search_test, + context.getString(R.string.results_found, serverResultSize.toString())) + else -> context.getString(R.string.book_search_test, + context.getString(R.string.results_found, serverResultSize.toString())) + } + binding.serverResultText.text = text + binding.serverResultText.setCompoundDrawablesWithIntrinsicBounds( + R.drawable.ic_circle_check, 0, 0, 0 + ) + } + +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/parsers/ExtensionTestSettingsBottomDialog.kt b/app/src/main/java/ani/dantotsu/parsers/ExtensionTestSettingsBottomDialog.kt new file mode 100644 index 00000000..fcedad3f --- /dev/null +++ b/app/src/main/java/ani/dantotsu/parsers/ExtensionTestSettingsBottomDialog.kt @@ -0,0 +1,117 @@ +package ani.dantotsu.parsers + +import android.graphics.drawable.Drawable +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.LinearLayoutManager +import ani.dantotsu.BottomSheetDialogFragment +import ani.dantotsu.databinding.BottomSheetExtensionTestSettingsBinding +import ani.dantotsu.parsers.novel.NovelExtensionManager +import com.xwray.groupie.GroupieAdapter +import eu.kanade.tachiyomi.extension.anime.AnimeExtensionManager +import eu.kanade.tachiyomi.extension.manga.MangaExtensionManager +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get + +class ExtensionTestSettingsBottomDialog : BottomSheetDialogFragment() { + private var _binding: BottomSheetExtensionTestSettingsBinding? = null + private val binding get() = _binding!! + private val adapter: GroupieAdapter = GroupieAdapter() + private val animeExtension: AnimeExtensionManager = Injekt.get() + private val mangaExtensions: MangaExtensionManager = Injekt.get() + private val novelExtensions: NovelExtensionManager = Injekt.get() + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + _binding = BottomSheetExtensionTestSettingsBinding.inflate(inflater, container, false) + return _binding?.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + binding.extensionSelectionRecyclerView.adapter = adapter + binding.extensionSelectionRecyclerView.layoutManager = LinearLayoutManager( + context, + LinearLayoutManager.VERTICAL, + false + ) + binding.animeRadioButton.setOnCheckedChangeListener { _, b -> + if (b) { + extensionType = "anime" + extensionsToTest.clear() + setupAdapter() + } + } + binding.mangaRadioButton.setOnCheckedChangeListener { _, b -> + if (b) { + extensionType = "manga" + extensionsToTest.clear() + setupAdapter() + } + } + binding.novelsRadioButton.setOnCheckedChangeListener { _, b -> + if (b) { + extensionType = "novel" + extensionsToTest.clear() + setupAdapter() + } + } + binding.pingRadioButton.setOnCheckedChangeListener { _, b -> + if (b) { + testType = "ping" + } + } + binding.basicRadioButton.setOnCheckedChangeListener { _, b -> + if (b) { + testType = "basic" + } + } + binding.fullRadioButton.setOnCheckedChangeListener { _, b -> + if (b) { + testType = "full" + } + } + setupAdapter() + } + + override fun onDestroyView() { + _binding = null + super.onDestroyView() + } + + private fun setupAdapter() { + val namesAndUrls: Map = when (extensionType) { + "anime" -> animeExtension.installedExtensionsFlow.value.associate { it.name to it.icon } + "manga" -> mangaExtensions.installedExtensionsFlow.value.associate { it.name to it.icon } + "novel" -> novelExtensions.installedExtensionsFlow.value.associate { it.name to it.icon } + else -> emptyMap() + } + adapter.clear() + namesAndUrls.forEach { (name, icon) -> + val isSelected = extensionsToTest.contains(name) + adapter.add(ExtensionSelectItem(name, icon, isSelected, ::selectedCallback)) + } + } + + private fun selectedCallback(name: String, isSelected: Boolean) { + if (isSelected) { + extensionsToTest.add(name) + } else { + extensionsToTest.remove(name) + } + } + + companion object { + fun newInstance(): ExtensionTestSettingsBottomDialog { + return ExtensionTestSettingsBottomDialog() + } + + var extensionType = "anime" + var testType = "ping" + var extensionsToTest: MutableList = mutableListOf() + } +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/parsers/ParserTestActivity.kt b/app/src/main/java/ani/dantotsu/parsers/ParserTestActivity.kt new file mode 100644 index 00000000..7be91fe2 --- /dev/null +++ b/app/src/main/java/ani/dantotsu/parsers/ParserTestActivity.kt @@ -0,0 +1,112 @@ +package ani.dantotsu.parsers + +import android.os.Bundle +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.updateLayoutParams +import androidx.recyclerview.widget.LinearLayoutManager +import ani.dantotsu.R +import ani.dantotsu.databinding.ActivityParserTestBinding +import ani.dantotsu.initActivity +import ani.dantotsu.navBarHeight +import ani.dantotsu.statusBarHeight +import ani.dantotsu.themes.ThemeManager +import ani.dantotsu.toast +import com.xwray.groupie.GroupieAdapter + +class ParserTestActivity : AppCompatActivity() { + private lateinit var binding: ActivityParserTestBinding + val adapter = GroupieAdapter() + val extensionsToTest: MutableList = mutableListOf() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + ThemeManager(this).applyTheme() + initActivity(this) + binding = ActivityParserTestBinding.inflate(layoutInflater) + binding.toolbar.updateLayoutParams { + topMargin = statusBarHeight + } + binding.extensionResultsRecyclerView.updateLayoutParams { + bottomMargin = navBarHeight + } + setContentView(binding.root) + + binding.extensionResultsRecyclerView.adapter = adapter + binding.extensionResultsRecyclerView.layoutManager = LinearLayoutManager( + this, + LinearLayoutManager.VERTICAL, + false + ) + binding.backButton.setOnClickListener { + onBackPressedDispatcher.onBackPressed() + } + binding.optionsLayout.setOnClickListener { + ExtensionTestSettingsBottomDialog.newInstance() + .show(supportFragmentManager, "extension_test_settings") + } + + binding.startButton.setOnClickListener { + if (ExtensionTestSettingsBottomDialog.extensionsToTest.isEmpty()) { + toast(R.string.no_extensions_selected) + return@setOnClickListener + } + extensionsToTest.forEach { + it.cancelJob() + } + extensionsToTest.clear() + adapter.clear() + when (ExtensionTestSettingsBottomDialog.extensionType) { + "anime" -> { + ExtensionTestSettingsBottomDialog.extensionsToTest.forEach { name -> + val extension = + AnimeSources.list.find { source -> source.name == name }?.get?.value + extension?.let { + extensionsToTest.add( + ExtensionTestItem( + "anime", + ExtensionTestSettingsBottomDialog.testType, + it + ) + ) + } + } + } + "manga" -> { + ExtensionTestSettingsBottomDialog.extensionsToTest.forEach { name -> + val extension = + MangaSources.list.find { source -> source.name == name }?.get?.value + extension?.let { + extensionsToTest.add( + ExtensionTestItem( + "manga", + ExtensionTestSettingsBottomDialog.testType, + it + ) + ) + } + } + } + "novel" -> { + ExtensionTestSettingsBottomDialog.extensionsToTest.forEach { name -> + val extension = + NovelSources.list.find { source -> source.name == name }?.get?.value + extension?.let { + extensionsToTest.add( + ExtensionTestItem( + "novel", + ExtensionTestSettingsBottomDialog.testType, + it + ) + ) + } + } + } + } + extensionsToTest.forEach { + adapter.add(it) + it.startTest() + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt b/app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt index 0125c3df..0fa65612 100644 --- a/app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt +++ b/app/src/main/java/ani/dantotsu/settings/ExtensionsActivity.kt @@ -1,6 +1,7 @@ package ani.dantotsu.settings import android.app.AlertDialog +import android.content.Intent import android.os.Bundle import android.text.Editable import android.text.TextWatcher @@ -13,6 +14,7 @@ import android.view.inputmethod.EditorInfo import android.widget.AutoCompleteTextView import android.widget.EditText import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import androidx.core.view.updateLayoutParams import androidx.fragment.app.Fragment import androidx.viewpager2.adapter.FragmentStateAdapter @@ -28,6 +30,7 @@ import ani.dantotsu.media.MediaType import ani.dantotsu.navBarHeight import ani.dantotsu.others.AndroidBug5497Workaround import ani.dantotsu.others.LanguageMapper +import ani.dantotsu.parsers.ParserTestActivity import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.statusBarHeight @@ -70,6 +73,14 @@ class ExtensionsActivity : AppCompatActivity() { bottomMargin = statusBarHeight + navBarHeight } + binding.testButton.setOnClickListener { + ContextCompat.startActivity( + this, + Intent(this, ParserTestActivity::class.java), + null + ) + } + val tabLayout = findViewById(R.id.tabLayout) val viewPager = findViewById(R.id.viewPager) viewPager.offscreenPageLimit = 1 diff --git a/app/src/main/java/ani/dantotsu/settings/SettingsExtensionsActivity.kt b/app/src/main/java/ani/dantotsu/settings/SettingsExtensionsActivity.kt index 078d7b38..abf742ba 100644 --- a/app/src/main/java/ani/dantotsu/settings/SettingsExtensionsActivity.kt +++ b/app/src/main/java/ani/dantotsu/settings/SettingsExtensionsActivity.kt @@ -1,6 +1,7 @@ package ani.dantotsu.settings import android.app.AlertDialog +import android.content.Intent import android.os.Bundle import android.view.HapticFeedbackConstants import android.view.KeyEvent @@ -9,6 +10,7 @@ import android.view.ViewGroup import android.view.inputmethod.EditorInfo import android.widget.EditText import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import androidx.recyclerview.widget.LinearLayoutManager @@ -20,6 +22,7 @@ import ani.dantotsu.databinding.ItemRepositoryBinding import ani.dantotsu.initActivity import ani.dantotsu.media.MediaType import ani.dantotsu.navBarHeight +import ani.dantotsu.parsers.ParserTestActivity import ani.dantotsu.settings.saving.PrefManager import ani.dantotsu.settings.saving.PrefName import ani.dantotsu.statusBarHeight @@ -232,6 +235,20 @@ class SettingsExtensionsActivity : AppCompatActivity() { setExtensionOutput(it.attachView, MediaType.MANGA) } ), + Settings( + type = 1, + name = getString(R.string.extension_test), + desc = getString(R.string.extension_test_desc), + icon = R.drawable.ic_round_search_sources_24, + isActivity = true, + onClick = { + ContextCompat.startActivity( + context, + Intent(context, ParserTestActivity::class.java), + null + ) + } + ), Settings( type = 1, name = getString(R.string.user_agent), diff --git a/app/src/main/res/layout/activity_extensions.xml b/app/src/main/res/layout/activity_extensions.xml index 246c1785..a95edfed 100644 --- a/app/src/main/res/layout/activity_extensions.xml +++ b/app/src/main/res/layout/activity_extensions.xml @@ -41,6 +41,15 @@ android:layout_marginHorizontal="16dp" android:orientation="horizontal"> + + + + + + + + + + + + + + + + + + + + + +