feat: Some QoL features (GH-85)

Co-authored-by: AshbornXS <75546030+AshbornXS@users.noreply.github.com>
This commit is contained in:
Ahmad Ansori Palembani 2024-06-08 08:36:56 +07:00
parent 45caff3ae0
commit b4638017dd
Signed by: null2264
GPG key ID: BA64F8B60AF3EFB6
17 changed files with 223 additions and 27 deletions

View file

@ -22,4 +22,18 @@ class BasePreferences(private val preferenceStore: PreferenceStore) {
fun hasShownOnboarding() = preferenceStore.getBoolean(Preference.appStateKey("onboarding_complete"), false) fun hasShownOnboarding() = preferenceStore.getBoolean(Preference.appStateKey("onboarding_complete"), false)
fun crashReport() = preferenceStore.getBoolean("pref_crash_report", true) fun crashReport() = preferenceStore.getBoolean("pref_crash_report", true)
fun longTapBrowseNavBehaviour() = preferenceStore.getEnum("pref_browser_long_tap", LongTapBrowse.DEFAULT)
enum class LongTapBrowse(@StringRes val titleResId: Int) {
DEFAULT(R.string.browse_long_tap_default),
SEARCH(R.string.browse_long_tap_search),
}
fun longTapRecentsNavBehaviour() = preferenceStore.getEnum("pref_recents_long_tap", LongTapRecents.DEFAULT)
enum class LongTapRecents(@StringRes val titleResId: Int) {
DEFAULT(R.string.recents_long_tap_default),
LAST_READ(R.string.recents_long_tap_last_read)
}
} }

View file

@ -356,6 +356,14 @@ class DownloadBottomSheet @JvmOverloads constructor(
?: Pair(listOf<Download>(), listOf<Download>()) ?: Pair(listOf<Download>(), listOf<Download>())
presenter.reorder(selectedSeries + otherSeries) presenter.reorder(selectedSeries + otherSeries)
} }
R.id.move_to_bottom_series -> {
val (selectedSeries, otherSeries) = adapter?.currentItems
?.filterIsInstance<DownloadItem>()
?.map(DownloadItem::download)
?.partition { item.download.manga.id == it.manga.id }
?: Pair(listOf<Download>(), listOf<Download>())
presenter.reorder(otherSeries + selectedSeries)
}
R.id.cancel_series -> { R.id.cancel_series -> {
val allDownloadsForSeries = adapter?.currentItems val allDownloadsForSeries = adapter?.currentItems
?.filterIsInstance<DownloadItem>() ?.filterIsInstance<DownloadItem>()

View file

@ -2,6 +2,9 @@ package eu.kanade.tachiyomi.ui.extension
import android.content.pm.PackageInstaller import android.content.pm.PackageInstaller
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
import eu.kanade.tachiyomi.extension.ExtensionInstallerJob import eu.kanade.tachiyomi.extension.ExtensionInstallerJob
import eu.kanade.tachiyomi.extension.ExtensionManager import eu.kanade.tachiyomi.extension.ExtensionManager
import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.extension.model.Extension
@ -10,12 +13,15 @@ import eu.kanade.tachiyomi.extension.model.InstalledExtensionsOrder
import eu.kanade.tachiyomi.extension.util.ExtensionLoader import eu.kanade.tachiyomi.extension.util.ExtensionLoader
import eu.kanade.tachiyomi.ui.migration.BaseMigrationPresenter import eu.kanade.tachiyomi.ui.migration.BaseMigrationPresenter
import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.LocaleHelper
import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.withUIContext import eu.kanade.tachiyomi.util.system.withUIContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
typealias ExtensionTuple = typealias ExtensionTuple =
Triple<List<Extension.Installed>, List<Extension.Untrusted>, List<Extension.Available>> Triple<List<Extension.Installed>, List<Extension.Untrusted>, List<Extension.Available>>
@ -24,16 +30,19 @@ typealias ExtensionIntallInfo = Pair<InstallStep, PackageInstaller.SessionInfo?>
/** /**
* Presenter of [ExtensionBottomSheet]. * Presenter of [ExtensionBottomSheet].
*/ */
class ExtensionBottomPresenter : BaseMigrationPresenter<ExtensionBottomSheet>() { class ExtensionBottomPresenter : BaseMigrationPresenter<ExtensionBottomSheet>(), DownloadQueue.DownloadListener {
private var extensions = emptyList<ExtensionItem>() private var extensions = emptyList<ExtensionItem>()
val downloadManager: DownloadManager = Injekt.get()
private var currentDownloads = hashMapOf<String, ExtensionIntallInfo>() private var currentDownloads = hashMapOf<String, ExtensionIntallInfo>()
private var firstLoad = true private var firstLoad = true
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
downloadManager.addListener(this)
presenterScope.launch { presenterScope.launch {
val extensionJob = async { val extensionJob = async {
extensionManager.findAvailableExtensions() extensionManager.findAvailableExtensions()
@ -279,4 +288,11 @@ class ExtensionBottomPresenter : BaseMigrationPresenter<ExtensionBottomSheet>()
extensionManager.trust(pkgName, versionCode, signatureHash) extensionManager.trust(pkgName, versionCode, signatureHash)
} }
} }
override fun updateDownload(download: Download) = updateDownloads()
override fun updateDownloads() {
presenterScope.launchUI {
view?.updateDownloadStatus(!downloadManager.isPaused())
}
}
} }

View file

@ -514,4 +514,8 @@ class ExtensionBottomSheet @JvmOverloads constructor(context: Context, attrs: At
return if (index == -1) POSITION_NONE else index return if (index == -1) POSITION_NONE else index
} }
} }
fun updateDownloadStatus(isRunning: Boolean) {
(controller.activity as? MainActivity)?.downloadStatusChanged(isRunning)
}
} }

View file

@ -2172,4 +2172,8 @@ open class LibraryController(
destroyActionModeIfNeeded() destroyActionModeIfNeeded()
} }
} }
fun updateDownloadStatus(isRunning: Boolean) {
(activity as? MainActivity)?.downloadStatusChanged(isRunning)
}
} }

View file

@ -15,6 +15,8 @@ import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.database.models.MangaCategory import eu.kanade.tachiyomi.data.database.models.MangaCategory
import eu.kanade.tachiyomi.data.database.models.Track import eu.kanade.tachiyomi.data.database.models.Track
import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.data.download.model.DownloadQueue
import eu.kanade.tachiyomi.data.preference.DelayedLibrarySuggestionsJob import eu.kanade.tachiyomi.data.preference.DelayedLibrarySuggestionsJob
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.data.track.TrackManager
@ -45,6 +47,7 @@ import eu.kanade.tachiyomi.util.manga.MangaCoverMetadata
import eu.kanade.tachiyomi.util.mapStatus import eu.kanade.tachiyomi.util.mapStatus
import eu.kanade.tachiyomi.util.system.executeOnIO import eu.kanade.tachiyomi.util.system.executeOnIO
import eu.kanade.tachiyomi.util.system.launchIO import eu.kanade.tachiyomi.util.system.launchIO
import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.withUIContext import eu.kanade.tachiyomi.util.system.withUIContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -69,7 +72,7 @@ class LibraryPresenter(
private val downloadManager: DownloadManager = Injekt.get(), private val downloadManager: DownloadManager = Injekt.get(),
private val chapterFilter: ChapterFilter = Injekt.get(), private val chapterFilter: ChapterFilter = Injekt.get(),
private val trackManager: TrackManager = Injekt.get(), private val trackManager: TrackManager = Injekt.get(),
) : BaseCoroutinePresenter<LibraryController>() { ) : BaseCoroutinePresenter<LibraryController>(), DownloadQueue.DownloadListener {
private val getLibraryManga: GetLibraryManga by injectLazy() private val getLibraryManga: GetLibraryManga by injectLazy()
private val context = preferences.context private val context = preferences.context
@ -147,6 +150,7 @@ class LibraryPresenter(
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
downloadManager.addListener(this)
if (!controllerIsSubClass) { if (!controllerIsSubClass) {
lastLibraryItems?.let { libraryItems = it } lastLibraryItems?.let { libraryItems = it }
lastCategories?.let { categories = it } lastCategories?.let { categories = it }
@ -1493,4 +1497,11 @@ class LibraryPresenter(
} }
} }
} }
override fun updateDownload(download: Download) = updateDownloads()
override fun updateDownloads() {
presenterScope.launchUI {
view?.updateDownloadStatus(!downloadManager.isPaused())
}
}
} }

View file

@ -75,6 +75,7 @@ import dev.yokai.presentation.onboarding.OnboardingController
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.Migrations import eu.kanade.tachiyomi.Migrations
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.DatabaseHelper
import eu.kanade.tachiyomi.data.download.DownloadJob import eu.kanade.tachiyomi.data.download.DownloadJob
import eu.kanade.tachiyomi.data.download.DownloadManager import eu.kanade.tachiyomi.data.download.DownloadManager
import eu.kanade.tachiyomi.data.library.LibraryUpdateJob import eu.kanade.tachiyomi.data.library.LibraryUpdateJob
@ -99,6 +100,7 @@ import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.ui.more.AboutController import eu.kanade.tachiyomi.ui.more.AboutController
import eu.kanade.tachiyomi.ui.more.OverflowDialog import eu.kanade.tachiyomi.ui.more.OverflowDialog
import eu.kanade.tachiyomi.ui.more.stats.StatsController import eu.kanade.tachiyomi.ui.more.stats.StatsController
import eu.kanade.tachiyomi.ui.reader.ReaderActivity
import eu.kanade.tachiyomi.ui.recents.RecentsController import eu.kanade.tachiyomi.ui.recents.RecentsController
import eu.kanade.tachiyomi.ui.recents.RecentsViewType import eu.kanade.tachiyomi.ui.recents.RecentsViewType
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
@ -106,10 +108,12 @@ import eu.kanade.tachiyomi.ui.setting.SettingsLegacyController
import eu.kanade.tachiyomi.ui.setting.controllers.SettingsMainController import eu.kanade.tachiyomi.ui.setting.controllers.SettingsMainController
import eu.kanade.tachiyomi.ui.source.BrowseController import eu.kanade.tachiyomi.ui.source.BrowseController
import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController
import eu.kanade.tachiyomi.ui.source.globalsearch.GlobalSearchController
import eu.kanade.tachiyomi.util.manga.MangaCoverMetadata import eu.kanade.tachiyomi.util.manga.MangaCoverMetadata
import eu.kanade.tachiyomi.util.manga.MangaShortcutManager import eu.kanade.tachiyomi.util.manga.MangaShortcutManager
import eu.kanade.tachiyomi.util.system.contextCompatDrawable import eu.kanade.tachiyomi.util.system.contextCompatDrawable
import eu.kanade.tachiyomi.util.system.dpToPx import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.executeOnIO
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.hasSideNavBar import eu.kanade.tachiyomi.util.system.hasSideNavBar
import eu.kanade.tachiyomi.util.system.ignoredSystemInsets import eu.kanade.tachiyomi.util.system.ignoredSystemInsets
@ -167,6 +171,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>() {
private val downloadManager: DownloadManager by injectLazy() private val downloadManager: DownloadManager by injectLazy()
private val mangaShortcutManager: MangaShortcutManager by injectLazy() private val mangaShortcutManager: MangaShortcutManager by injectLazy()
private val extensionManager: ExtensionManager by injectLazy() private val extensionManager: ExtensionManager by injectLazy()
private val db: DatabaseHelper by injectLazy()
private val hideBottomNav private val hideBottomNav
get() = router.backstackSize > 1 && router.backstack[1].controller !is DialogController get() = router.backstackSize > 1 && router.backstack[1].controller !is DialogController
private val hideAppBar private val hideAppBar
@ -390,16 +395,48 @@ open class MainActivity : BaseActivity<MainActivityBinding>() {
} }
true true
} }
for (id in listOf(R.id.nav_recents, R.id.nav_browse)) { nav.getItemView(R.id.nav_recents)?.setOnLongClickListener {
nav.getItemView(id)?.setOnLongClickListener { if (nav.selectedItemId != R.id.nav_recents) {
nav.selectedItemId = id nav.selectedItemId = R.id.nav_recents
nav.post {
val controller =
router.backstack.firstOrNull()?.controller as? BottomSheetController
controller?.showSheet()
}
true
} }
when (basePreferences.longTapRecentsNavBehaviour().get()) {
BasePreferences.LongTapRecents.DEFAULT -> {
nav.post {
val controller =
router.backstack.firstOrNull()?.controller as? BottomSheetController
controller?.showSheet()
}
}
BasePreferences.LongTapRecents.LAST_READ -> {
lifecycleScope.launchUI {
val lastReadChapter =
db.getHistoryUngrouped("", 0, true).executeOnIO().maxByOrNull { it.history.last_read }
lastReadChapter ?: return@launchUI
val manga = lastReadChapter.manga
val chapter = lastReadChapter.chapter
startActivity(ReaderActivity.newIntent(this@MainActivity, manga, chapter))
}
}
}
true
}
nav.getItemView(R.id.nav_browse)?.setOnLongClickListener {
if (nav.selectedItemId != R.id.nav_browse) {
nav.selectedItemId = R.id.nav_browse
}
when (basePreferences.longTapBrowseNavBehaviour().get()) {
BasePreferences.LongTapBrowse.DEFAULT -> {
nav.post {
val controller =
router.backstack.firstOrNull()?.controller as? BottomSheetController
controller?.showSheet()
}
}
BasePreferences.LongTapBrowse.SEARCH ->
router.pushController(GlobalSearchController().withFadeTransaction())
}
true
} }
val container: ViewGroup = binding.controllerContainer val container: ViewGroup = binding.controllerContainer
@ -1486,11 +1523,13 @@ open class MainActivity : BaseActivity<MainActivityBinding>() {
} }
} }
private fun downloadStatusChanged(downloading: Boolean) { fun downloadStatusChanged(downloading: Boolean) {
lifecycleScope.launchUI { lifecycleScope.launchUI {
val hasQueue = downloading || downloadManager.hasQueue() val hasQueue = downloading || downloadManager.hasQueue()
if (hasQueue) { if (hasQueue) {
nav.getOrCreateBadge(R.id.nav_recents) val badge = nav.getOrCreateBadge(R.id.nav_recents)
badge.number = downloadManager.queue.size
if (downloading) badge.backgroundColor = -870219 else badge.backgroundColor = Color.GRAY
showDLQueueTutorial() showDLQueueTutorial()
} else { } else {
nav.removeBadge(R.id.nav_recents) nav.removeBadge(R.id.nav_recents)

View file

@ -9,11 +9,13 @@ import android.view.View
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat import androidx.core.os.LocaleListCompat
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import dev.yokai.domain.base.BasePreferences
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.updater.AppDownloadInstallJob import eu.kanade.tachiyomi.data.updater.AppDownloadInstallJob
import eu.kanade.tachiyomi.ui.setting.SettingsLegacyController import eu.kanade.tachiyomi.ui.setting.SettingsLegacyController
import eu.kanade.tachiyomi.ui.setting.ThemePreference import eu.kanade.tachiyomi.ui.setting.ThemePreference
import eu.kanade.tachiyomi.ui.setting.bindTo
import eu.kanade.tachiyomi.ui.setting.defaultValue import eu.kanade.tachiyomi.ui.setting.defaultValue
import eu.kanade.tachiyomi.ui.setting.infoPreference import eu.kanade.tachiyomi.ui.setting.infoPreference
import eu.kanade.tachiyomi.ui.setting.intListPreference import eu.kanade.tachiyomi.ui.setting.intListPreference
@ -230,6 +232,28 @@ class SettingsGeneralController : SettingsLegacyController() {
} }
} }
} }
preferenceCategory {
titleRes = R.string.navigation
listPreference(activity) {
bindTo(basePreferences.longTapRecentsNavBehaviour())
titleRes = R.string.recents_long_tap
val values = BasePreferences.LongTapRecents.entries.toList()
entriesRes = values.map { it.titleResId }.toTypedArray()
entryValues = values.map { it.name }.toTypedArray().toList()
}
listPreference(activity) {
bindTo(basePreferences.longTapBrowseNavBehaviour())
titleRes = R.string.browse_long_tap
val values = BasePreferences.LongTapBrowse.entries.toList()
entriesRes = values.map { it.titleResId }.toTypedArray()
entryValues = values.map { it.name }.toTypedArray().toList()
}
}
} }
override fun onDestroyView(view: View) { override fun onDestroyView(view: View) {

View file

@ -23,6 +23,7 @@ import eu.kanade.tachiyomi.ui.main.SearchControllerInterface
import eu.kanade.tachiyomi.ui.manga.MangaDetailsController import eu.kanade.tachiyomi.ui.manga.MangaDetailsController
import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController import eu.kanade.tachiyomi.ui.source.browse.BrowseSourceController
import eu.kanade.tachiyomi.util.addOrRemoveToFavorites import eu.kanade.tachiyomi.util.addOrRemoveToFavorites
import eu.kanade.tachiyomi.util.system.extensionIntentForText
import eu.kanade.tachiyomi.util.system.rootWindowInsetsCompat import eu.kanade.tachiyomi.util.system.rootWindowInsetsCompat
import eu.kanade.tachiyomi.util.view.activityBinding import eu.kanade.tachiyomi.util.view.activityBinding
import eu.kanade.tachiyomi.util.view.isControllerVisible import eu.kanade.tachiyomi.util.view.isControllerVisible
@ -163,7 +164,15 @@ open class GlobalSearchController(
activityBinding?.searchToolbar?.searchItem?.expandActionView() activityBinding?.searchToolbar?.searchItem?.expandActionView()
activityBinding?.searchToolbar?.searchView?.setQuery(presenter.query, false) activityBinding?.searchToolbar?.searchView?.setQuery(presenter.query, false)
if (presenter.query.isBlank()) {
activityBinding?.searchToolbar?.searchView?.requestFocus()
}
setOnQueryTextChangeListener(activityBinding?.searchToolbar?.searchView, onlyOnSubmit = true, hideKbOnSubmit = true) { setOnQueryTextChangeListener(activityBinding?.searchToolbar?.searchView, onlyOnSubmit = true, hideKbOnSubmit = true) {
// try to handle the query as a manga URL
applicationContext?.extensionIntentForText(it ?: "")?.let {
startActivity(it)
}
presenter.search(it ?: "") presenter.search(it ?: "")
setTitle() // Update toolbar title setTitle() // Update toolbar title
true true
@ -177,7 +186,9 @@ open class GlobalSearchController(
val searchItem = activityBinding?.searchToolbar?.searchItem ?: return val searchItem = activityBinding?.searchToolbar?.searchItem ?: return
searchItem.expandActionView() searchItem.expandActionView()
searchView.setQuery(presenter.query, false) searchView.setQuery(presenter.query, false)
searchView.clearFocus() if (presenter.query.isNotBlank()) {
searchView.clearFocus()
}
} }
if (type == ControllerChangeType.POP_ENTER && lastPosition > -1) { if (type == ControllerChangeType.POP_ENTER && lastPosition > -1) {
val holder = binding.recycler.findViewHolderForAdapterPosition(lastPosition) as? GlobalSearchHolder val holder = binding.recycler.findViewHolderForAdapterPosition(lastPosition) as? GlobalSearchHolder
@ -221,6 +232,11 @@ open class GlobalSearchController(
customTitle = view.context?.getString(R.string.loading) customTitle = view.context?.getString(R.string.loading)
setTitle() setTitle()
} }
// try to handle the query as a manga URL
applicationContext?.extensionIntentForText(presenter.query)?.let {
startActivity(it)
}
} }
override fun onDestroyView(view: View) { override fun onDestroyView(view: View) {

View file

@ -134,6 +134,9 @@ open class BaseWebViewActivity : BaseActivity<WebviewActivityBinding>() {
override fun onReceivedTitle(view: WebView?, title: String?) { override fun onReceivedTitle(view: WebView?, title: String?) {
super.onReceivedTitle(view, title) super.onReceivedTitle(view, title)
this@BaseWebViewActivity.title = title this@BaseWebViewActivity.title = title
binding.toolbarTitle.text = title
binding.toolbarSubtitle.text = view?.url
binding.toolbarSubtitle.isSelected = true
} }
} }
val marginB = binding.webview.marginBottom val marginB = binding.webview.marginBottom

View file

@ -12,6 +12,7 @@ import androidx.activity.OnBackPressedCallback
import androidx.activity.addCallback import androidx.activity.addCallback
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.system.WebViewClientCompat import eu.kanade.tachiyomi.util.system.WebViewClientCompat
@ -19,6 +20,7 @@ import eu.kanade.tachiyomi.util.system.extensionIntentForText
import eu.kanade.tachiyomi.util.system.getResourceColor import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.openInBrowser import eu.kanade.tachiyomi.util.system.openInBrowser
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import okhttp3.HttpUrl.Companion.toHttpUrl
import timber.log.Timber import timber.log.Timber
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
@ -27,6 +29,8 @@ open class WebViewActivity : BaseWebViewActivity() {
private val sourceManager by injectLazy<SourceManager>() private val sourceManager by injectLazy<SourceManager>()
private var bundle: Bundle? = null private var bundle: Bundle? = null
private val network: NetworkHelper by injectLazy()
private var backPressedCallback: OnBackPressedCallback? = null private var backPressedCallback: OnBackPressedCallback? = null
private val backCallback = { private val backCallback = {
if (binding.webview.canGoBack()) binding.webview.goBack() if (binding.webview.canGoBack()) binding.webview.goBack()
@ -166,10 +170,17 @@ open class WebViewActivity : BaseWebViewActivity() {
R.id.action_web_share -> shareWebpage() R.id.action_web_share -> shareWebpage()
R.id.action_web_browser -> openInBrowser() R.id.action_web_browser -> openInBrowser()
R.id.action_open_in_app -> openUrlInApp() R.id.action_open_in_app -> openUrlInApp()
R.id.action_web_clear_cookies -> clearCookies()
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
private fun clearCookies() {
val url = binding.webview.url ?: return
val cleared = network.cookieJar.remove(url.toHttpUrl())
toast("Cleared $cleared cookies for: $url")
}
private fun openUrlInApp() { private fun openUrlInApp() {
val url = binding.webview.url ?: return val url = binding.webview.url ?: return
extensionIntentForText(url)?.let { startActivity(it) } extensionIntentForText(url)?.let { startActivity(it) }

View file

@ -37,6 +37,8 @@ fun WebView.setDefaultSettings() {
databaseEnabled = true databaseEnabled = true
useWideViewPort = true useWideViewPort = true
loadWithOverviewMode = true loadWithOverviewMode = true
builtInZoomControls = true
displayZoomControls = false
cacheMode = WebSettings.LOAD_DEFAULT cacheMode = WebSettings.LOAD_DEFAULT
} }
} }

View file

@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/web_view_layout" android:id="@+id/web_view_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -10,11 +9,11 @@
android:orientation="vertical"> android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout <com.google.android.material.appbar.AppBarLayout
android:orientation="vertical"
android:id="@+id/web_linear_layout" android:id="@+id/web_linear_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true" android:fitsSystemWindows="true"
android:layout_height="wrap_content"> android:orientation="vertical">
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"
@ -23,9 +22,39 @@
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:background="?attr/colorSurface" android:background="?attr/colorSurface"
android:theme="?attr/actionBarTheme" android:theme="?attr/actionBarTheme"
app:titleTextColor="?actionBarTintColor" app:titleTextColor="?attr/actionBarTintColor"
app:navigationIcon="@drawable/ic_close_24dp" app:navigationIcon="@drawable/ic_close_24dp"
app:layout_scrollFlags="scroll|enterAlways" /> app:layout_scrollFlags="scroll|enterAlways">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/toolbar_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="?attr/actionBarTintColor"
android:textSize="20sp"
android:singleLine="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<TextView
android:id="@+id/toolbar_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:scrollHorizontally="true"
android:singleLine="true"
android:textColor="?attr/actionBarTintColor"
android:layout_below="@+id/toolbar_title"
android:layout_alignStart="@+id/toolbar_title" />
</RelativeLayout>
</com.google.android.material.appbar.MaterialToolbar>
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
@ -36,18 +65,17 @@
<WebView <WebView
android:id="@+id/webview" android:id="@+id/webview"
android:nestedScrollingEnabled="true"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" > android:layout_height="match_parent"
android:nestedScrollingEnabled="true">
<ProgressBar <ProgressBar
android:id="@+id/progressBar" android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal" style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="2dp" android:layout_height="2dp"
android:progressTint="?attr/colorSecondary"
android:progressBackgroundTint="?attr/colorSurface" android:progressBackgroundTint="?attr/colorSurface"
/> android:progressTint="?attr/colorSecondary" />
</WebView> </WebView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View file

@ -9,6 +9,9 @@
<item android:id="@+id/move_to_top_series" <item android:id="@+id/move_to_top_series"
android:title="@string/move_series_to_top" /> android:title="@string/move_series_to_top" />
<item android:id="@+id/move_to_bottom_series"
android:title="@string/move_series_to_bottom" />
<item android:id="@+id/cancel_series" <item android:id="@+id/cancel_series"
android:title="@string/cancel_all_for_series" /> android:title="@string/cancel_all_for_series" />
</menu> </menu>

View file

@ -29,4 +29,9 @@
android:title="@string/open_in_browser" android:title="@string/open_in_browser"
app:showAsAction="never" /> app:showAsAction="never" />
<item
android:id="@+id/action_web_clear_cookies"
android:title="@string/clear_cookies"
app:showAsAction="never" />
</menu> </menu>

View file

@ -972,6 +972,7 @@
<string name="pref_inverted_colors">Invertido</string> <string name="pref_inverted_colors">Invertido</string>
<string name="empty_backup_error">Nenhuma entrada na biblioteca para fazer backup</string> <string name="empty_backup_error">Nenhuma entrada na biblioteca para fazer backup</string>
<string name="move_series_to_top">Mover série para o topo</string> <string name="move_series_to_top">Mover série para o topo</string>
<string name="move_series_to_bottom">Mover série para o fundo</string>
<string name="ascending">Crescente</string> <string name="ascending">Crescente</string>
<string name="date">Data</string> <string name="date">Data</string>
<string name="descending">Decrescente</string> <string name="descending">Decrescente</string>

View file

@ -311,6 +311,9 @@
<string name="only_downloaded">Only downloaded</string> <string name="only_downloaded">Only downloaded</string>
<string name="unread_or_downloaded">Unread or downloaded</string> <string name="unread_or_downloaded">Unread or downloaded</string>
<string name="clear_history">Clear history</string> <string name="clear_history">Clear history</string>
<string name="recents_long_tap_default">Show download queue</string>
<string name="recents_long_tap_last_read">Open last read chapter</string>
<string name="recents_long_tap">Long tap Recents behaviour</string>
<!-- Browse --> <!-- Browse -->
<string name="search_filters">Search filters</string> <string name="search_filters">Search filters</string>
@ -331,6 +334,9 @@
<string name="last_used">Last used</string> <string name="last_used">Last used</string>
<string name="local_source_help_guide">Local source guide</string> <string name="local_source_help_guide">Local source guide</string>
<string name="check_site_in_web">Check website in WebView</string> <string name="check_site_in_web">Check website in WebView</string>
<string name="browse_long_tap_default">Open extensions / migration menu</string>
<string name="browse_long_tap_search">Open global search</string>
<string name="browse_long_tap">Long tap Browse behaviour</string>
<!-- Other Screens --> <!-- Other Screens -->
@ -990,6 +996,7 @@
<string name="downloading_">Downloading: %1$s</string> <string name="downloading_">Downloading: %1$s</string>
<string name="cancel_all">Cancel all</string> <string name="cancel_all">Cancel all</string>
<string name="move_series_to_top">Move series to top</string> <string name="move_series_to_top">Move series to top</string>
<string name="move_series_to_bottom">Move series to bottom</string>
<string name="downloads_swipe_tutorial">Downloads can be cancelled by swiping them away\nSwipe this tip to dismiss it</string> <string name="downloads_swipe_tutorial">Downloads can be cancelled by swiping them away\nSwipe this tip to dismiss it</string>
<string name="cancel_all_for_series">Cancel all for this series</string> <string name="cancel_all_for_series">Cancel all for this series</string>
<string name="downloaded">Downloaded</string> <string name="downloaded">Downloaded</string>