Rewrite SignInScene with modern coroutines

This commit is contained in:
tarsin committed 2023-01-08 22:22:34 +08:00
1 parent a3be0dfddf
commit e2cd2ddc0d
2 files changed
+177 -280

No files matched your search

@@ -26,137 +26,9 @@ object EhClient {
internal fun enqueue(request: EhRequest, scope: CoroutineScope) {
check(!request.isActive) // Abort if attempt to execute an active request
request.job = scope.launchIO {
val method = request.method
val params = request.args
val callback: Callback<Any?>? = request.callback
try {
val result: Any? = when (method) {
METHOD_SIGN_IN -> EhEngine.signIn(
mOkHttpClient,
params!![0] as String,
params[1] as String
)
METHOD_GET_GALLERY_LIST -> EhEngine.getGalleryList(
mOkHttpClient,
params!![0] as String
)
METHOD_GET_GALLERY_DETAIL -> EhEngine.getGalleryDetail(
mOkHttpClient,
params!![0] as String?
)
METHOD_GET_PREVIEW_SET -> EhEngine.getPreviewSet(
mOkHttpClient,
params!![0] as String?
)
METHOD_GET_RATE_GALLERY -> EhEngine.rateGallery(
mOkHttpClient,
params!![0] as Long,
params[1] as String?,
params[2] as Long,
params[3] as String?,
params[4] as Float
)
METHOD_GET_COMMENT_GALLERY -> EhEngine.commentGallery(
mOkHttpClient,
params!![0] as String?,
params[1] as String,
params[2] as String?
)
METHOD_GET_GALLERY_TOKEN -> EhEngine.getGalleryToken(
mOkHttpClient,
params!![0] as Long,
params[1] as String?,
params[2] as Int
)
METHOD_GET_FAVORITES -> EhEngine.getFavorites(
mOkHttpClient,
params!![0] as String
)
METHOD_ADD_FAVORITES -> EhEngine.addFavorites(
mOkHttpClient,
params!![0] as Long,
params[1] as String?,
params[2] as Int,
params[3] as String?
)
METHOD_ADD_FAVORITES_RANGE -> @Suppress("UNCHECKED_CAST") EhEngine.addFavoritesRange(
mOkHttpClient,
params!![0] as LongArray,
params[1] as Array<String?>,
params[2] as Int
)
METHOD_MODIFY_FAVORITES -> EhEngine.modifyFavorites(
mOkHttpClient,
params!![0] as String,
params[1] as LongArray,
params[2] as Int
)
METHOD_GET_TORRENT_LIST -> EhEngine.getTorrentList(
mOkHttpClient,
params!![0] as String?,
params[1] as Long,
params[2] as String?
)
METHOD_GET_PROFILE -> EhEngine.getProfile(mOkHttpClient)
METHOD_VOTE_COMMENT -> EhEngine.voteComment(
mOkHttpClient,
params!![0] as Long,
params[1] as String?,
params[2] as Long,
params[3] as String?,
params[4] as Long,
params[5] as Int
)
METHOD_IMAGE_SEARCH -> EhEngine.imageSearch(
mOkHttpClient,
params!![0] as File,
params[1] as Boolean,
params[2] as Boolean,
params[3] as Boolean
)
METHOD_ARCHIVE_LIST -> EhEngine.getArchiveList(
mOkHttpClient,
params!![0] as String?,
params[1] as Long,
params[2] as String?
)
METHOD_DOWNLOAD_ARCHIVE -> EhEngine.downloadArchive(
mOkHttpClient,
params!![0] as Long,
params[1] as String?,
params[2] as String?,
params[3] as String?,
params[4] as Boolean
)
METHOD_VOTE_TAG -> EhEngine.voteTag(
mOkHttpClient,
params!![0] as Long,
params[1] as String?,
params[2] as Long,
params[3] as String?,
params[4] as String?,
params[5] as Int
)
METHOD_GET_UCONFIG -> EhEngine.getUConfig(mOkHttpClient)
else -> throw IllegalStateException("Can't detect method $method")
}
val result: Any? = execute(request.method, request.args)
withUIContext { callback?.onSuccess(result) }
} catch (e: Exception) {
if (e is CancellationException)
@@ -167,6 +39,136 @@ object EhClient {
}
}
suspend fun execute(method: Int, vararg params: Any?): Any? {
return when (method) {
METHOD_SIGN_IN -> EhEngine.signIn(
mOkHttpClient,
params[0] as String,
params[1] as String
)
METHOD_GET_GALLERY_LIST -> EhEngine.getGalleryList(
mOkHttpClient,
params[0] as String
)
METHOD_GET_GALLERY_DETAIL -> EhEngine.getGalleryDetail(
mOkHttpClient,
params[0] as String?
)
METHOD_GET_PREVIEW_SET -> EhEngine.getPreviewSet(
mOkHttpClient,
params[0] as String?
)
METHOD_GET_RATE_GALLERY -> EhEngine.rateGallery(
mOkHttpClient,
params[0] as Long,
params[1] as String?,
params[2] as Long,
params[3] as String?,
params[4] as Float
)
METHOD_GET_COMMENT_GALLERY -> EhEngine.commentGallery(
mOkHttpClient,
params[0] as String?,
params[1] as String,
params[2] as String?
)
METHOD_GET_GALLERY_TOKEN -> EhEngine.getGalleryToken(
mOkHttpClient,
params[0] as Long,
params[1] as String?,
params[2] as Int
)
METHOD_GET_FAVORITES -> EhEngine.getFavorites(
mOkHttpClient,
params[0] as String
)
METHOD_ADD_FAVORITES -> EhEngine.addFavorites(
mOkHttpClient,
params[0] as Long,
params[1] as String?,
params[2] as Int,
params[3] as String?
)
METHOD_ADD_FAVORITES_RANGE -> @Suppress("UNCHECKED_CAST") EhEngine.addFavoritesRange(
mOkHttpClient,
params[0] as LongArray,
params[1] as Array<String?>,
params[2] as Int
)
METHOD_MODIFY_FAVORITES -> EhEngine.modifyFavorites(
mOkHttpClient,
params[0] as String,
params[1] as LongArray,
params[2] as Int
)
METHOD_GET_TORRENT_LIST -> EhEngine.getTorrentList(
mOkHttpClient,
params[0] as String?,
params[1] as Long,
params[2] as String?
)
METHOD_GET_PROFILE -> EhEngine.getProfile(mOkHttpClient)
METHOD_VOTE_COMMENT -> EhEngine.voteComment(
mOkHttpClient,
params[0] as Long,
params[1] as String?,
params[2] as Long,
params[3] as String?,
params[4] as Long,
params[5] as Int
)
METHOD_IMAGE_SEARCH -> EhEngine.imageSearch(
mOkHttpClient,
params[0] as File,
params[1] as Boolean,
params[2] as Boolean,
params[3] as Boolean
)
METHOD_ARCHIVE_LIST -> EhEngine.getArchiveList(
mOkHttpClient,
params[0] as String?,
params[1] as Long,
params[2] as String?
)
METHOD_DOWNLOAD_ARCHIVE -> EhEngine.downloadArchive(
mOkHttpClient,
params[0] as Long,
params[1] as String?,
params[2] as String?,
params[3] as String?,
params[4] as Boolean
)
METHOD_VOTE_TAG -> EhEngine.voteTag(
mOkHttpClient,
params[0] as Long,
params[1] as String?,
params[2] as Long,
params[3] as String?,
params[4] as String?,
params[5] as Int
)
METHOD_GET_UCONFIG -> EhEngine.getUConfig(mOkHttpClient)
else -> throw IllegalStateException("Can't detect method $method")
}
}
interface Callback<E> {
fun onSuccess(result: E)
fun onFailure(e: Exception)
@@ -15,57 +15,37 @@
*/
package com.hippo.ehviewer.ui.scene
import android.content.Context
import android.graphics.Paint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.lifecycle.lifecycleScope
import com.hippo.app.BaseDialogBuilder
import com.hippo.ehviewer.EhApplication
import com.hippo.ehviewer.EhApplication.Companion.ehCookieStore
import com.hippo.ehviewer.R
import com.hippo.ehviewer.Settings
import com.hippo.ehviewer.UrlOpener
import com.hippo.ehviewer.client.EhClient
import com.hippo.ehviewer.client.EhRequest
import com.hippo.ehviewer.client.EhUrl
import com.hippo.ehviewer.client.EhUtils
import com.hippo.ehviewer.client.parser.ProfileParser
import com.hippo.ehviewer.databinding.SceneLoginBinding
import com.hippo.util.ExceptionUtils
import com.hippo.yorozuya.IntIdGenerator
import eu.kanade.tachiyomi.util.lang.launchIO
import eu.kanade.tachiyomi.util.lang.withUIContext
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
class SignInScene : BaseScene() {
private var _binding: SceneLoginBinding? = null
private val binding
get() = _binding!!
private var mSigningIn = false
private var mRequestId = IntIdGenerator.INVALID_ID
private var mSignInJob: Job? = null
override fun needShowLeftDrawer(): Boolean {
return false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
onInit()
} else {
onRestore(savedInstanceState)
}
}
private fun onInit() {}
private fun onRestore(savedInstanceState: Bundle) {
mRequestId = savedInstanceState.getInt(KEY_REQUEST_ID)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt(KEY_REQUEST_ID, mRequestId)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
@@ -98,42 +78,22 @@ class SignInScene : BaseScene() {
binding.touristMode.setOnClickListener {
// Set gallery size SITE_E if skip sign in
Settings.putGallerySite(EhUrl.SITE_E)
redirectTo()
}
val application = EhApplication.application
if (application.containGlobalStuff(mRequestId)) {
mSigningIn = true
// request exist
showProgress(false)
finishSignIn()
}
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Show IME
if (View.INVISIBLE != binding.progress.visibility) {
showSoftInput(binding.username)
}
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
private fun showProgress(animation: Boolean) {
private fun showProgress() {
if (View.VISIBLE != binding.progress.visibility) {
binding.progress.run {
if (animation) {
alpha = 0.0f
visibility = View.VISIBLE
animate().alpha(1.0f).setDuration(500).start()
} else {
alpha = 1.0f
visibility = View.VISIBLE
}
alpha = 0.0f
visibility = View.VISIBLE
animate().alpha(1.0f).setDuration(500).start()
}
}
}
@@ -143,9 +103,7 @@ class SignInScene : BaseScene() {
}
private fun signIn() {
if (mSigningIn) {
return
}
if (mSignInJob?.isActive == true) return
val username = binding.username.text.toString()
val password = binding.password.text.toString()
if (username.isEmpty()) {
@@ -161,40 +119,33 @@ class SignInScene : BaseScene() {
binding.passwordLayout.error = null
}
hideSoftInput()
showProgress(true)
showProgress()
// Clean up for sign in
EhUtils.signOut()
val callback: EhCallback<*, *> = SignInListener(context)
mRequestId =
(requireActivity().applicationContext as EhApplication).putGlobalStuff(callback)
val request = EhRequest()
.setMethod(EhClient.METHOD_SIGN_IN)
.setArgs(username, password)
.setCallback(callback)
request.enqueue(this)
mSigningIn = true
mSignInJob = lifecycleScope.launchIO {
runCatching {
(EhClient.execute(EhClient.METHOD_SIGN_IN, username, password) as String).let {
Settings.putDisplayName(it)
}
}.onFailure {
it.printStackTrace()
withUIContext {
hideProgress()
showResultErrorDialog(it)
}
}.onSuccess {
// This fragment's lifecycle is to be finished
GlobalScope.launchIO {
getProfile()
}
withUIContext {
finishSignIn()
}
}
}
}
private val profile: Unit
get() {
val context = context
val activity = mainActivity
if (null == context || null == activity) {
return
}
hideSoftInput()
showProgress(true)
val callback: EhCallback<*, *> = GetProfileListener(context)
mRequestId = (context.applicationContext as EhApplication).putGlobalStuff(callback)
val request = EhRequest()
.setMethod(EhClient.METHOD_GET_PROFILE)
.setCallback(callback)
request.enqueue()
EhRequest().setMethod(EhClient.METHOD_GET_UCONFIG).enqueue()
}
private fun redirectTo() {
private fun finishSignIn() {
Settings.putNeedSignIn(false)
if (Settings.getSelectSite()) {
navigate(R.id.selectSiteScene, null)
@@ -203,81 +154,25 @@ class SignInScene : BaseScene() {
}
}
private fun whetherToSkip(e: Exception?) {
val context = context ?: return
BaseDialogBuilder(context)
private fun showResultErrorDialog(e: Throwable) {
BaseDialogBuilder(requireContext())
.setTitle(R.string.sign_in_failed)
.setMessage(
"""
${ExceptionUtils.getReadableString(e!!)}
${getString(R.string.sign_in_failed_tip)}
""".trimIndent()
${ExceptionUtils.getReadableString(e)}
${getString(R.string.sign_in_failed_tip)}
""".trimIndent()
)
.setPositiveButton(R.string.get_it, null)
.show()
}
}
fun onSignInEnd(e: Exception?) {
context ?: return
if (ehCookieStore.hasSignedIn()) {
profile
} else {
mSigningIn = false
hideProgress()
whetherToSkip(e)
suspend fun getProfile() {
runCatching {
(EhClient.execute(EhClient.METHOD_GET_PROFILE) as ProfileParser.Result).run {
Settings.putDisplayName(displayName)
Settings.putAvatar(avatar)
}
}
fun onGetProfileEnd() {
mSigningIn = false
redirectTo()
}
private inner class SignInListener(context: Context?) :
EhCallback<SignInScene?, String>(context) {
override fun onSuccess(result: String) {
application.removeGlobalStuff(this)
Settings.putDisplayName(result)
val scene = this@SignInScene
scene.onSignInEnd(null)
}
override fun onFailure(e: Exception) {
application.removeGlobalStuff(this)
e.printStackTrace()
val scene = this@SignInScene
scene.onSignInEnd(e)
}
override fun onCancel() {
application.removeGlobalStuff(this)
}
}
private inner class GetProfileListener(context: Context?) :
EhCallback<SignInScene?, ProfileParser.Result>(context) {
override fun onSuccess(result: ProfileParser.Result) {
application.removeGlobalStuff(this)
Settings.putDisplayName(result.displayName)
Settings.putAvatar(result.avatar)
val scene = this@SignInScene
scene.onGetProfileEnd()
}
override fun onFailure(e: Exception) {
application.removeGlobalStuff(this)
e.printStackTrace()
val scene = this@SignInScene
scene.onGetProfileEnd()
}
override fun onCancel() {
application.removeGlobalStuff(this)
}
}
companion object {
private const val KEY_REQUEST_ID = "request_id"
}
}