Convert EhLoginActivity to compose

This commit is contained in:
Jobobby04 2022-09-13 18:18:48 -04:00
parent f28342601b
commit 3807fb0607
2 changed files with 237 additions and 146 deletions

View File

@ -0,0 +1,197 @@
package eu.kanade.presentation.webview
import android.content.pm.ApplicationInfo
import android.webkit.CookieManager
import android.webkit.WebView
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.LinearProgressIndicator
import androidx.compose.material3.ProgressIndicatorDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import com.google.accompanist.web.AccompanistWebViewClient
import com.google.accompanist.web.LoadingState
import com.google.accompanist.web.WebContent
import com.google.accompanist.web.WebView
import com.google.accompanist.web.rememberWebViewNavigator
import com.google.accompanist.web.rememberWebViewState
import eu.kanade.presentation.components.AppBar
import eu.kanade.presentation.components.Button
import eu.kanade.presentation.components.Scaffold
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.util.system.setDefaultSettings
@Composable
fun EhLoginWebViewScreen(
onUp: () -> Unit,
onPageFinished: (view: WebView, url: String) -> Unit,
onClickRecheckLoginStatus: (loadUrl: (String) -> Unit) -> Unit,
onClickAlternateLoginPage: (loadUrl: (String) -> Unit) -> Unit,
onClickSkipPageRestyling: (loadUrl: (String) -> Unit) -> Unit,
onClickCustomIgneousCookie: () -> Unit,
) {
val state = rememberWebViewState(
url = "https://forums.e-hentai.org/index.php?act=Login",
)
val navigator = rememberWebViewNavigator()
val loading by produceState(true) {
CookieManager.getInstance().removeAllCookies {
value = false
}
}
Scaffold(
topBar = {
Box {
AppBar(
title = "ExHentai login",
navigateUp = onUp,
navigationIcon = Icons.Default.Close,
)
when (val loadingState = state.loadingState) {
is LoadingState.Initializing -> LinearProgressIndicator(
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter),
)
is LoadingState.Loading -> {
val animatedProgress by animateFloatAsState(
(loadingState as? LoadingState.Loading)?.progress ?: 1f,
animationSpec = ProgressIndicatorDefaults.ProgressAnimationSpec,
)
LinearProgressIndicator(
progress = animatedProgress,
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter),
)
}
else -> {}
}
}
},
) { contentPadding ->
if (loading) {
return@Scaffold
}
val webClient = remember {
object : AccompanistWebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
onPageFinished(view ?: return, url ?: return)
}
}
}
var showAdvancedOptions by remember {
mutableStateOf(false)
}
Box(Modifier.padding(contentPadding)) {
Box {
WebView(
state = state,
navigator = navigator,
modifier = Modifier.padding(bottom = 48.dp),
onCreated = { webView ->
webView.setDefaultSettings()
// Debug mode (chrome://inspect/#devices)
if (BuildConfig.DEBUG &&
0 != webView.context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE
) {
WebView.setWebContentsDebuggingEnabled(true)
}
},
client = webClient,
)
Row(
Modifier
.fillMaxWidth()
.height(48.dp)
.align(Alignment.BottomCenter),
horizontalArrangement = Arrangement.SpaceBetween,
) {
Button(onClick = onUp, Modifier.weight(0.5F)) {
Text(text = stringResource(android.R.string.cancel))
}
Button(onClick = { showAdvancedOptions = true }, Modifier.weight(0.5F)) {
Text(text = stringResource(R.string.pref_category_advanced))
}
}
}
if (showAdvancedOptions) {
Box(Modifier.background(Color(0xb5000000))) {
Dialog(onDismissRequest = { showAdvancedOptions = false }) {
fun loadUrl(url: String) {
state.content = WebContent.Url(url)
}
Column(Modifier.fillMaxWidth(0.8F)) {
Button(
onClick = {
onClickRecheckLoginStatus(::loadUrl)
showAdvancedOptions = false
},
modifier = Modifier.fillMaxWidth(),
) {
Text(text = stringResource(R.string.recheck_login_status))
}
Button(
onClick = {
onClickAlternateLoginPage(::loadUrl)
showAdvancedOptions = false
},
modifier = Modifier.fillMaxWidth(),
) {
Text(text = stringResource(R.string.alternative_login_page))
}
Button(
onClick = {
onClickSkipPageRestyling(::loadUrl)
showAdvancedOptions = false
},
modifier = Modifier.fillMaxWidth(),
) {
Text(text = stringResource(R.string.skip_page_restyling))
}
Button(
onClick = {
onClickCustomIgneousCookie()
showAdvancedOptions = false
},
modifier = Modifier.fillMaxWidth(),
) {
Text(text = stringResource(R.string.custom_igneous_cookie))
}
Button(onClick = { showAdvancedOptions = false }, Modifier.fillMaxWidth()) {
Text(text = stringResource(android.R.string.cancel))
}
}
}
}
}
}
}
}

View File

@ -2,33 +2,21 @@ package exh.ui.login
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.ApplicationInfo
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.webkit.CookieManager import android.webkit.CookieManager
import android.webkit.WebChromeClient
import android.webkit.WebView import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.Toast import android.widget.Toast
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import eu.kanade.tachiyomi.BuildConfig import eu.kanade.presentation.webview.EhLoginWebViewScreen
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.databinding.EhActivityLoginBinding
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
import eu.kanade.tachiyomi.util.lang.launchUI
import eu.kanade.tachiyomi.util.system.WebViewUtil import eu.kanade.tachiyomi.util.system.WebViewUtil
import eu.kanade.tachiyomi.util.system.setDefaultSettings
import eu.kanade.tachiyomi.util.system.toast import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.setComposeContent
import eu.kanade.tachiyomi.widget.materialdialogs.setTextInput import eu.kanade.tachiyomi.widget.materialdialogs.setTextInput
import exh.log.xLogD import exh.log.xLogD
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import reactivecircus.flowbinding.appcompat.navigationClicks
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.net.HttpCookie import java.net.HttpCookie
import java.util.Locale import java.util.Locale
@ -37,13 +25,7 @@ import java.util.Locale
* LoginController * LoginController
*/ */
class EhLoginActivity : BaseActivity() { class EhLoginActivity : BaseActivity() {
lateinit var binding: EhActivityLoginBinding private val preferenceManager: PreferencesHelper by injectLazy()
val preferenceManager: PreferencesHelper by injectLazy()
val sourceManager: SourceManager by injectLazy()
private var bundle: Bundle? = null
private var igneous: String? = null private var igneous: String? = null
@ -56,95 +38,28 @@ class EhLoginActivity : BaseActivity() {
return return
} }
try { setComposeContent {
binding = EhActivityLoginBinding.inflate(layoutInflater) EhLoginWebViewScreen(
setContentView(binding.root) onUp = { finish() },
} catch (e: Throwable) { onPageFinished = ::onPageFinished,
// Potentially throws errors like "Error inflating class android.webkit.WebView" onClickRecheckLoginStatus = ::recheckLoginStatus,
toast(R.string.information_webview_required, Toast.LENGTH_LONG) onClickAlternateLoginPage = ::alternateLoginPage,
finish() onClickSkipPageRestyling = ::skipPageRestyling,
return onClickCustomIgneousCookie = ::openIgneousDialog,
} )
title = "ExHentai login"
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
binding.toolbar.navigationClicks()
.onEach { finish() }
.launchIn(lifecycleScope)
onViewCreated()
if (bundle == null) {
binding.webview.setDefaultSettings()
// Debug mode (chrome://inspect/#devices)
if (BuildConfig.DEBUG && 0 != applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) {
WebView.setWebContentsDebuggingEnabled(true)
}
binding.webview.webChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
binding.progressBar.isVisible = true
binding.progressBar.progress = newProgress
if (newProgress == 100) {
binding.progressBar.isInvisible = true
}
super.onProgressChanged(view, newProgress)
}
}
} else {
binding.webview.restoreState(bundle!!)
}
if (bundle == null) {
startWebview()
} }
} }
fun onViewCreated() { private fun recheckLoginStatus(loadUrl: (String) -> Unit) {
binding.btnCancel.setOnClickListener { finish() } loadUrl("https://exhentai.org/")
}
binding.btnAdvanced.setOnClickListener { private fun alternateLoginPage(loadUrl: (String) -> Unit) {
binding.advancedOptions.isVisible = true loadUrl("https://e-hentai.org/bounce_login.php")
binding.webview.isVisible = false }
binding.btnAdvanced.isEnabled = false
binding.btnCancel.isEnabled = false
}
binding.btnClose.setOnClickListener { private fun skipPageRestyling(loadUrl: (String) -> Unit) {
hideAdvancedOptions() loadUrl("https://forums.e-hentai.org/index.php?act=Login&$PARAM_SKIP_INJECT=true")
}
binding.btnRecheck.setOnClickListener {
hideAdvancedOptions()
binding.webview.loadUrl("https://exhentai.org/")
}
binding.btnAltLogin.setOnClickListener {
hideAdvancedOptions()
binding.webview.loadUrl("https://e-hentai.org/bounce_login.php")
}
binding.btnSkipRestyle.setOnClickListener {
hideAdvancedOptions()
binding.webview.loadUrl("https://forums.e-hentai.org/index.php?act=Login&$PARAM_SKIP_INJECT=true")
}
binding.btnIgneousCookie.setOnClickListener {
hideAdvancedOptions()
openIgneousDialog()
}
CookieManager.getInstance().removeAllCookies {
launchUI {
if (bundle == null) {
startWebview()
}
}
}
} }
private fun openIgneousDialog() { private fun openIgneousDialog() {
@ -164,54 +79,33 @@ class EhLoginActivity : BaseActivity() {
.show() .show()
} }
private fun hideAdvancedOptions() { private fun onPageFinished(view: WebView, url: String) {
binding.advancedOptions.isVisible = false xLogD(url)
binding.webview.isVisible = true val parsedUrl = Uri.parse(url)
binding.btnAdvanced.isEnabled = true if (parsedUrl.host.equals("forums.e-hentai.org", ignoreCase = true)) {
binding.btnCancel.isEnabled = true // Hide distracting content
} if (!parsedUrl.queryParameterNames.contains(PARAM_SKIP_INJECT)) {
view.evaluateJavascript(HIDE_JS, null)
}
// Check login result
private fun startWebview() { if (parsedUrl.getQueryParameter("code")?.toInt() != 0) {
binding.webview.setDefaultSettings() if (checkLoginCookies(url)) view.loadUrl("https://exhentai.org/")
}
binding.webview.loadUrl("https://forums.e-hentai.org/index.php?act=Login") } else if (parsedUrl.host.equals("exhentai.org", ignoreCase = true)) {
// At ExHentai, check that everything worked out...
binding.webview.webViewClient = object : WebViewClient() { if (applyExHentaiCookies(url)) {
override fun onPageFinished(view: WebView, url: String) { preferenceManager.enableExhentai().set(true)
super.onPageFinished(view, url) setResult(RESULT_OK)
xLogD(url) finish()
val parsedUrl = Uri.parse(url)
if (parsedUrl.host.equals("forums.e-hentai.org", ignoreCase = true)) {
// Hide distracting content
if (!parsedUrl.queryParameterNames.contains(PARAM_SKIP_INJECT)) {
view.evaluateJavascript(HIDE_JS, null)
}
// Check login result
if (parsedUrl.getQueryParameter("code")?.toInt() != 0) {
if (checkLoginCookies(url)) view.loadUrl("https://exhentai.org/")
}
} else if (parsedUrl.host.equals("exhentai.org", ignoreCase = true)) {
// At ExHentai, check that everything worked out...
if (applyExHentaiCookies(url)) {
preferenceManager.enableExhentai().set(true)
setResult(RESULT_OK)
finish()
}
}
} }
} }
} }
override fun onDestroy() {
binding.webview?.destroy()
super.onDestroy()
}
/** /**
* Check if we are logged in * Check if we are logged in
*/ */
fun checkLoginCookies(url: String): Boolean { private fun checkLoginCookies(url: String): Boolean {
getCookies(url)?.let { parsed -> getCookies(url)?.let { parsed ->
return parsed.count { return parsed.count {
( (
@ -227,7 +121,7 @@ class EhLoginActivity : BaseActivity() {
/** /**
* Parse cookies at ExHentai * Parse cookies at ExHentai
*/ */
fun applyExHentaiCookies(url: String): Boolean { private fun applyExHentaiCookies(url: String): Boolean {
getCookies(url)?.let { parsed -> getCookies(url)?.let { parsed ->
var memberId: String? = null var memberId: String? = null