From 8a2cb42546e113d32129b4221687eb1e0d8ca957 Mon Sep 17 00:00:00 2001 From: FooIbar <118464521+FooIbar@users.noreply.github.com> Date: Fri, 10 Feb 2023 02:01:57 +0800 Subject: [PATCH] Support reset image limits --- .../java/com/hippo/ehviewer/Settings.java | 1 + .../com/hippo/ehviewer/client/EhEngine.kt | 64 +++++++++++++ .../java/com/hippo/ehviewer/client/EhUrl.kt | 3 +- .../ehviewer/client/parser/HomeParser.kt | 25 +++++ .../preference/ImageLimitsPreference.kt | 95 +++++++++++++++++++ .../hippo/ehviewer/ui/fragment/EhFragment.kt | 5 + app/src/main/res/values-zh-rCN/strings.xml | 5 + app/src/main/res/values/strings.xml | 5 + app/src/main/res/xml/eh_settings.xml | 28 ++++-- 9 files changed, 220 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/com/hippo/ehviewer/preference/ImageLimitsPreference.kt diff --git a/app/src/main/java/com/hippo/ehviewer/Settings.java b/app/src/main/java/com/hippo/ehviewer/Settings.java index bb7209c01..bc6dd0111 100755 --- a/app/src/main/java/com/hippo/ehviewer/Settings.java +++ b/app/src/main/java/com/hippo/ehviewer/Settings.java @@ -45,6 +45,7 @@ public class Settings { public static final String KEY_THEME = "theme"; public static final String KEY_ACCOUNT = "account"; + public static final String KEY_IMAGE_LIMITS = "image_limits"; public static final String KEY_BLACK_DARK_THEME = "black_dark_theme"; public static final int THEME_SYSTEM = -1; public static final String KEY_GALLERY_SITE = "gallery_site"; diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhEngine.kt b/app/src/main/java/com/hippo/ehviewer/client/EhEngine.kt index 1abda77d3..e35c839c1 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/EhEngine.kt +++ b/app/src/main/java/com/hippo/ehviewer/client/EhEngine.kt @@ -51,6 +51,8 @@ import com.hippo.ehviewer.client.parser.VoteTagParser import com.hippo.network.StatusCodeException import com.hippo.util.ExceptionUtils import com.hippo.yorozuya.AssertUtils +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.delay import okhttp3.FormBody import okhttp3.Headers @@ -783,6 +785,68 @@ object EhEngine { } } + @Throws(Throwable::class) + private suspend fun getImageLimitsInternal(): HomeParser.Limits { + val url = EhUrl.URL_HOME + Log.d(TAG, url) + val request = EhRequestBuilder(url, null).build() + val call = okHttpClient.newCall(request) + var body: String? = null + var headers: Headers? = null + var code = -1 + try { + call.executeAsync().use { response -> + code = response.code + headers = response.headers + body = response.body.string() + return HomeParser.parse(body!!) + } + } catch (e: Throwable) { + ExceptionUtils.throwIfFatal(e) + transformException(code, headers, body, e) + throw e + } + } + + @Throws(Throwable::class) + suspend fun getImageLimits(): HomeParser.Result = coroutineScope { + val limitsDeferred = async { + getImageLimitsInternal() + } + val fundsDeferred = async { + getFunds() + } + HomeParser.Result(limitsDeferred.await(), fundsDeferred.await()) + } + + @Throws(Throwable::class) + suspend fun resetImageLimits(): HomeParser.Limits? { + val builder = FormBody.Builder() + .add("act", "limits") + .add("reset", "Reset Limit") + val url = EhUrl.URL_HOME + Log.d(TAG, url) + val request = EhRequestBuilder(url, null) + .post(builder.build()) + .build() + val call = okHttpClient.newCall(request) + var body: String? = null + var headers: Headers? = null + var code = -1 + try { + call.executeAsync().use { response -> + code = response.code + headers = response.headers + body = response.body.string() + return HomeParser.parseResetLimits(body!!) + } + } catch (e: Throwable) { + ExceptionUtils.throwIfFatal(e) + transformException(code, headers, body, e) + throw e + } + } + @Throws(Throwable::class) private suspend fun getProfileInternal( url: String, referer: String diff --git a/app/src/main/java/com/hippo/ehviewer/client/EhUrl.kt b/app/src/main/java/com/hippo/ehviewer/client/EhUrl.kt index 4f816ef05..19e890b9f 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/EhUrl.kt +++ b/app/src/main/java/com/hippo/ehviewer/client/EhUrl.kt @@ -44,7 +44,8 @@ object EhUrl { const val URL_SIGN_IN = "https://forums.e-hentai.org/index.php?act=Login" const val URL_REGISTER = "https://forums.e-hentai.org/index.php?act=Reg&CODE=00" const val URL_FORUMS = "https://forums.e-hentai.org/" - const val URL_FUNDS = "https://e-hentai.org/exchange.php?t=gp" + const val URL_FUNDS = HOST_E + "exchange.php?t=gp" + const val URL_HOME = HOST_E + "home.php" const val REFERER_EX = "https://$DOMAIN_EX" const val ORIGIN_EX = REFERER_EX const val REFERER_E = "https://$DOMAIN_E" diff --git a/app/src/main/java/com/hippo/ehviewer/client/parser/HomeParser.kt b/app/src/main/java/com/hippo/ehviewer/client/parser/HomeParser.kt index f17829ac6..4df94118f 100644 --- a/app/src/main/java/com/hippo/ehviewer/client/parser/HomeParser.kt +++ b/app/src/main/java/com/hippo/ehviewer/client/parser/HomeParser.kt @@ -1,10 +1,33 @@ package com.hippo.ehviewer.client.parser import com.hippo.ehviewer.client.exception.ParseException +import org.jsoup.Jsoup object HomeParser { private val PATTERN_FUNDS = Regex("Available: ([\\d,]+) Credits.*Available: ([\\d,]+) kGP", RegexOption.DOT_MATCHES_ALL) + private const val RESET_SUCCEED = "Image limit was successfully reset." + + fun parse(body: String): Limits { + Jsoup.parse(body).selectFirst("div.homebox")?.let { + val es = it.select("p > strong") + if (es.size == 3) { + val current = ParserUtils.parseInt(es[0].text(), 0) + val maximum = ParserUtils.parseInt(es[1].text(), 0) + val resetCost = ParserUtils.parseInt(es[2].text(), 0) + return Limits(current, maximum, resetCost) + } + } + throw ParseException("Parse image limits error", body) + } + + fun parseResetLimits(body: String): Limits? { + return if (body.contains(RESET_SUCCEED)){ + null + } else { + parse(body) + } + } fun parseFunds(body: String): Funds { PATTERN_FUNDS.find(body)?.groupValues?.run { @@ -15,5 +38,7 @@ object HomeParser { throw ParseException("Parse funds error", body) } + data class Limits(val current: Int = 0, val maximum: Int, val resetCost: Int = 0) data class Funds(val fundsGP: Int, val fundsC: Int) + class Result(val limits: Limits, val funds: Funds) } \ No newline at end of file diff --git a/app/src/main/java/com/hippo/ehviewer/preference/ImageLimitsPreference.kt b/app/src/main/java/com/hippo/ehviewer/preference/ImageLimitsPreference.kt new file mode 100644 index 000000000..12efdd8ca --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/preference/ImageLimitsPreference.kt @@ -0,0 +1,95 @@ +package com.hippo.ehviewer.preference + +import android.content.Context +import android.content.DialogInterface +import android.util.AttributeSet +import android.view.View +import android.widget.Button +import androidx.appcompat.app.AlertDialog +import androidx.lifecycle.LifecycleCoroutineScope +import androidx.lifecycle.lifecycleScope +import com.hippo.ehviewer.R +import com.hippo.ehviewer.client.EhEngine +import com.hippo.ehviewer.client.parser.HomeParser +import com.hippo.ehviewer.ui.SettingsActivity +import com.hippo.ehviewer.ui.scene.BaseScene +import com.hippo.preference.DialogPreference +import eu.kanade.tachiyomi.util.lang.launchIO +import eu.kanade.tachiyomi.util.lang.withUIContext + +class ImageLimitsPreference(context: Context, attrs: AttributeSet) : + DialogPreference(context, attrs), View.OnClickListener { + private val mActivity = context as SettingsActivity + private val placeholder = context.getString(R.string.please_wait) + private lateinit var coroutineScope: LifecycleCoroutineScope + private lateinit var resetButton: Button + private lateinit var mDialog: AlertDialog + private lateinit var mLimits: HomeParser.Limits + private lateinit var mFunds: HomeParser.Funds + + override fun onPrepareDialogBuilder(builder: AlertDialog.Builder) { + super.onPrepareDialogBuilder(builder) + builder.setMessage(placeholder) + } + + override fun onDialogCreated(dialog: AlertDialog) { + super.onDialogCreated(dialog) + mDialog = dialog + coroutineScope = dialog.lifecycleScope + resetButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE) + resetButton.setOnClickListener(this) + resetButton.isEnabled = false + coroutineScope.launchIO { + getImageLimits() + } + } + + private suspend fun getImageLimits() { + runCatching { + EhEngine.getImageLimits() + }.onFailure { + it.printStackTrace() + withUIContext { + mDialog.setMessage(it.message) + } + }.onSuccess { + mLimits = it.limits + mFunds = it.funds + withUIContext { + bind() + } + } + } + + private fun bind() { + val (current, maximum, resetCost) = mLimits + val (fundsGP, fundsC) = mFunds + val cost = if (fundsGP >= resetCost) "$resetCost GP" else "$resetCost Credits" + val message = mActivity.getString(R.string.current_limits, "$current / $maximum", cost) + + "\n" + mActivity.getString(R.string.current_funds, "$fundsGP+", fundsC) + mDialog.setMessage(message) + resetButton.isEnabled = resetCost in 1..maxOf(fundsGP, fundsC) + } + + override fun onClick(v: View) { + resetButton.isEnabled = false + mDialog.setMessage(placeholder) + coroutineScope.launchIO { + runCatching { + EhEngine.resetImageLimits() + }.onFailure { + it.printStackTrace() + withUIContext { + mDialog.setMessage(it.message) + } + }.onSuccess { + withUIContext { + mLimits = it ?: HomeParser.Limits(maximum = mLimits.maximum).also { + mActivity.showTip(R.string.reset_limits_succeed, BaseScene.LENGTH_SHORT) + } + bind() + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/EhFragment.kt b/app/src/main/java/com/hippo/ehviewer/ui/fragment/EhFragment.kt index 1f1cfb062..5234f78a7 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/EhFragment.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/fragment/EhFragment.kt @@ -25,6 +25,7 @@ import androidx.preference.Preference import com.hippo.ehviewer.EhApplication import com.hippo.ehviewer.R import com.hippo.ehviewer.Settings +import com.hippo.ehviewer.client.EhCookieStore import com.hippo.ehviewer.client.EhEngine import com.hippo.ehviewer.client.EhTagDatabase import eu.kanade.tachiyomi.util.lang.launchIO @@ -33,6 +34,7 @@ class EhFragment : BasePreferenceFragment() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.eh_settings) val account = findPreference(Settings.KEY_ACCOUNT) + val imageLimits = findPreference(Settings.KEY_IMAGE_LIMITS) val theme = findPreference(Settings.KEY_THEME) val blackDarkTheme = findPreference(Settings.KEY_BLACK_DARK_THEME) val gallerySite = findPreference(Settings.KEY_GALLERY_SITE) @@ -59,6 +61,9 @@ class EhFragment : BasePreferenceFragment() { preferenceScreen.removePreference(showTagTranslations) preferenceScreen.removePreference(tagTranslationsSource!!) } + if (!EhCookieStore.hasSignedIn()) { + preferenceScreen.removePreference(imageLimits!!) + } } override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 818326e8c..affc32cc3 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -482,6 +482,11 @@ 下载压缩包需要 H@H 客户端 资金:%1$s GP,%2$d Credits 余额不足 + 图片配额 + 当前图片配额和资金 + 当前:%1$s\n重置花费:%2$s + 成功重置图片配额 + 重置 隐私 不允许屏幕抓取 启用后,将不能截取该应用的屏幕截图,同时,将不会在系统任务切换器中显示该应用的内容预览,重新加载应用以生效此更改 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2923740c3..a61812e55 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -553,6 +553,11 @@ Need H@H client for archive download Funds: %1$s GP, %2$d Credits Insufficient Funds + Image Limits + Current Image Limits and Funds + Current: %1$s\nReset Cost: %2$s + Image limit was successfully reset + Reset Privacy Prevent screenshots Prevent the content of the app from being taken screenshots of or shown in the \"Recent Apps\" list. diff --git a/app/src/main/res/xml/eh_settings.xml b/app/src/main/res/xml/eh_settings.xml index bc4bc2b79..1c8384476 100644 --- a/app/src/main/res/xml/eh_settings.xml +++ b/app/src/main/res/xml/eh_settings.xml @@ -23,14 +23,22 @@ android:title="@string/account_name" app:iconSpaceReserved="false" /> + + + app:iconSpaceReserved="false" + app:useSimpleSummaryProvider="true" /> + app:iconSpaceReserved="false" + app:useSimpleSummaryProvider="true" /> + app:iconSpaceReserved="false" + app:useSimpleSummaryProvider="true" /> + app:iconSpaceReserved="false" + app:useSimpleSummaryProvider="true" /> + app:iconSpaceReserved="false" + app:useSimpleSummaryProvider="true" />