diff --git a/app/build.gradle.kts b/app/build.gradle.kts index b18c4704b..f4e5b68b8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,4 +1,6 @@ import com.google.devtools.ksp.gradle.KspTaskJvm +import com.mikepenz.aboutlibraries.plugin.DuplicateMode.MERGE +import com.mikepenz.aboutlibraries.plugin.DuplicateRule.GROUP import org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17 import java.io.ByteArrayOutputStream import java.time.Instant @@ -191,7 +193,6 @@ dependencies { // https://developer.android.com/jetpack/androidx/releases/paging implementation("androidx.paging:paging-common-ktx:3.2.0-alpha06") implementation("androidx.paging:paging-compose:1.0.0-alpha20") - implementation("androidx.preference:preference-ktx:1.2.0") implementation("androidx.recyclerview:recyclerview:1.3.0") // https://developer.android.com/jetpack/androidx/releases/room @@ -229,8 +230,6 @@ dependencies { implementation("dev.rikka.rikkax.core:core-ktx:1.4.1") implementation("dev.rikka.rikkax.insets:insets:1.3.0") implementation("dev.rikka.rikkax.layoutinflater:layoutinflater:1.3.0") - implementation("dev.rikka.rikkax.preference:simplemenu-preference:1.0.3") - implementation("dev.rikka.rikkax.material:material-preference:2.0.0") implementation(platform("io.arrow-kt:arrow-stack:1.2.0-RC")) implementation("io.arrow-kt:arrow-fx-coroutines") @@ -245,11 +244,6 @@ dependencies { implementation("org.jsoup:jsoup:1.16.1") } -configurations.all { - exclude("dev.rikka.rikkax.appcompat", "appcompat") - exclude("dev.rikka.rikkax.material", "material") -} - ksp { arg("room.schemaLocation", "$projectDir/schemas") arg("room.generateKotlin", "true") @@ -260,6 +254,6 @@ tasks.withType().configureEach { } aboutLibraries { - duplicationMode = com.mikepenz.aboutlibraries.plugin.DuplicateMode.MERGE - duplicationRule = com.mikepenz.aboutlibraries.plugin.DuplicateRule.GROUP + duplicationMode = MERGE + duplicationRule = GROUP } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2577ac51d..34609a290 100755 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -126,10 +126,6 @@ - Unit) = a val systemDns = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) AsyncDns.toDns(AndroidAsyncDns.IPv4, AndroidAsyncDns.IPv6) else Dns.SYSTEM object EhDns : Dns { - override fun lookup(hostname: String): List = builtInHosts[hostname].takeIf { Settings.builtInHosts } ?: EhDoH.lookup(hostname) ?: systemDns.lookup(hostname) + override fun lookup(hostname: String): List = builtInHosts[hostname].takeIf { Settings.builtInHosts } ?: systemDns.lookup(hostname) } diff --git a/app/src/main/java/com/hippo/ehviewer/preference/AccountPreference.kt b/app/src/main/java/com/hippo/ehviewer/preference/AccountPreference.kt deleted file mode 100644 index 918953ca8..000000000 --- a/app/src/main/java/com/hippo/ehviewer/preference/AccountPreference.kt +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2018 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.hippo.ehviewer.preference - -import android.content.Context -import android.content.DialogInterface -import android.text.Html -import android.util.AttributeSet -import androidx.appcompat.app.AlertDialog -import com.hippo.ehviewer.R -import com.hippo.ehviewer.client.EhCookieStore -import com.hippo.ehviewer.client.EhUrl -import com.hippo.ehviewer.client.EhUtils -import com.hippo.ehviewer.ui.SettingsActivity -import com.hippo.ehviewer.ui.legacy.preference.MessagePreference -import com.hippo.ehviewer.ui.scene.BaseScene -import com.hippo.ehviewer.util.addTextToClipboard -import okhttp3.Cookie -import okhttp3.HttpUrl.Companion.toHttpUrl -import java.util.LinkedList - -class AccountPreference @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, -) : MessagePreference(context, attrs) { - private val mActivity = context as SettingsActivity - private var message: String? = null - - init { - val store = EhCookieStore - val eCookies = store.getCookies(EhUrl.HOST_E.toHttpUrl()) - val exCookies = store.getCookies(EhUrl.HOST_EX.toHttpUrl()) - val cookies: MutableList = LinkedList(eCookies) - cookies.addAll(exCookies) - var ipbMemberId: String? = null - var ipbPassHash: String? = null - var igneous: String? = null - var i = 0 - val n = cookies.size - while (i < n) { - val cookie = cookies[i] - when (cookie.name) { - EhCookieStore.KEY_IPB_MEMBER_ID -> ipbMemberId = cookie.value - EhCookieStore.KEY_IPB_PASS_HASH -> ipbPassHash = cookie.value - EhCookieStore.KEY_IGNEOUS -> igneous = cookie.value - } - i++ - } - if (ipbMemberId != null || ipbPassHash != null || igneous != null) { - message = ( - EhCookieStore.KEY_IPB_MEMBER_ID + ": " + ipbMemberId + "
" + - EhCookieStore.KEY_IPB_PASS_HASH + ": " + ipbPassHash + "
" + - EhCookieStore.KEY_IGNEOUS + ": " + igneous - ) - setDialogMessage( - Html.fromHtml( - context.getString( - R.string.settings_eh_identity_cookies_signed, - message, - ), - Html.FROM_HTML_MODE_LEGACY, - ), - ) - message = message!!.replace("
", "\n") - } else { - setDialogMessage(context.getString(R.string.settings_eh_identity_cookies_tourist)) - } - } - - override fun onPrepareDialogBuilder(builder: AlertDialog.Builder) { - super.onPrepareDialogBuilder(builder) - if (message != null) { - builder.setNeutralButton(R.string.settings_eh_identity_cookies_copy) { dialog: DialogInterface?, which: Int -> - mActivity.addTextToClipboard(message, true) - this@AccountPreference.onClick(dialog, which) - } - } - builder.setPositiveButton(R.string.settings_eh_sign_out) { _: DialogInterface?, _: Int -> - EhUtils.signOut() - mActivity.showTip(R.string.settings_eh_sign_out_tip, BaseScene.LENGTH_SHORT) - } - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/preference/CleanRedundancyPreference.kt b/app/src/main/java/com/hippo/ehviewer/preference/CleanRedundancyPreference.kt deleted file mode 100644 index 1e0ee6c18..000000000 --- a/app/src/main/java/com/hippo/ehviewer/preference/CleanRedundancyPreference.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.hippo.ehviewer.preference - -import android.content.Context -import android.util.AttributeSet -import com.hippo.ehviewer.R -import com.hippo.ehviewer.download.downloadLocation -import com.hippo.unifile.UniFile -import eu.kanade.tachiyomi.util.lang.launchUI -import eu.kanade.tachiyomi.util.lang.withUIContext -import kotlinx.coroutines.Job -import kotlinx.coroutines.launch -import splitties.init.appCtx -import com.hippo.ehviewer.download.DownloadManager as downloadManager - -private val NO_REDUNDANCY = appCtx.getString(R.string.settings_download_clean_redundancy_no_redundancy) -private val CLEAR_REDUNDANCY_DONE = { cnt: Int -> appCtx.getString(R.string.settings_download_clean_redundancy_done, cnt) } -private val FINAL_CLEAR_REDUNDANCY_MSG = { cnt: Int -> if (cnt == 0) NO_REDUNDANCY else CLEAR_REDUNDANCY_DONE(cnt) } - -class CleanRedundancyPreference @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, -) : TaskPreference(context, attrs) { - private fun clearFile(file: UniFile): Boolean { - var name = file.name ?: return false - val index = name.indexOf('-') - if (index >= 0) { - name = name.substring(0, index) - } - val gid = name.toLongOrNull() ?: return false - if (downloadManager.containDownloadInfo(gid)) { - return false - } - file.delete() - return true - } - - private fun doRealWork(): Int { - return downloadLocation.listFiles()?.sumOf { clearFile(it).compareTo(false) } ?: 0 - } - - override fun launchJob() { - if (singletonJob?.isActive == true) { - singletonJob?.invokeOnCompletion { - launchUI { - dialog.dismiss() - } - } - } else { - singletonJob = launch { - val cnt = doRealWork() - withUIContext { - showTip(FINAL_CLEAR_REDUNDANCY_MSG(cnt)) - dialog.dismiss() - } - } - } - } -} - -private var singletonJob: Job? = null diff --git a/app/src/main/java/com/hippo/ehviewer/preference/DohPreference.kt b/app/src/main/java/com/hippo/ehviewer/preference/DohPreference.kt deleted file mode 100644 index 4644f1ee8..000000000 --- a/app/src/main/java/com/hippo/ehviewer/preference/DohPreference.kt +++ /dev/null @@ -1,56 +0,0 @@ -package com.hippo.ehviewer.preference - -import android.content.Context -import android.content.DialogInterface -import android.util.AttributeSet -import androidx.preference.Preference -import com.hippo.ehviewer.EhApplication -import com.hippo.ehviewer.R -import com.hippo.ehviewer.Settings -import com.hippo.ehviewer.client.systemDns -import com.hippo.ehviewer.ui.legacy.EditTextDialogBuilder -import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.dnsoverhttps.DnsOverHttps -import java.net.InetAddress - -class DohPreference @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, -) : Preference(context, attrs) { - override fun onClick() { - val builder = EditTextDialogBuilder(context, Settings.dohUrl, context.getString(R.string.settings_advanced_dns_over_http_hint)) - builder.setTitle(R.string.settings_advanced_dns_over_http_title) - builder.setPositiveButton(android.R.string.ok, null) - val dialog = builder.create() - dialog.show() - dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener { - val text = builder.text.trim() - runCatching { - doh = if (text.isNotBlank()) buildDoHDNS(text) else null - }.onFailure { - builder.setError("Invalid URL!") - }.onSuccess { - Settings.dohUrl = text - dialog.dismiss() - } - } - } -} - -private fun buildDoHDNS(url: String): DnsOverHttps { - return DnsOverHttps.Builder().apply { - client(EhApplication.okHttpClient) - url(url.toHttpUrl()) - post(true) - systemDns(systemDns) - }.build() -} - -private var doh: DnsOverHttps? = Settings.dohUrl.runCatching { buildDoHDNS(this) }.getOrNull() - -object EhDoH { - fun lookup(hostname: String): List? = doh - ?.runCatching { lookup(hostname).takeIf { it.isNotEmpty() } } - ?.onFailure { it.printStackTrace() } - ?.getOrNull() -} diff --git a/app/src/main/java/com/hippo/ehviewer/preference/ImageLimitsPreference.kt b/app/src/main/java/com/hippo/ehviewer/preference/ImageLimitsPreference.kt deleted file mode 100644 index b864996fe..000000000 --- a/app/src/main/java/com/hippo/ehviewer/preference/ImageLimitsPreference.kt +++ /dev/null @@ -1,86 +0,0 @@ -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.lifecycleScope -import com.hippo.ehviewer.R -import com.hippo.ehviewer.ui.SettingsActivity -import com.hippo.ehviewer.ui.legacy.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 resetButton: Button - private lateinit var mDialog: AlertDialog - - init { - updateSummary() - } - - override fun onPrepareDialogBuilder(builder: AlertDialog.Builder) { - super.onPrepareDialogBuilder(builder) - builder.setMessage(placeholder) - } - - override fun onDialogCreated(dialog: AlertDialog) { - super.onDialogCreated(dialog) - mDialog = dialog - resetButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE) - resetButton.setOnClickListener(this) - resetButton.isEnabled = false - launchIOCatching { - mActivity.getImageLimits() - } - } - - override fun onDialogClosed(positiveResult: Boolean) { - super.onDialogClosed(positiveResult) - updateSummary() - } - - private fun updateSummary() { - summary = mActivity.mLimits?.run { - mActivity.getString(R.string.image_limits_summary, current, maximum) - } ?: mActivity.getString(R.string.image_limits_summary, 0, 0) - } - - private fun launchIOCatching(block: suspend () -> Unit) = mActivity.lifecycleScope.launchIO { - runCatching { - block() - }.onFailure { - it.printStackTrace() - withUIContext { - mDialog.setMessage(it.message) - } - }.onSuccess { - withUIContext { - bind() - } - } - } - - private fun bind() { - val (current, maximum, resetCost) = mActivity.mLimits!! - val (fundsGP, fundsC) = mActivity.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) - launchIOCatching { - mActivity.resetImageLimits() - } - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/preference/ProxyPreference.kt b/app/src/main/java/com/hippo/ehviewer/preference/ProxyPreference.kt deleted file mode 100644 index aa0055159..000000000 --- a/app/src/main/java/com/hippo/ehviewer/preference/ProxyPreference.kt +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.hippo.ehviewer.preference - -import android.annotation.SuppressLint -import android.content.Context -import android.content.DialogInterface -import android.text.TextUtils -import android.util.AttributeSet -import android.view.View -import android.widget.AutoCompleteTextView -import android.widget.EditText -import androidx.appcompat.app.AlertDialog -import com.google.android.material.textfield.TextInputLayout -import com.hippo.ehviewer.EhProxySelector -import com.hippo.ehviewer.R -import com.hippo.ehviewer.Settings -import com.hippo.ehviewer.network.InetValidator -import com.hippo.ehviewer.ui.legacy.preference.DialogPreference -import com.hippo.ehviewer.yorozuya.MathUtils -import com.hippo.ehviewer.yorozuya.ViewUtils - -class ProxyPreference @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, -) : DialogPreference(context, attrs), View.OnClickListener { - private var mType: TextInputLayout? = null - private var mIpInputLayout: TextInputLayout? = null - private var mIp: EditText? = null - private var mPortInputLayout: TextInputLayout? = null - private var mPort: EditText? = null - private val mArray: Array - - init { - mArray = context.resources.getStringArray(R.array.proxy_types) - dialogLayoutResource = R.layout.preference_dialog_proxy - updateSummary(Settings.proxyType, Settings.proxyIp, Settings.proxyPort) - } - - private fun getProxyTypeText(type: Int): String { - return mArray[MathUtils.clamp(type, 0, mArray.size - 1)] - } - - private fun updateSummary(type: Int, ip: String?, port: Int) { - var type1 = type - if ((type1 == EhProxySelector.TYPE_HTTP || type1 == EhProxySelector.TYPE_SOCKS) && - (TextUtils.isEmpty(ip) || !InetValidator.isValidInetPort(port)) - ) { - type1 = EhProxySelector.TYPE_SYSTEM - } - summary = if (type1 == EhProxySelector.TYPE_HTTP || type1 == EhProxySelector.TYPE_SOCKS) { - val context = context - context.getString( - R.string.settings_advanced_proxy_summary_1, - getProxyTypeText(type1), - ip, - port, - ) - } else { - val context = context - context.getString( - R.string.settings_advanced_proxy_summary_2, - getProxyTypeText(type1), - ) - } - } - - override fun onPrepareDialogBuilder(builder: AlertDialog.Builder) { - super.onPrepareDialogBuilder(builder) - builder.setPositiveButton(android.R.string.ok, null) - } - - @SuppressLint("SetTextI18n") - override fun onDialogCreated(dialog: AlertDialog) { - super.onDialogCreated(dialog) - dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(this) - mType = ViewUtils.`$$`(dialog, R.id.type) as TextInputLayout - val array = context.resources.getStringArray(R.array.proxy_types) - mIpInputLayout = ViewUtils.`$$`(dialog, R.id.ip_input_layout) as TextInputLayout - mIp = ViewUtils.`$$`(dialog, R.id.ip) as EditText - mPortInputLayout = ViewUtils.`$$`(dialog, R.id.port_input_layout) as TextInputLayout - mPort = ViewUtils.`$$`(dialog, R.id.port) as EditText - val type = Settings.proxyType - (mType!!.editText as AutoCompleteTextView).setText( - array[ - MathUtils.clamp( - type, - 0, - array.size, - ), - ], - false, - ) - mIp!!.setText(Settings.proxyIp) - val portString: String? - val port = Settings.proxyPort - portString = if (!InetValidator.isValidInetPort(port)) { - null - } else { - port.toString() - } - mPort!!.setText(portString) - } - - override fun onDialogClosed(positiveResult: Boolean) { - super.onDialogClosed(positiveResult) - mType = null - mIpInputLayout = null - mIp = null - mPortInputLayout = null - mPort = null - } - - override fun onClick(v: View) { - val dialog = dialog - val context: Context = context - if (null == dialog || null == mType || null == mIpInputLayout || null == mIp || null == mPortInputLayout || null == mPort) { - return - } - val type = mArray.indexOf(mType!!.editText!!.text.toString()) - val ip = mIp!!.text.toString().trim { it <= ' ' } - if (ip.isEmpty()) { - if (type == EhProxySelector.TYPE_HTTP || type == EhProxySelector.TYPE_SOCKS) { - mIpInputLayout!!.error = context.getString(R.string.text_is_empty) - return - } - } - mIpInputLayout!!.error = null - val port: Int - val portString = mPort!!.text.toString().trim { it <= ' ' } - if (portString.isEmpty()) { - if (type == EhProxySelector.TYPE_HTTP || type == EhProxySelector.TYPE_SOCKS) { - mPortInputLayout!!.error = context.getString(R.string.text_is_empty) - return - } else { - port = -1 - } - } else { - port = try { - portString.toInt() - } catch (e: NumberFormatException) { - -1 - } - if (!InetValidator.isValidInetPort(port)) { - mPortInputLayout!!.error = context.getString(R.string.proxy_invalid_port) - return - } - } - mPortInputLayout!!.error = null - Settings.proxyType = type - Settings.proxyIp = ip - Settings.proxyPort = port - updateSummary(type, ip, port) - EhProxySelector.updateProxy() - dialog.dismiss() - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/preference/RestoreDownloadPreference.kt b/app/src/main/java/com/hippo/ehviewer/preference/RestoreDownloadPreference.kt deleted file mode 100644 index b7b901b0d..000000000 --- a/app/src/main/java/com/hippo/ehviewer/preference/RestoreDownloadPreference.kt +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.hippo.ehviewer.preference - -import android.content.Context -import android.util.AttributeSet -import com.hippo.ehviewer.EhDB -import com.hippo.ehviewer.R -import com.hippo.ehviewer.client.EhEngine.fillGalleryListByApi -import com.hippo.ehviewer.client.EhUrl -import com.hippo.ehviewer.client.data.BaseGalleryInfo -import com.hippo.ehviewer.client.data.GalleryInfo -import com.hippo.ehviewer.download.DownloadManager -import com.hippo.ehviewer.download.downloadLocation -import com.hippo.ehviewer.spider.SpiderQueen -import com.hippo.ehviewer.spider.readCompatFromUniFile -import com.hippo.unifile.UniFile -import eu.kanade.tachiyomi.util.lang.launchUI -import eu.kanade.tachiyomi.util.lang.withUIContext -import kotlinx.coroutines.Job -import kotlinx.coroutines.launch -import moe.tarsin.coroutines.runSuspendCatching -import splitties.init.appCtx -import com.hippo.ehviewer.download.DownloadManager as downloadManager - -private val RESTORE_NOT_FOUND = appCtx.getString(R.string.settings_download_restore_not_found) -private val RESTORE_FAILED = appCtx.getString(R.string.settings_download_restore_failed) -private val RESTORE_COUNT_MSG = { cnt: Int -> if (cnt == 0) RESTORE_NOT_FOUND else appCtx.getString(R.string.settings_download_restore_successfully, cnt) } - -class RestoreDownloadPreference @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, -) : TaskPreference(context, attrs) { - private val mManager: DownloadManager = downloadManager - private var restoreDirCount = 0 - private fun getRestoreItem(file: UniFile?): RestoreItem? { - if (null == file || !file.isDirectory) return null - val siFile = file.findFile(SpiderQueen.SPIDER_INFO_FILENAME) ?: return null - return runCatching { - val spiderInfo = readCompatFromUniFile(siFile) ?: return null - val gid = spiderInfo.gid - val dirname = file.name ?: return null - if (mManager.containDownloadInfo(gid)) { - // Restore download dir to avoid redownload - val dbdirname = EhDB.getDownloadDirname(gid) - if (null == dbdirname || dirname != dbdirname) { - EhDB.putDownloadDirname(gid, dirname) - restoreDirCount++ - } - return null - } - RestoreItem(dirname).also { - it.gid = spiderInfo.gid - it.token = spiderInfo.token - } - }.onFailure { - it.printStackTrace() - }.getOrNull() - } - - private suspend fun doRealWork(): List? { - val files = downloadLocation.listFiles() ?: return null - return files.mapNotNull { getRestoreItem(it) }.apply { - runSuspendCatching { - fillGalleryListByApi(this, EhUrl.referer) - }.onFailure { - it.printStackTrace() - } - } - } - - private class RestoreItem( - val dirname: String, - ) : BaseGalleryInfo() - - override fun launchJob() { - if (singletonJob?.isActive == true) { - singletonJob?.invokeOnCompletion { - launchUI { - dialog.dismiss() - } - } - } else { - singletonJob = launch { - val result = doRealWork() - withUIContext { - if (result == null) { - showTip(RESTORE_FAILED) - } else { - if (result.isEmpty()) { - showTip(RESTORE_COUNT_MSG(restoreDirCount)) - } else { - var count = 0 - var i = 0 - val n = result.size - while (i < n) { - val item = result[i] - // Avoid failed gallery info - if (null != item.title) { - // Put to download - mManager.addDownload(item, null) - // Put download dir to DB - EhDB.putDownloadDirname(item.gid, (item as RestoreItem).dirname) - count++ - } - i++ - } - showTip(RESTORE_COUNT_MSG(count + restoreDirCount)) - } - } - dialog.dismiss() - } - } - } - } -} - -private var singletonJob: Job? = null diff --git a/app/src/main/java/com/hippo/ehviewer/preference/TaskPreference.kt b/app/src/main/java/com/hippo/ehviewer/preference/TaskPreference.kt deleted file mode 100644 index 527cf94be..000000000 --- a/app/src/main/java/com/hippo/ehviewer/preference/TaskPreference.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.hippo.ehviewer.preference - -import android.content.Context -import android.util.AttributeSet -import androidx.appcompat.app.AlertDialog -import com.google.android.material.snackbar.Snackbar -import com.hippo.ehviewer.R -import com.hippo.ehviewer.ui.SettingsActivity -import com.hippo.ehviewer.ui.legacy.preference.DialogPreference -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job - -abstract class TaskPreference @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, -) : DialogPreference(context, attrs), CoroutineScope { - override val coroutineContext = Dispatchers.IO + Job() - protected lateinit var dialog: AlertDialog - override fun onPrepareDialogBuilder(builder: AlertDialog.Builder) { - builder.setTitle(null) - builder.setView(R.layout.preference_dialog_task) - builder.setCancelable(false) - } - - abstract fun launchJob() - - override fun onDialogCreated(dialog: AlertDialog) { - this.dialog = dialog - launchJob() - } - - protected fun showTip(msg: String) { - (context as SettingsActivity).showTip( - msg, - Snackbar.LENGTH_SHORT, - ) - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/preference/VersionPreference.kt b/app/src/main/java/com/hippo/ehviewer/preference/VersionPreference.kt deleted file mode 100644 index b3f4d228c..000000000 --- a/app/src/main/java/com/hippo/ehviewer/preference/VersionPreference.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.hippo.ehviewer.preference - -import android.content.Context -import android.util.AttributeSet -import androidx.preference.Preference -import com.hippo.ehviewer.BuildConfig -import com.hippo.ehviewer.R - -class VersionPreference @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null, -) : Preference(context, attrs) { - init { - setTitle(R.string.settings_about_version) - summary = "${BuildConfig.VERSION_NAME} (${BuildConfig.COMMIT_SHA})\n" + - context.getString(R.string.settings_about_build_time, BuildConfig.BUILD_TIME) - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/SettingsActivity.kt b/app/src/main/java/com/hippo/ehviewer/ui/SettingsActivity.kt deleted file mode 100644 index 4904dfd90..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/SettingsActivity.kt +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.hippo.ehviewer.ui - -import android.os.Bundle -import android.view.MenuItem -import android.widget.TextView -import androidx.annotation.StringRes -import androidx.fragment.app.FragmentTransaction -import androidx.lifecycle.lifecycleScope -import com.google.android.material.appbar.AppBarLayout -import com.google.android.material.floatingactionbutton.FloatingActionButton -import com.google.android.material.snackbar.Snackbar -import com.hippo.ehviewer.R -import com.hippo.ehviewer.client.EhCookieStore -import com.hippo.ehviewer.client.EhEngine -import com.hippo.ehviewer.client.parser.HomeParser -import com.hippo.ehviewer.ui.fragment.SettingsFragment -import com.hippo.ehviewer.ui.scene.BaseScene -import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.withUIContext - -class SettingsActivity : EhActivity() { - private var mFab: FloatingActionButton? = null - private var mContentText: TextView? = null - private var mAppbarLayout: AppBarLayout? = null - var mLimits: HomeParser.Limits? = null - private set - var mFunds: HomeParser.Funds? = null - private set - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - lifecycleScope.launchIO { - if (EhCookieStore.hasSignedIn()) { - runCatching { - getImageLimits() - }.exceptionOrNull()?.printStackTrace() - } - } - setContentView(R.layout.activity_preference) - setSupportActionBar(findViewById(R.id.toolbar)) - mContentText = findViewById(R.id.tip) - mFab = findViewById(R.id.fab) - mAppbarLayout = findViewById(R.id.appbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) - if (savedInstanceState == null) { - supportFragmentManager - .beginTransaction() - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_MATCH_ACTIVITY_OPEN) - .replace(R.id.fragment, SettingsFragment()) - .commitAllowingStateLoss() - } - } - - suspend fun getImageLimits() = EhEngine.getImageLimits().run { - mLimits = limits - mFunds = funds - } - - suspend fun resetImageLimits() { - mLimits = - EhEngine.resetImageLimits() ?: HomeParser.Limits(maximum = mLimits!!.maximum).also { - withUIContext { - showTip(R.string.reset_limits_succeed, BaseScene.LENGTH_SHORT) - } - } - } - - fun showTip(@StringRes id: Int, length: Int) { - showTip(getString(id), length) - } - - fun showTip(message: CharSequence?, length: Int) { - Snackbar.make( - findViewById(R.id.snackbar), - message!!, - if (length == BaseScene.LENGTH_LONG) Snackbar.LENGTH_LONG else Snackbar.LENGTH_SHORT, - ).show() - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == android.R.id.home) { - onBackPressedDispatcher.onBackPressed() - return true - } - return super.onOptionsItemSelected(item) - } - - fun getMFab(): FloatingActionButton { - return mFab!! - } - - fun getMContentText(): TextView { - return mContentText!! - } - - fun resetAppbarLiftStatus() { - mAppbarLayout?.setExpanded(true) - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/AboutFragment.kt b/app/src/main/java/com/hippo/ehviewer/ui/fragment/AboutFragment.kt deleted file mode 100644 index 37801ce29..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/AboutFragment.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.hippo.ehviewer.ui.fragment - -import android.os.Bundle -import android.text.Html -import androidx.preference.Preference -import com.hippo.ehviewer.R - -class AboutFragment : BasePreferenceFragment() { - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.about_settings) - val author = findPreference(KEY_AUTHOR) - author!!.summary = Html.fromHtml( - getString(R.string.settings_about_author_summary).replace('$', '@'), - Html.FROM_HTML_MODE_LEGACY, - ) - } - - override val fragmentTitle: Int - get() = R.string.settings_about - - companion object { - private const val KEY_AUTHOR = "author" - private const val KEY_CHECK_FOR_UPDATES = "check_for_updates" - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/AdvancedFragment.kt b/app/src/main/java/com/hippo/ehviewer/ui/fragment/AdvancedFragment.kt deleted file mode 100644 index 416eff80e..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/AdvancedFragment.kt +++ /dev/null @@ -1,369 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.hippo.ehviewer.ui.fragment - -import android.annotation.SuppressLint -import android.content.Intent -import android.net.Uri -import android.os.Build -import android.os.Bundle -import android.provider.Settings -import android.util.Log -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AppCompatDelegate -import androidx.core.os.LocaleListCompat -import androidx.lifecycle.lifecycleScope -import androidx.preference.Preference -import com.hippo.ehviewer.AppConfig -import com.hippo.ehviewer.BuildConfig -import com.hippo.ehviewer.EhDB -import com.hippo.ehviewer.R -import com.hippo.ehviewer.client.EhEngine -import com.hippo.ehviewer.client.data.FavListUrlBuilder -import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder -import com.hippo.ehviewer.ui.scene.BaseScene -import com.hippo.ehviewer.util.ExceptionUtils -import com.hippo.ehviewer.util.LogCat -import com.hippo.ehviewer.util.ReadableTime -import com.hippo.ehviewer.yorozuya.IOUtils -import eu.kanade.tachiyomi.util.lang.launchIO -import eu.kanade.tachiyomi.util.lang.withUIContext -import kotlinx.coroutines.delay -import moe.tarsin.coroutines.runSuspendCatching -import java.io.BufferedInputStream -import java.io.BufferedOutputStream -import java.io.File -import java.io.FileInputStream -import java.io.FileOutputStream -import java.util.zip.ZipEntry -import java.util.zip.ZipOutputStream -import com.hippo.ehviewer.Settings as AppSettings - -class AdvancedFragment : BasePreferenceFragment() { - private var exportLauncher = registerForActivityResult( - ActivityResultContracts.CreateDocument("application/vnd.sqlite3"), - ) { uri: Uri? -> - if (uri != null) { - try { - // grantUriPermission might throw RemoteException on MIUI - requireActivity().grantUriPermission( - BuildConfig.APPLICATION_ID, - uri, - Intent.FLAG_GRANT_WRITE_URI_PERMISSION, - ) - } catch (e: Exception) { - ExceptionUtils.throwIfFatal(e) - e.printStackTrace() - } - try { - val alertDialog = BaseDialogBuilder(requireActivity()) - .setCancelable(false) - .setView(R.layout.preference_dialog_task) - .show() - lifecycleScope.launchIO { - val e = runSuspendCatching { - EhDB.exportDB(requireActivity(), uri) - }.exceptionOrNull()?.run { - printStackTrace() - getString(R.string.settings_advanced_export_data_failed) - } - withUIContext { - if (alertDialog.isShowing) { - alertDialog.dismiss() - } - showTip( - e ?: getString(R.string.settings_advanced_export_data_to, uri.toString()), - BaseScene.LENGTH_SHORT, - ) - } - } - } catch (e: Exception) { - showTip(R.string.settings_advanced_export_data_failed, BaseScene.LENGTH_SHORT) - } - } - } - private var dumpLogcatLauncher = registerForActivityResult( - ActivityResultContracts.CreateDocument("application/zip"), - ) { uri: Uri? -> - if (uri != null) { - try { - // grantUriPermission might throw RemoteException on MIUI - requireActivity().grantUriPermission( - BuildConfig.APPLICATION_ID, - uri, - Intent.FLAG_GRANT_WRITE_URI_PERMISSION, - ) - } catch (e: Exception) { - ExceptionUtils.throwIfFatal(e) - e.printStackTrace() - } - try { - val zipFile = File(AppConfig.externalTempDir, "logs.zip") - if (zipFile.exists()) { - zipFile.delete() - } - val files = ArrayList() - AppConfig.externalParseErrorDir?.listFiles()?.let { files.addAll(it) } - AppConfig.externalCrashDir?.listFiles()?.let { files.addAll(it) } - var finished = false - var origin: BufferedInputStream? = null - var out: ZipOutputStream? = null - try { - val dest = FileOutputStream(zipFile) - out = ZipOutputStream(BufferedOutputStream(dest)) - val bytes = ByteArray(1024 * 64) - for (file in files) { - if (!file.isFile) { - continue - } - try { - val fi = FileInputStream(file) - origin = BufferedInputStream(fi, bytes.size) - val entry = ZipEntry(file.name) - out.putNextEntry(entry) - var count: Int - while (origin.read(bytes, 0, bytes.size).also { count = it } != -1) { - out.write(bytes, 0, count) - } - origin.close() - origin = null - } catch (e: Exception) { - e.printStackTrace() - } - } - val entry = - ZipEntry("logcat-" + ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".txt") - out.putNextEntry(entry) - LogCat.save(out) - out.closeEntry() - out.close() - IOUtils.copy( - FileInputStream(zipFile), - requireActivity().contentResolver.openOutputStream(uri), - ) - finished = true - } catch (e: Exception) { - e.printStackTrace() - } finally { - origin?.close() - out?.close() - } - if (!finished) { - finished = LogCat.save(requireActivity().contentResolver.openOutputStream(uri)) - } - showTip( - if (finished) { - getString( - R.string.settings_advanced_dump_logcat_to, - uri.toString(), - ) - } else { - getString(R.string.settings_advanced_dump_logcat_failed) - }, - BaseScene.LENGTH_SHORT, - ) - } catch (e: Exception) { - showTip( - getString(R.string.settings_advanced_dump_logcat_failed), - BaseScene.LENGTH_SHORT, - ) - } - } - } - private var importDataLauncher = registerForActivityResult, Uri>( - ActivityResultContracts.OpenDocument(), - ) { uri: Uri? -> - if (uri != null) { - try { - // grantUriPermission might throw RemoteException on MIUI - requireActivity().grantUriPermission( - BuildConfig.APPLICATION_ID, - uri, - Intent.FLAG_GRANT_READ_URI_PERMISSION, - ) - } catch (e: Exception) { - ExceptionUtils.throwIfFatal(e) - e.printStackTrace() - } - try { - val alertDialog = BaseDialogBuilder(requireActivity()) - .setCancelable(false) - .setView(R.layout.preference_dialog_task) - .show() - lifecycleScope.launchIO { - val error = runSuspendCatching { - EhDB.importDB(requireActivity(), uri) - }.exceptionOrNull()?.run { - printStackTrace() - getString(R.string.cant_read_the_file) - } - withUIContext { - if (alertDialog.isShowing) { - alertDialog.dismiss() - } - if (null == error) { - showTip(getString(R.string.settings_advanced_import_data_successfully), BaseScene.LENGTH_SHORT) - } else { - showTip(error, BaseScene.LENGTH_SHORT) - } - } - } - } catch (e: Exception) { - showTip(e.localizedMessage, BaseScene.LENGTH_SHORT) - } - } - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.advanced_settings) - val dumpLogcat = findPreference(KEY_DUMP_LOGCAT) - val appLanguage = findPreference(KEY_APP_LANGUAGE) - val importData = findPreference(KEY_IMPORT_DATA) - val exportData = findPreference(KEY_EXPORT_DATA) - val backupFavorite = findPreference(KEY_BACKUP_FAVORITE) - val openByDefault = findPreference(KEY_OPEN_BY_DEFAULT) - val domainFronting = findPreference(AppSettings.KEY_DOMAIN_FRONTING) - val bypassVpn = findPreference(AppSettings.KEY_BYPASS_VPN) - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { - openByDefault!!.isVisible = false - } else { - openByDefault!!.onPreferenceClickListener = this - } - dumpLogcat!!.onPreferenceClickListener = this - importData!!.onPreferenceClickListener = this - exportData!!.onPreferenceClickListener = this - backupFavorite!!.onPreferenceClickListener = this - appLanguage!!.onPreferenceChangeListener = this - bypassVpn!!.isVisible = AppSettings.dF - domainFronting!!.setOnPreferenceChangeListener { _, newValue -> - bypassVpn.isVisible = newValue as Boolean - true - } - } - - override fun onPreferenceClick(preference: Preference): Boolean { - val key = preference.key - if (KEY_DUMP_LOGCAT == key) { - try { - dumpLogcatLauncher.launch("log-" + ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".zip") - } catch (e: Throwable) { - ExceptionUtils.throwIfFatal(e) - showTip(R.string.error_cant_find_activity, BaseScene.LENGTH_SHORT) - } - return true - } else if (KEY_IMPORT_DATA == key) { - try { - importDataLauncher.launch(arrayOf("*/*")) - } catch (e: Throwable) { - ExceptionUtils.throwIfFatal(e) - showTip(R.string.error_cant_find_activity, BaseScene.LENGTH_SHORT) - } - return true - } else if (KEY_EXPORT_DATA == key) { - try { - exportLauncher.launch(ReadableTime.getFilenamableTime(System.currentTimeMillis()) + ".db") - } catch (e: Throwable) { - ExceptionUtils.throwIfFatal(e) - showTip(R.string.error_cant_find_activity, BaseScene.LENGTH_SHORT) - } - return true - } else if (KEY_BACKUP_FAVORITE == key) { - try { - backupFavorite() - } catch (e: Exception) { - ExceptionUtils.throwIfFatal(e) - showTip(R.string.settings_advanced_backup_favorite_failed, BaseScene.LENGTH_SHORT) - } - return true - } else if (KEY_OPEN_BY_DEFAULT == key) { - try { - @SuppressLint("InlinedApi") - val intent = Intent( - Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, - Uri.parse("package:" + requireContext().packageName), - ) - startActivity(intent) - } catch (t: Throwable) { - val intent = Intent( - Settings.ACTION_APPLICATION_DETAILS_SETTINGS, - Uri.parse("package:" + requireContext().packageName), - ) - startActivity(intent) - } - return true - } - return false - } - - private fun backupFavorite() { - val favListUrlBuilder = FavListUrlBuilder() - var favTotal = 0 - var favIndex = 0 - tailrec suspend fun doBackup() { - val result = EhEngine.getFavorites(favListUrlBuilder.build()) - if (result.galleryInfoList.isEmpty()) { - showTip(R.string.settings_advanced_backup_favorite_nothing, BaseScene.LENGTH_SHORT) - } else { - if (favTotal == 0) favTotal = result.countArray.sum() - favIndex += result.galleryInfoList.size - val status = "($favIndex/$favTotal)" - Log.d("LocalFavorites", "now backup page $status") - EhDB.putLocalFavorites(result.galleryInfoList) - showTip(getString(R.string.settings_advanced_backup_favorite_start, status), BaseScene.LENGTH_SHORT) - if (result.next != null) { - delay(AppSettings.downloadDelay.toLong()) - favListUrlBuilder.setIndex(result.next, true) - doBackup() - } - } - } - viewLifecycleOwner.lifecycleScope.launchIO { - runSuspendCatching { - doBackup() - }.onSuccess { - showTip(R.string.settings_advanced_backup_favorite_success, BaseScene.LENGTH_SHORT) - }.onFailure { - showTip(R.string.settings_advanced_backup_favorite_failed, BaseScene.LENGTH_SHORT) - } - } - } - - override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { - val key = preference.key - if (KEY_APP_LANGUAGE == key) { - if ("system" == newValue) { - AppCompatDelegate.setApplicationLocales(LocaleListCompat.getEmptyLocaleList()) - } else { - AppCompatDelegate.setApplicationLocales(LocaleListCompat.forLanguageTags(newValue as String)) - } - requireActivity().recreate() - return true - } - return false - } - - override val fragmentTitle: Int - get() = R.string.settings_advanced - - companion object { - private const val KEY_DUMP_LOGCAT = "dump_logcat" - private const val KEY_APP_LANGUAGE = "app_language" - private const val KEY_IMPORT_DATA = "import_data" - private const val KEY_EXPORT_DATA = "export_data" - private const val KEY_OPEN_BY_DEFAULT = "open_by_default" - private const val KEY_BACKUP_FAVORITE = "backup_favorite" - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/BaseFragment.kt b/app/src/main/java/com/hippo/ehviewer/ui/fragment/BaseFragment.kt deleted file mode 100644 index 3b0cc7c2c..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/BaseFragment.kt +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2022 Tarsin Norbin - * - * This file is part of EhViewer - * - * EhViewer is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * EhViewer is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with EhViewer. - * If not, see . - */ -package com.hippo.ehviewer.ui.fragment - -import android.view.View -import android.widget.TextView -import androidx.annotation.StringRes -import androidx.fragment.app.Fragment -import com.google.android.material.floatingactionbutton.FloatingActionButton -import com.hippo.ehviewer.ui.SettingsActivity - -abstract class BaseFragment : Fragment() { - override fun onStart() { - super.onStart() - setTitle(getFragmentTitle()) - (requireActivity() as SettingsActivity).resetAppbarLiftStatus() - } - - override fun onDestroyView() { - hideFabAndClearTip() - super.onDestroyView() - } - - abstract fun getFragmentTitle(): Int - - private fun setTitle(@StringRes string: Int) { - requireActivity().setTitle(string) - } - - fun showTip(@StringRes id: Int, length: Int) { - (requireActivity() as SettingsActivity).showTip(getString(id), length) - } - - fun showTip(message: CharSequence?, length: Int) { - (requireActivity() as SettingsActivity).showTip(message, length) - } - - fun getTipView(@StringRes res: Int? = null): TextView { - return (requireActivity() as SettingsActivity).getMContentText().apply { - visibility = View.VISIBLE - res?.let { text = getString(it) } - } - } - - fun getFabViewAndShow(): FloatingActionButton { - return (requireActivity() as SettingsActivity).getMFab().apply { visibility = View.VISIBLE } - } - - private fun hideFabAndClearTip() { - getFabViewAndShow().apply { - visibility = View.GONE - setOnClickListener(null) - } - getTipView().apply { - visibility = View.GONE - } - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/BasePreferenceFragment.kt b/app/src/main/java/com/hippo/ehviewer/ui/fragment/BasePreferenceFragment.kt deleted file mode 100644 index 2d74d2460..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/BasePreferenceFragment.kt +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2022 Tarsin Norbin - * - * This file is part of EhViewer - * - * EhViewer is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * EhViewer is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with EhViewer. - * If not, see . - */ -package com.hippo.ehviewer.ui.fragment - -import android.os.Bundle -import androidx.annotation.StringRes -import androidx.fragment.app.FragmentTransaction -import androidx.preference.Preference -import androidx.preference.PreferenceFragmentCompat -import com.hippo.ehviewer.R -import com.hippo.ehviewer.ui.SettingsActivity - -open class BasePreferenceFragment : - PreferenceFragmentCompat(), - Preference.OnPreferenceClickListener, - Preference.OnPreferenceChangeListener { - override fun onStart() { - super.onStart() - setTitle(fragmentTitle) - } - - @get:StringRes - open val fragmentTitle: Int - get() = -1 - - override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { - return false - } - - override fun onPreferenceClick(preference: Preference): Boolean { - return false - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {} - - override fun onPreferenceTreeClick(preference: Preference): Boolean { - val fragment = when (preference.key) { - "eh" -> EhFragment() - "download" -> DownloadFragment() - "privacy" -> PrivacyFragment() - "advance" -> AdvancedFragment() - "about" -> AboutFragment() - "filter" -> FilterFragment() - "mytags" -> MyTagsFragment() - "uconfig" -> UConfigFragment() - "license" -> LicenseFragment() - else -> null - } - fragment?.let { - requireActivity().supportFragmentManager - .beginTransaction() - .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE) - .replace(R.id.fragment, it) - .addToBackStack(null) - .commitAllowingStateLoss() - } - return true - } - - private fun setTitle(@StringRes string: Int) { - requireActivity().setTitle(string) - } - - fun showTip(@StringRes id: Int, length: Int) { - (requireActivity() as SettingsActivity).showTip(getString(id), length) - } - - fun showTip(message: CharSequence?, length: Int) { - (requireActivity() as SettingsActivity).showTip(message, length) - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/DownloadFragment.kt b/app/src/main/java/com/hippo/ehviewer/ui/fragment/DownloadFragment.kt deleted file mode 100644 index 25cd6cc76..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/DownloadFragment.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.hippo.ehviewer.ui.fragment - -import android.content.Intent -import android.net.Uri -import android.os.Bundle -import androidx.activity.result.contract.ActivityResultContracts -import androidx.lifecycle.lifecycleScope -import androidx.preference.Preference -import com.hippo.ehviewer.AppConfig -import com.hippo.ehviewer.R -import com.hippo.ehviewer.Settings -import com.hippo.ehviewer.download.downloadLocation -import com.hippo.ehviewer.ui.keepNoMediaFileStatus -import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder -import com.hippo.ehviewer.ui.scene.BaseScene -import com.hippo.ehviewer.util.ExceptionUtils -import com.hippo.unifile.UniFile -import eu.kanade.tachiyomi.util.lang.launchNonCancellable - -class DownloadFragment : BasePreferenceFragment() { - private var mDownloadLocation: Preference? = null - private var pickImageDirLauncher = registerForActivityResult( - ActivityResultContracts.OpenDocumentTree(), - ) { treeUri: Uri? -> - if (treeUri != null) { - requireActivity().contentResolver.takePersistableUriPermission( - treeUri, - Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION, - ) - val uniFile = UniFile.fromTreeUri(activity, treeUri) - if (uniFile != null) { - downloadLocation = uniFile - lifecycleScope.launchNonCancellable { - keepNoMediaFileStatus() - } - onUpdateDownloadLocation() - } else { - showTip( - R.string.settings_download_cant_get_download_location, - BaseScene.LENGTH_SHORT, - ) - } - } - } - - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.download_settings) - val mediaScan = findPreference(Settings.KEY_MEDIA_SCAN) - mDownloadLocation = findPreference(KEY_DOWNLOAD_LOCATION) - onUpdateDownloadLocation() - mediaScan!!.onPreferenceChangeListener = this - if (mDownloadLocation != null) { - mDownloadLocation!!.onPreferenceClickListener = this - } - } - - override fun onDestroy() { - super.onDestroy() - mDownloadLocation = null - } - - private fun onUpdateDownloadLocation() { - mDownloadLocation?.summary = downloadLocation.uri.toString() - } - - override fun onPreferenceClick(preference: Preference): Boolean { - val key = preference.key - if (KEY_DOWNLOAD_LOCATION == key) { - val file = downloadLocation - if (!UniFile.isFileUri(downloadLocation.uri)) { - BaseDialogBuilder(requireContext()) - .setTitle(R.string.settings_download_download_location) - .setMessage(file.uri.toString()) - .setPositiveButton(R.string.pick_new_download_location) { _, _ -> openDirPickerL() } - .setNeutralButton(R.string.reset_download_location) { _, _ -> - val uniFile = UniFile.fromFile(AppConfig.defaultDownloadDir) - if (uniFile != null) { - downloadLocation = uniFile - lifecycleScope.launchNonCancellable { - keepNoMediaFileStatus() - } - onUpdateDownloadLocation() - } else { - showTip( - R.string.settings_download_cant_get_download_location, - BaseScene.LENGTH_SHORT, - ) - } - } - .show() - } else { - openDirPickerL() - } - return true - } - return false - } - - private fun openDirPickerL() { - try { - pickImageDirLauncher.launch(null) - } catch (e: Throwable) { - ExceptionUtils.throwIfFatal(e) - showTip(R.string.error_cant_find_activity, BaseScene.LENGTH_SHORT) - } - } - - override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { - val key = preference.key - if (Settings.KEY_MEDIA_SCAN == key) { - if (newValue is Boolean) { - lifecycleScope.launchNonCancellable { - keepNoMediaFileStatus() - } - } - return true - } - return false - } - - override val fragmentTitle: Int - get() = R.string.settings_download - - companion object { - const val KEY_DOWNLOAD_LOCATION = "download_location" - } -} 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 deleted file mode 100644 index d877f9917..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/EhFragment.kt +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.hippo.ehviewer.ui.fragment - -import android.app.Activity -import android.content.res.Configuration -import android.os.Bundle -import android.text.format.DateFormat.is24HourFormat -import androidx.annotation.StringRes -import androidx.appcompat.app.AppCompatDelegate -import androidx.lifecycle.lifecycleScope -import androidx.preference.ListPreference -import androidx.preference.Preference -import com.google.android.material.timepicker.MaterialTimePicker -import com.google.android.material.timepicker.MaterialTimePicker.INPUT_MODE_CLOCK -import com.google.android.material.timepicker.TimeFormat.CLOCK_12H -import com.google.android.material.timepicker.TimeFormat.CLOCK_24H -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 com.hippo.ehviewer.dailycheck.schedHour -import com.hippo.ehviewer.dailycheck.schedMinute -import com.hippo.ehviewer.dailycheck.updateDailyCheckWork -import eu.kanade.tachiyomi.util.lang.launchNonCancellable - -class EhFragment : BasePreferenceFragment() { - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.eh_settings) - val account = findPreference(Settings.KEY_ACCOUNT) - val theme = findPreference(Settings.KEY_THEME) - val blackDarkTheme = findPreference(Settings.KEY_BLACK_DARK_THEME) - val gallerySite = findPreference(Settings.KEY_GALLERY_SITE) - val listMode = findPreference(Settings.KEY_LIST_MODE) - val listThumbSize = findPreference(Settings.KEY_LIST_THUMB_SIZE) - val detailSize = findPreference(Settings.KEY_DETAIL_SIZE) - val thumbSize = findPreference(Settings.KEY_THUMB_SIZE) - val thumbResolution = findPreference(Settings.KEY_THUMB_RESOLUTION) - val showTagTranslations = findPreference(Settings.KEY_SHOW_TAG_TRANSLATIONS) - val tagTranslationsSource = findPreference(Settings.KEY_TAG_TRANSLATIONS_SOURCE) - Settings.displayName?.let { account?.summary = it } - theme!!.onPreferenceChangeListener = this - gallerySite!!.onPreferenceChangeListener = this - listMode!!.onPreferenceChangeListener = this - listThumbSize!!.onPreferenceChangeListener = this - detailSize!!.onPreferenceChangeListener = this - thumbSize!!.onPreferenceChangeListener = this - showTagTranslations!!.onPreferenceChangeListener = this - blackDarkTheme!!.onPreferenceChangeListener = this - thumbResolution!!.setSummaryProvider { - getString(R.string.settings_eh_thumb_resolution_summary, (it as ListPreference).entry) - } - - if (!EhTagDatabase.isTranslatable(requireActivity())) { - preferenceScreen.removePreference(showTagTranslations) - preferenceScreen.removePreference(tagTranslationsSource!!) - } - if (!EhCookieStore.hasSignedIn()) { - Settings.SIGN_IN_REQUIRED.forEach { - val preference = findPreference(it) - preferenceScreen.removePreference(preference!!) - } - } else { - findPreference(Settings.KEY_REQUEST_NEWS_TIMER)!!.apply { - setOnPreferenceClickListener { - MaterialTimePicker.Builder() - .apply { - schedHour?.let { setHour(it) } - schedMinute?.let { setMinute(it) } - } - .setTimeFormat(if (is24HourFormat(requireContext())) CLOCK_24H else CLOCK_12H) - .setInputMode(INPUT_MODE_CLOCK) - .build() - .apply { - addOnPositiveButtonClickListener { - Settings.requestNewsTimerHour = hour - Settings.requestNewsTimerMinute = minute - updateDailyCheckWork(requireContext()) - } - } - .show(childFragmentManager, null) - false - } - } - } - } - - override fun onPreferenceChange(preference: Preference, newValue: Any): Boolean { - val key = preference.key - if (Settings.KEY_THEME == key) { - AppCompatDelegate.setDefaultNightMode((newValue as String).toInt()) - requireActivity().recreate() - return true - } else if (Settings.KEY_GALLERY_SITE == key) { - requireActivity().setResult(Activity.RESULT_OK) - lifecycleScope.launchNonCancellable { - runCatching { - EhEngine.getUConfig() - }.onFailure { - it.printStackTrace() - } - } - return true - } else if (Settings.KEY_LIST_MODE == key) { - requireActivity().setResult(Activity.RESULT_OK) - return true - } else if (Settings.KEY_LIST_THUMB_SIZE == key) { - requireActivity().setResult(Activity.RESULT_OK) - } else if (Settings.KEY_DETAIL_SIZE == key) { - requireActivity().setResult(Activity.RESULT_OK) - } else if (Settings.KEY_THUMB_SIZE == key) { - requireActivity().setResult(Activity.RESULT_OK) - } else if (Settings.KEY_SHOW_TAG_TRANSLATIONS == key) { - if (java.lang.Boolean.TRUE == newValue) { - lifecycleScope.launchNonCancellable { EhTagDatabase.update() } - } - } else if (Settings.KEY_BLACK_DARK_THEME == key) { - if (requireActivity().resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_YES > 0) { - val nightMode = AppCompatDelegate.getDefaultNightMode() - AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_TIME) - AppCompatDelegate.setDefaultNightMode(nightMode) - requireActivity().recreate() - } - return true - } else if (Settings.KEY_REQUEST_NEWS == key) { - updateDailyCheckWork(requireContext()) - } else if (Settings.KEY_REQUEST_NEWS_TIMER == key) { - updateDailyCheckWork(requireContext()) - } - return true - } - - @get:StringRes - override val fragmentTitle: Int - get() = R.string.settings_eh -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/FilterFragment.kt b/app/src/main/java/com/hippo/ehviewer/ui/fragment/FilterFragment.kt deleted file mode 100644 index d89a81df7..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/FilterFragment.kt +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Copyright 2022 Tarsin Norbin - * - * This file is part of EhViewer - * - * EhViewer is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * EhViewer is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with EhViewer. - * If not, see . - */ -package com.hippo.ehviewer.ui.fragment - -import android.content.DialogInterface -import android.os.Bundle -import android.text.TextUtils -import android.view.LayoutInflater -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.view.View -import android.view.ViewGroup -import android.widget.EditText -import android.widget.ImageView -import android.widget.TextView -import androidx.appcompat.app.AlertDialog -import androidx.core.content.ContextCompat -import androidx.core.view.MenuProvider -import androidx.recyclerview.widget.DefaultItemAnimator -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import com.google.android.material.checkbox.MaterialCheckBox -import com.google.android.material.textfield.TextInputLayout -import com.hippo.ehviewer.R -import com.hippo.ehviewer.client.EhFilter -import com.hippo.ehviewer.dao.Filter -import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder -import com.hippo.ehviewer.ui.legacy.ViewTransition -import com.hippo.ehviewer.yorozuya.ViewUtils - -class FilterFragment : BaseFragment() { - private var mViewTransition: ViewTransition? = null - private var mAdapter: FilterAdapter = FilterAdapter() - private var mFilterList: FilterList = FilterList() - private val mMenuProvider: MenuProvider = FilterMenuProvider() - - inner class FilterMenuProvider : MenuProvider { - override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { - menuInflater.inflate(R.menu.activity_filter, menu) - } - - override fun onMenuItemSelected(menuItem: MenuItem): Boolean { - val itemId = menuItem.itemId - if (itemId == R.id.action_tip) { - showTipDialog() - return true - } - return false - } - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - val recyclerView = - inflater.inflate(R.layout.rv_layout, container, false) as RecyclerView - val tip = getTipView(R.string.filter) - mViewTransition = - ViewTransition(recyclerView, tip) - val fab = getFabViewAndShow() - val drawable = ContextCompat.getDrawable(requireActivity(), R.drawable.big_filter) - drawable?.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight) - tip.setCompoundDrawables(null, drawable, null, null) - mAdapter.setHasStableIds(true) - recyclerView.adapter = mAdapter - recyclerView.layoutManager = LinearLayoutManager(requireContext()) - recyclerView.setHasFixedSize(true) - val defaultItemAnimator = recyclerView.itemAnimator as DefaultItemAnimator? - defaultItemAnimator?.supportsChangeAnimations = false - fab.setOnClickListener { showAddFilterDialog() } - return recyclerView - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - updateView(false) - requireActivity().addMenuProvider(mMenuProvider) - } - - private fun updateView(animation: Boolean) { - if (null == mViewTransition) { - return - } - if (0 == mFilterList.size()) { - mViewTransition!!.showView(1, animation) - } else { - mViewTransition!!.showView(0, animation) - } - } - - override fun onDestroyView() { - mViewTransition = null - requireActivity().removeMenuProvider(mMenuProvider) - super.onDestroyView() - } - - private fun showTipDialog() { - BaseDialogBuilder(requireActivity()) - .setTitle(R.string.filter) - .setMessage(R.string.filter_tip) - .setPositiveButton(android.R.string.ok, null) - .show() - } - - private fun showAddFilterDialog() { - val dialog = BaseDialogBuilder(requireActivity()) - .setTitle(R.string.add_filter) - .setView(R.layout.dialog_add_filter) - .setPositiveButton(R.string.add, null) - .setNegativeButton(android.R.string.cancel, null) - .show() - AddFilterDialogHelper(dialog) - } - - private fun showDeleteFilterDialog(filter: Filter) { - val message = getString(R.string.delete_filter, filter.text) - BaseDialogBuilder(requireActivity()) - .setMessage(message) - .setPositiveButton(R.string.delete) { _: DialogInterface?, which: Int -> - if (DialogInterface.BUTTON_POSITIVE != which) { - return@setPositiveButton - } - mFilterList.delete(filter) - mAdapter.notifyDataSetChanged() - updateView(true) - } - .setNegativeButton(android.R.string.cancel, null) - .show() - } - - override fun getFragmentTitle(): Int { - return R.string.filter - } - - private class FilterHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { - val checkbox: MaterialCheckBox? - val text: TextView? - val delete: ImageView? - - init { - checkbox = itemView.findViewById(R.id.checkbox) - text = itemView.findViewById(R.id.text) - delete = itemView.findViewById(R.id.delete) - } - } - - private inner class AddFilterDialogHelper(dialog: AlertDialog) : View.OnClickListener { - private var mDialog: AlertDialog - private var mSpinner: TextInputLayout - private var mInputLayout: TextInputLayout - private var mEditText: EditText - private val mArray: Array = - context!!.resources.getStringArray(R.array.filter_entries) - - init { - mDialog = dialog - mSpinner = ViewUtils.`$$`(dialog, R.id.spinner) as TextInputLayout - mInputLayout = ViewUtils.`$$`(dialog, R.id.text_input_layout) as TextInputLayout - mEditText = mInputLayout.editText!! - val button: View? = dialog.getButton(DialogInterface.BUTTON_POSITIVE) - button?.setOnClickListener(this) - } - - override fun onClick(v: View) { - val text1 = mSpinner.editText!!.text.toString() - if (TextUtils.isEmpty(text1)) { - mSpinner.error = getString(R.string.text_is_empty) - return - } else { - mSpinner.error = null - } - val text = mEditText.text.toString().trim { it <= ' ' } - if (TextUtils.isEmpty(text)) { - mInputLayout.error = getString(R.string.text_is_empty) - return - } else { - mInputLayout.error = null - } - val mode = mArray.indexOf(text1) - val filter = Filter() - filter.mode = mode - filter.text = text - if (!mFilterList.add(filter)) { - mInputLayout.error = getString(R.string.label_text_exist) - return - } else { - mInputLayout.error = null - } - mAdapter.notifyDataSetChanged() - updateView(true) - mDialog.dismiss() - } - } - - private inner class FilterAdapter : RecyclerView.Adapter() { - override fun getItemViewType(position: Int): Int { - return if (mFilterList[position].mode == MODE_HEADER) { - TYPE_HEADER - } else { - TYPE_ITEM - } - } - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): FilterHolder { - val layoutId: Int = when (viewType) { - TYPE_ITEM -> R.layout.item_filter - TYPE_HEADER -> R.layout.item_filter_header - else -> R.layout.item_filter - } - return FilterHolder(layoutInflater.inflate(layoutId, parent, false)) - } - - override fun onBindViewHolder(holder: FilterHolder, position: Int) { - val filter = mFilterList[position] - if (MODE_HEADER == filter.mode) { - holder.text?.text = filter.text - } else { - holder.checkbox?.text = filter.text - holder.checkbox?.isChecked = filter.enable!! - holder.itemView.setOnClickListener { - mFilterList.trigger(filter) - - // for updating delete line on filter text - mAdapter.notifyItemChanged(position) - } - holder.delete?.setOnClickListener { showDeleteFilterDialog(filter) } - } - } - - override fun getItemCount(): Int { - return mFilterList.size() - } - - override fun getItemId(position: Int): Long { - return run { - val filter = mFilterList[position] - if (filter.id != null) { - (filter.text.hashCode() shr filter.mode) + filter.id!! - } else { - (filter.text.hashCode() shr filter.mode).toLong() - } - } - } - } - - private inner class FilterList { - private val mEhFilter: EhFilter = EhFilter - private val mTitleFilterList: List = mEhFilter.titleFilterList - private val mUploaderFilterList: List = mEhFilter.uploaderFilterList - private val mTagFilterList: List = mEhFilter.tagFilterList - private val mTagNamespaceFilterList: List = mEhFilter.tagNamespaceFilterList - private val mCommenterFilterList: List = mEhFilter.commenterFilterList - private val mCommentFilterList: List = mEhFilter.commentFilterList - private var mTitleHeader: Filter? = null - private var mUploaderHeader: Filter? = null - private var mTagHeader: Filter? = null - private var mTagNamespaceHeader: Filter? = null - private var mCommenterHeader: Filter? = null - private var mCommentHeader: Filter? = null - fun size(): Int { - var count = 0 - var size = mTitleFilterList.size - count += if (0 == size) 0 else size + 1 - size = mUploaderFilterList.size - count += if (0 == size) 0 else size + 1 - size = mTagFilterList.size - count += if (0 == size) 0 else size + 1 - size = mTagNamespaceFilterList.size - count += if (0 == size) 0 else size + 1 - size = mCommenterFilterList.size - count += if (0 == size) 0 else size + 1 - size = mCommentFilterList.size - count += if (0 == size) 0 else size + 1 - return count - } - - private val titleHeader: Filter - get() { - if (null == mTitleHeader) { - mTitleHeader = Filter() - mTitleHeader!!.mode = MODE_HEADER - mTitleHeader!!.text = getString(R.string.filter_title) - } - return mTitleHeader!! - } - private val uploaderHeader: Filter - get() { - if (null == mUploaderHeader) { - mUploaderHeader = Filter() - mUploaderHeader!!.mode = MODE_HEADER - mUploaderHeader!!.text = getString(R.string.filter_uploader) - } - return mUploaderHeader!! - } - private val tagHeader: Filter - get() { - if (null == mTagHeader) { - mTagHeader = Filter() - mTagHeader!!.mode = MODE_HEADER - mTagHeader!!.text = getString(R.string.filter_tag) - } - return mTagHeader!! - } - private val tagNamespaceHeader: Filter - get() { - if (null == mTagNamespaceHeader) { - mTagNamespaceHeader = Filter() - mTagNamespaceHeader!!.mode = MODE_HEADER - mTagNamespaceHeader!!.text = getString(R.string.filter_tag_namespace) - } - return mTagNamespaceHeader!! - } - private val commenterHeader: Filter - get() { - if (null == mCommenterHeader) { - mCommenterHeader = Filter() - mCommenterHeader!!.mode = MODE_HEADER - mCommenterHeader!!.text = getString(R.string.filter_commenter) - } - return mCommenterHeader!! - } - private val commentHeader: Filter - get() { - if (null == mCommentHeader) { - mCommentHeader = Filter() - mCommentHeader!!.mode = MODE_HEADER - mCommentHeader!!.text = getString(R.string.filter_comment) - } - return mCommentHeader!! - } - - operator fun get(index: Int): Filter { - var index1 = index - var size = mTitleFilterList.size - if (0 != size) { - index1 -= if (index1 == 0) { - return titleHeader - } else if (index1 <= size) { - return mTitleFilterList[index1 - 1] - } else { - size + 1 - } - } - size = mUploaderFilterList.size - if (0 != size) { - index1 -= if (index1 == 0) { - return uploaderHeader - } else if (index1 <= size) { - return mUploaderFilterList[index1 - 1] - } else { - size + 1 - } - } - size = mTagFilterList.size - if (0 != size) { - index1 -= if (index1 == 0) { - return tagHeader - } else if (index1 <= size) { - return mTagFilterList[index1 - 1] - } else { - size + 1 - } - } - size = mTagNamespaceFilterList.size - if (0 != size) { - index1 -= if (index1 == 0) { - return tagNamespaceHeader - } else if (index1 <= size) { - return mTagNamespaceFilterList[index1 - 1] - } else { - size + 1 - } - } - size = mCommenterFilterList.size - if (0 != size) { - index1 -= if (index1 == 0) { - return commenterHeader - } else if (index1 <= size) { - return mCommenterFilterList[index1 - 1] - } else { - size + 1 - } - } - size = mCommentFilterList.size - if (0 != size) { - if (index1 == 0) { - return commentHeader - } else if (index1 <= size) { - return mCommentFilterList[index1 - 1] - } - } - throw IndexOutOfBoundsException() - } - - fun add(filter: Filter): Boolean { - return mEhFilter.addFilter(filter) - } - - fun delete(filter: Filter) { - mEhFilter.deleteFilter(filter) - } - - fun trigger(filter: Filter) { - mEhFilter.triggerFilter(filter) - } - } - - companion object { - private const val MODE_HEADER = -1 - private const val TYPE_ITEM = 0 - private const val TYPE_HEADER = 1 - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/LicenseFragment.kt b/app/src/main/java/com/hippo/ehviewer/ui/fragment/LicenseFragment.kt deleted file mode 100644 index 3bf16768e..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/LicenseFragment.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.hippo.ehviewer.ui.fragment - -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.ComposeView -import com.hippo.ehviewer.R -import com.hippo.ehviewer.ui.compose.setMD3Content -import com.mikepenz.aboutlibraries.ui.compose.LibrariesContainer - -class LicenseFragment : BaseFragment() { - override fun getFragmentTitle(): Int { - return R.string.license - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - return ComposeView(inflater.context).apply { - setMD3Content { - LibrariesContainer(modifier = Modifier.fillMaxSize()) - } - } - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/MyTagsFragment.kt b/app/src/main/java/com/hippo/ehviewer/ui/fragment/MyTagsFragment.kt deleted file mode 100644 index 2e1079236..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/MyTagsFragment.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2022 Tarsin Norbin - * - * This file is part of EhViewer - * - * EhViewer is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * EhViewer is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with EhViewer. - * If not, see . - */ -package com.hippo.ehviewer.ui.fragment - -import android.annotation.SuppressLint -import android.graphics.Bitmap -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.webkit.CookieManager -import android.webkit.WebResourceRequest -import android.webkit.WebView -import android.webkit.WebViewClient -import com.hippo.ehviewer.R -import com.hippo.ehviewer.client.EhCookieStore -import com.hippo.ehviewer.client.EhUrl -import com.hippo.ehviewer.databinding.ActivityWebviewBinding -import com.hippo.ehviewer.ui.legacy.DialogWebChromeClient -import okhttp3.HttpUrl.Companion.toHttpUrl -import rikka.core.res.resolveColor - -class MyTagsFragment : BaseFragment() { - private var _binding: ActivityWebviewBinding? = null - private val binding get() = _binding!! - private val url = EhUrl.myTagsUrl - - @SuppressLint("SetJavaScriptEnabled") - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - _binding = ActivityWebviewBinding.inflate(inflater, container, false) - binding.webview.run { - setBackgroundColor(requireActivity().theme.resolveColor(android.R.attr.colorBackground)) - settings.builtInZoomControls = true - settings.displayZoomControls = false - settings.javaScriptEnabled = true - webViewClient = MyTagsWebViewClient() - webChromeClient = DialogWebChromeClient(requireContext()) - } - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - binding.progress.visibility = View.VISIBLE - binding.webview.loadUrl(url) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - // http://stackoverflow.com/questions/32284642/how-to-handle-an-uncatched-exception - val cookieManager = CookieManager.getInstance() - cookieManager.flush() - cookieManager.removeAllCookies(null) - cookieManager.removeSessionCookies(null) - - // Copy cookies from okhttp cookie store to CookieManager - val store = EhCookieStore - for (cookie in store.getCookies(url.toHttpUrl())) { - cookieManager.setCookie(url, cookie.toString()) - } - } - - override fun onDestroyView() { - super.onDestroyView() - binding.webview.destroy() - _binding = null - } - - override fun getFragmentTitle(): Int { - return R.string.my_tags - } - - private inner class MyTagsWebViewClient : WebViewClient() { - override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { - // Never load other urls - return request.url.toString() != this@MyTagsFragment.url - } - - override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { - binding.progress.visibility = View.VISIBLE - } - - override fun onPageFinished(view: WebView, url: String) { - binding.progress.visibility = View.GONE - } - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/PrivacyFragment.kt b/app/src/main/java/com/hippo/ehviewer/ui/fragment/PrivacyFragment.kt deleted file mode 100644 index e93b01ed7..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/PrivacyFragment.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2022 Tarsin Norbin - * - * This file is part of EhViewer - * - * EhViewer is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * EhViewer is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with EhViewer. - * If not, see . - */ - -package com.hippo.ehviewer.ui.fragment - -import android.os.Bundle -import androidx.annotation.StringRes -import androidx.preference.SeekBarPreference -import androidx.preference.SwitchPreferenceCompat -import com.hippo.ehviewer.R -import com.hippo.ehviewer.Settings -import com.hippo.ehviewer.ui.isAuthenticationSupported - -/** - * Created by Mo10 on 2018/2/10. - */ -class PrivacyFragment : BasePreferenceFragment() { - private lateinit var requireUnlock: SwitchPreferenceCompat - private lateinit var unlockDelay: SeekBarPreference - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.privacy_settings) - requireUnlock = findPreference("require_unlock")!! - unlockDelay = findPreference("require_unlock_delay")!! - requireUnlock.setOnPreferenceChangeListener { _, newValue -> - unlockDelay.isEnabled = newValue as Boolean - setUnlockDelaySummary(unlockDelay.value) - true - } - unlockDelay.setOnPreferenceChangeListener { _, newValue -> - setUnlockDelaySummary(newValue as Int) - true - } - } - - override fun onStart() { - super.onStart() - if (!requireContext().isAuthenticationSupported()) { - Settings.security = false - requireUnlock.isEnabled = false - requireUnlock.isChecked = false - unlockDelay.isEnabled = false - } else { - unlockDelay.isEnabled = requireUnlock.isChecked == true - setUnlockDelaySummary(unlockDelay.value) - } - } - - @get:StringRes - override val fragmentTitle: Int - get() = R.string.settings_privacy - - private fun setUnlockDelaySummary(value: Int) { - unlockDelay.summary = if (value == 0) { - getString(R.string.settings_privacy_require_unlock_delay_summary_immediately) - } else { - getString(R.string.settings_privacy_require_unlock_delay_summary, value.toString()) - } - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/SettingsFragment.kt b/app/src/main/java/com/hippo/ehviewer/ui/fragment/SettingsFragment.kt deleted file mode 100644 index 4747bd187..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/SettingsFragment.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2022 Tarsin Norbin - * - * This file is part of EhViewer - * - * EhViewer is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * EhViewer is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with EhViewer. - * If not, see . - */ -package com.hippo.ehviewer.ui.fragment - -import android.os.Bundle -import com.hippo.ehviewer.R - -class SettingsFragment : BasePreferenceFragment() { - override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { - addPreferencesFromResource(R.xml.settings_headers) - } - - override val fragmentTitle: Int - get() = R.string.settings -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/fragment/UConfigFragment.kt b/app/src/main/java/com/hippo/ehviewer/ui/fragment/UConfigFragment.kt deleted file mode 100644 index 5bf92a1ec..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/fragment/UConfigFragment.kt +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2022 Tarsin Norbin - * - * This file is part of EhViewer - * - * EhViewer is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * EhViewer is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with EhViewer. - * If not, see . - */ -package com.hippo.ehviewer.ui.fragment - -import android.annotation.SuppressLint -import android.graphics.Bitmap -import android.os.Bundle -import android.view.LayoutInflater -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.view.View -import android.view.ViewGroup -import android.webkit.CookieManager -import android.webkit.WebResourceRequest -import android.webkit.WebView -import android.webkit.WebViewClient -import androidx.core.view.MenuProvider -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import com.hippo.ehviewer.R -import com.hippo.ehviewer.client.EhCookieStore -import com.hippo.ehviewer.client.EhCookieStore.KEY_SETTINGS_PROFILE -import com.hippo.ehviewer.client.EhUrl -import com.hippo.ehviewer.databinding.ActivityWebviewBinding -import com.hippo.ehviewer.ui.legacy.DialogWebChromeClient -import com.hippo.ehviewer.ui.scene.BaseScene -import eu.kanade.tachiyomi.util.lang.launchIO -import okhttp3.Cookie -import okhttp3.HttpUrl.Companion.toHttpUrl -import rikka.core.res.resolveColor - -class UConfigFragment : BaseFragment() { - private var _binding: ActivityWebviewBinding? = null - private val binding get() = _binding!! - private val url = EhUrl.uConfigUrl - private var loaded = false - - @SuppressLint("SetJavaScriptEnabled") - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - _binding = ActivityWebviewBinding.inflate(inflater, container, false) - binding.webview.run { - setBackgroundColor(requireActivity().theme.resolveColor(android.R.attr.colorBackground)) - settings.builtInZoomControls = true - settings.displayZoomControls = false - settings.javaScriptEnabled = true - webViewClient = UConfigWebViewClient() - webChromeClient = DialogWebChromeClient(requireContext()) - } - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - binding.progress.visibility = View.VISIBLE - binding.webview.loadUrl(url) - showTip(R.string.apply_tip, BaseScene.LENGTH_LONG) - requireActivity().addMenuProvider( - object : MenuProvider { - override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) { - menuInflater.inflate(R.menu.activity_u_config, menu) - } - - override fun onMenuItemSelected(menuItem: MenuItem): Boolean { - if (menuItem.itemId == R.id.action_apply) { - if (loaded) { - apply() - } - return true - } - return false - } - }, - viewLifecycleOwner, - Lifecycle.State.RESUMED, - ) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - // http://stackoverflow.com/questions/32284642/how-to-handle-an-uncatched-exception - val cookieManager = CookieManager.getInstance() - cookieManager.flush() - cookieManager.removeAllCookies(null) - cookieManager.removeSessionCookies(null) - - // Copy cookies from okhttp cookie store to CookieManager - val store = EhCookieStore - for (cookie in store.getCookies(url.toHttpUrl())) { - cookieManager.setCookie(url, cookie.toString()) - } - } - - private fun apply() { - binding.webview.loadUrl( - """javascript:(function() { - var apply = document.getElementById("apply").children[0]; - apply.click(); -})();""", - ) - } - - private fun longLive(cookie: Cookie): Cookie { - return Cookie.Builder() - .name(cookie.name) - .value(cookie.value) - .domain(cookie.domain) - .path(cookie.path) - .expiresAt(Long.MAX_VALUE) - .build() - } - - override fun onDestroyView() { - super.onDestroyView() - binding.webview.destroy() - - // Put cookies back to okhttp cookie store - val cookieManager = CookieManager.getInstance() - val cookiesString = cookieManager.getCookie(url) - if (!cookiesString.isNullOrEmpty()) { - val store = EhCookieStore - val hostUrl = EhUrl.host.toHttpUrl() - - lifecycleScope.launchIO { - store.deleteCookie(hostUrl, KEY_SETTINGS_PROFILE) - // The cookies saved in the uconfig page should not be shared between e and ex - for (header in cookiesString.split(";".toRegex()).dropLastWhile { it.isEmpty() }) { - Cookie.parse(hostUrl, header)?.let { - store.addCookie(longLive(it)) - } - } - } - } - _binding = null - } - - override fun getFragmentTitle(): Int { - return R.string.u_config - } - - private inner class UConfigWebViewClient : WebViewClient() { - override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { - // Never load other urls - return true - } - - override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { - binding.progress.visibility = View.VISIBLE - loaded = false - } - - override fun onPageFinished(view: WebView, url: String) { - binding.progress.visibility = View.GONE - loaded = true - } - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/legacy/SearchLayout.kt b/app/src/main/java/com/hippo/ehviewer/ui/legacy/SearchLayout.kt index 10aaa0d64..23e1866e3 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/legacy/SearchLayout.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/legacy/SearchLayout.kt @@ -33,7 +33,6 @@ import android.widget.TextView import androidx.annotation.IntDef import androidx.core.content.edit import androidx.core.view.forEach -import androidx.preference.PreferenceManager import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.LinearLayoutManager import com.google.android.material.chip.Chip @@ -41,6 +40,7 @@ import com.google.android.material.chip.ChipGroup import com.google.android.material.tabs.TabLayout import com.google.android.material.tabs.TabLayout.OnTabSelectedListener import com.hippo.ehviewer.R +import com.hippo.ehviewer.Settings import com.hippo.ehviewer.client.EhUtils import com.hippo.ehviewer.client.data.ListUrlBuilder import com.hippo.ehviewer.client.exception.EhException @@ -74,11 +74,10 @@ class SearchLayout @JvmOverloads constructor( private var mAction: TabLayout private var mAdapter: SearchAdapter private var mHelper: Helper? = null - private val mSharePref: SharedPreferences + private val mSharePref: SharedPreferences = Settings.prefs private val mInflater: LayoutInflater init { - mSharePref = PreferenceManager.getDefaultSharedPreferences(context) mInflater = LayoutInflater.from(context) val resources = context.resources layoutManager = SearchLayoutManager(context) @@ -213,7 +212,7 @@ class SearchLayout @JvmOverloads constructor( } } urlBuilder.keyword = query - urlBuilder.category = PreferenceManager.getDefaultSharedPreferences(context).getInt( + urlBuilder.category = Settings.prefs.getInt( SEARCH_CATEGORY_PREF, 0, ) diff --git a/app/src/main/java/com/hippo/ehviewer/ui/legacy/preference/DialogPreference.java b/app/src/main/java/com/hippo/ehviewer/ui/legacy/preference/DialogPreference.java deleted file mode 100644 index 08fc6af2e..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/legacy/preference/DialogPreference.java +++ /dev/null @@ -1,424 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.ehviewer.ui.legacy.preference; - -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.SharedPreferences; -import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; - -import androidx.annotation.DrawableRes; -import androidx.annotation.StringRes; -import androidx.appcompat.app.AlertDialog; -import androidx.core.content.ContextCompat; -import androidx.preference.Preference; - -import com.hippo.ehviewer.ui.legacy.BaseDialogBuilder; -import com.hippo.ehviewer.R; - -/** - * A base class for {@link Preference} objects that are - * dialog-based. These preferences will, when clicked, open a dialog showing the - * actual preference controls. - */ -public abstract class DialogPreference extends Preference implements - DialogInterface.OnClickListener, DialogInterface.OnDismissListener { - - private AlertDialog.Builder mBuilder; - - private CharSequence mDialogTitle; - private Drawable mDialogIcon; - private CharSequence mPositiveButtonText; - private CharSequence mNegativeButtonText; - private int mDialogLayoutResId; - - /** - * The dialog, if it is showing. - */ - private AlertDialog mDialog; - - /** - * Which button was clicked. - */ - private int mWhichButtonClicked; - - public DialogPreference(Context context) { - super(context); - init(context, null, 0, 0); - } - - public DialogPreference(Context context, AttributeSet attrs) { - super(context, attrs); - init(context, attrs, 0, 0); - } - - public DialogPreference(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context, attrs, defStyleAttr, defStyleAttr); - } - - private void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DialogPreference, defStyleAttr, defStyleRes); - mDialogTitle = a.getString(R.styleable.DialogPreference_dialogTitle); - if (mDialogTitle == null) { - // Fallback on the regular title of the preference - // (the one that is seen in the list) - mDialogTitle = getTitle(); - } - mDialogIcon = a.getDrawable(R.styleable.DialogPreference_dialogIcon); - mPositiveButtonText = a.getString(R.styleable.DialogPreference_positiveButtonText); - mNegativeButtonText = a.getString(R.styleable.DialogPreference_negativeButtonText); - mDialogLayoutResId = a.getResourceId(R.styleable.DialogPreference_dialogLayout, mDialogLayoutResId); - a.recycle(); - } - - /** - * Returns the title to be shown on subsequent dialogs. - * - * @return The title. - */ - public CharSequence getDialogTitle() { - return mDialogTitle; - } - - /** - * Sets the title of the dialog. This will be shown on subsequent dialogs. - * - * @param dialogTitle The title. - */ - public void setDialogTitle(CharSequence dialogTitle) { - mDialogTitle = dialogTitle; - } - - /** - * @param dialogTitleResId The dialog title as a resource. - * @see #setDialogTitle(CharSequence) - */ - public void setDialogTitle(int dialogTitleResId) { - setDialogTitle(getContext().getString(dialogTitleResId)); - } - - /** - * Returns the icon to be shown on subsequent dialogs. - * - * @return The icon, as a {@link Drawable}. - */ - public Drawable getDialogIcon() { - return mDialogIcon; - } - - /** - * Sets the icon of the dialog. This will be shown on subsequent dialogs. - * - * @param dialogIcon The icon, as a {@link Drawable}. - */ - public void setDialogIcon(Drawable dialogIcon) { - mDialogIcon = dialogIcon; - } - - /** - * Sets the icon (resource ID) of the dialog. This will be shown on - * subsequent dialogs. - * - * @param dialogIconRes The icon, as a resource ID. - */ - public void setDialogIcon(@DrawableRes int dialogIconRes) { - mDialogIcon = ContextCompat.getDrawable(getContext(), dialogIconRes); - } - - /** - * Returns the text of the positive button to be shown on subsequent - * dialogs. - * - * @return The text of the positive button. - */ - public CharSequence getPositiveButtonText() { - return mPositiveButtonText; - } - - /** - * Sets the text of the positive button of the dialog. This will be shown on - * subsequent dialogs. - * - * @param positiveButtonText The text of the positive button. - */ - public void setPositiveButtonText(CharSequence positiveButtonText) { - mPositiveButtonText = positiveButtonText; - } - - /** - * @param positiveButtonTextResId The positive button text as a resource. - * @see #setPositiveButtonText(CharSequence) - */ - public void setPositiveButtonText(@StringRes int positiveButtonTextResId) { - setPositiveButtonText(getContext().getString(positiveButtonTextResId)); - } - - /** - * Returns the text of the negative button to be shown on subsequent - * dialogs. - * - * @return The text of the negative button. - */ - public CharSequence getNegativeButtonText() { - return mNegativeButtonText; - } - - /** - * Sets the text of the negative button of the dialog. This will be shown on - * subsequent dialogs. - * - * @param negativeButtonText The text of the negative button. - */ - public void setNegativeButtonText(CharSequence negativeButtonText) { - mNegativeButtonText = negativeButtonText; - } - - /** - * @param negativeButtonTextResId The negative button text as a resource. - * @see #setNegativeButtonText(CharSequence) - */ - public void setNegativeButtonText(@StringRes int negativeButtonTextResId) { - setNegativeButtonText(getContext().getString(negativeButtonTextResId)); - } - - /** - * Returns the layout resource that is used as the content View for - * subsequent dialogs. - * - * @return The layout resource. - */ - public int getDialogLayoutResource() { - return mDialogLayoutResId; - } - - /** - * Sets the layout resource that is inflated as the {@link View} to be shown - * as the content View of subsequent dialogs. - * - * @param dialogLayoutResId The layout resource ID to be inflated. - */ - public void setDialogLayoutResource(int dialogLayoutResId) { - mDialogLayoutResId = dialogLayoutResId; - } - - /** - * Prepares the dialog builder to be shown when the preference is clicked. - * Use this to set custom properties on the dialog. - *

- * Do not {@link AlertDialog.Builder#create()} or - * {@link AlertDialog.Builder#show()}. - */ - protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { - } - - @Override - protected void onClick() { - if (mDialog != null && mDialog.isShowing()) return; - - showDialog(null); - } - - /** - * Shows the dialog associated with this Preference. This is normally initiated - * automatically on clicking on the preference. Call this method if you need to - * show the dialog on some other event. - * - * @param state Optional instance state to restore on the dialog - */ - protected void showDialog(Bundle state) { - Context context = getContext(); - - mWhichButtonClicked = DialogInterface.BUTTON_NEGATIVE; - - mBuilder = new BaseDialogBuilder(context) - .setTitle(mDialogTitle) - .setIcon(mDialogIcon) - .setPositiveButton(mPositiveButtonText, this) - .setNegativeButton(mNegativeButtonText, this); - - View contentView = onCreateDialogView(); - if (contentView != null) { - onBindDialogView(contentView); - mBuilder.setView(contentView); - } - - onPrepareDialogBuilder(mBuilder); - - //PreferenceUtils.registerOnActivityDestroyListener(this, this); - - // Create the dialog - final AlertDialog dialog = mDialog = mBuilder.create(); - if (state != null) { - dialog.onRestoreInstanceState(state); - } - if (needInputMethod()) { - requestInputMethod(dialog); - } - dialog.setOnDismissListener(this); - dialog.show(); - - onDialogCreated(dialog); - } - - /** - * Returns whether the preference needs to display a soft input method when the dialog - * is displayed. Default is false. Subclasses should override this method if they need - * the soft input method brought up automatically. - */ - protected boolean needInputMethod() { - return false; - } - - /** - * Sets the required flags on the dialog window to enable input method window to show up. - */ - private void requestInputMethod(Dialog dialog) { - Window window = dialog.getWindow(); - window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); - } - - /** - * Creates the content view for the dialog (if a custom content view is - * required). By default, it inflates the dialog layout resource if it is - * set. - * - * @return The content View for the dialog. - * @see #setLayoutResource(int) - */ - protected View onCreateDialogView() { - if (mDialogLayoutResId == 0) { - return null; - } - - LayoutInflater inflater = LayoutInflater.from(mBuilder.getContext()); - return inflater.inflate(mDialogLayoutResId, null); - } - - /** - * Binds views in the content View of the dialog to data. - * - * @param view The content View of the dialog, if it is custom. - */ - protected void onBindDialogView(View view) { - } - - protected void onDialogCreated(AlertDialog dialog) { - } - - @Override - public void onClick(DialogInterface dialog, int which) { - mWhichButtonClicked = which; - } - - @Override - public void onDismiss(DialogInterface dialog) { - mDialog = null; - onDialogClosed(mWhichButtonClicked == DialogInterface.BUTTON_POSITIVE); - } - - /** - * Called when the dialog is dismissed and should be used to save data to - * the {@link SharedPreferences}. - * - * @param positiveResult Whether the positive button was clicked (true), or - * the negative button was clicked or the dialog was canceled (false). - */ - protected void onDialogClosed(boolean positiveResult) { - } - - /** - * Gets the dialog that is shown by this preference. - * - * @return The dialog, or null if a dialog is not being shown. - */ - public Dialog getDialog() { - return mDialog; - } - - @Override - protected Parcelable onSaveInstanceState() { - final Parcelable superState = super.onSaveInstanceState(); - if (mDialog == null || !mDialog.isShowing()) { - return superState; - } - - final SavedState myState = new SavedState(superState); - myState.isDialogShowing = true; - myState.dialogBundle = mDialog.onSaveInstanceState(); - return myState; - } - - @Override - protected void onRestoreInstanceState(Parcelable state) { - if (state == null || !state.getClass().equals(SavedState.class)) { - // Didn't save state for us in onSaveInstanceState - super.onRestoreInstanceState(state); - return; - } - - SavedState myState = (SavedState) state; - super.onRestoreInstanceState(myState.getSuperState()); - if (myState.isDialogShowing) { - showDialog(myState.dialogBundle); - } - } - - private static class SavedState extends BaseSavedState { - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public SavedState createFromParcel(Parcel in) { - return new SavedState(in); - } - - @Override - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; - boolean isDialogShowing; - Bundle dialogBundle; - - public SavedState(Parcel source) { - super(source); - isDialogShowing = source.readInt() == 1; - dialogBundle = source.readBundle(DialogPreference.class.getClassLoader()); - } - - public SavedState(Parcelable superState) { - super(superState); - } - - @Override - public void writeToParcel(Parcel dest, int flags) { - super.writeToParcel(dest, flags); - dest.writeInt(isDialogShowing ? 1 : 0); - dest.writeBundle(dialogBundle); - } - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/legacy/preference/MessagePreference.java b/app/src/main/java/com/hippo/ehviewer/ui/legacy/preference/MessagePreference.java deleted file mode 100644 index e1990b4f9..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/legacy/preference/MessagePreference.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.hippo.ehviewer.ui.legacy.preference; - -import android.content.Context; -import android.content.res.TypedArray; -import android.text.Html; -import android.text.method.LinkMovementMethod; -import android.util.AttributeSet; -import android.view.View; -import android.widget.TextView; - -import androidx.appcompat.app.AlertDialog; - -import com.hippo.ehviewer.R; - -public class MessagePreference extends DialogPreference { - - private CharSequence mDialogMessage; - private boolean mDialogMessageLinkify; - - public MessagePreference(Context context) { - super(context); - init(context, null, 0, 0); - } - - public MessagePreference(Context context, AttributeSet attrs) { - super(context, attrs); - init(context, attrs, 0, 0); - } - - public MessagePreference(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context, attrs, defStyleAttr, 0); - } - - public void init(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MessagePreference, defStyleAttr, defStyleRes); - String message = a.getString(R.styleable.MessagePreference_dialogMessage); - if (a.getBoolean(R.styleable.MessagePreference_dialogMessageHtml, false)) { - mDialogMessage = Html.fromHtml(message, Html.FROM_HTML_MODE_LEGACY); - } else { - mDialogMessage = message; - } - mDialogMessageLinkify = a.getBoolean(R.styleable.MessagePreference_dialogMessageLinkify, false); - a.recycle(); - } - - public void setDialogMessage(CharSequence message) { - mDialogMessage = message; - } - - @Override - protected void onPrepareDialogBuilder(AlertDialog.Builder builder) { - super.onPrepareDialogBuilder(builder); - builder.setMessage(mDialogMessage); - builder.setPositiveButton(android.R.string.ok, this); - builder.setNegativeButton(null, null); - } - - @Override - protected void onDialogCreated(AlertDialog dialog) { - super.onDialogCreated(dialog); - - if (mDialogMessageLinkify) { - final View messageView = dialog.findViewById(android.R.id.message); - if (messageView instanceof TextView) { - ((TextView) messageView).setMovementMethod(LinkMovementMethod.getInstance()); - } - } - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/ui/legacy/preference/UrlPreference.kt b/app/src/main/java/com/hippo/ehviewer/ui/legacy/preference/UrlPreference.kt deleted file mode 100644 index dafa4bdbe..000000000 --- a/app/src/main/java/com/hippo/ehviewer/ui/legacy/preference/UrlPreference.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2016 Hippo Seven - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.hippo.ehviewer.ui.legacy.preference - -import android.content.Context -import android.util.AttributeSet -import androidx.preference.Preference -import com.hippo.ehviewer.R -import com.hippo.ehviewer.ui.openBrowser - -class UrlPreference @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : - Preference(context, attrs) { - private val mUrl: String? - - init { - val a = context.obtainStyledAttributes(attrs, R.styleable.UrlPreference, 0, 0) - mUrl = a.getString(R.styleable.UrlPreference_url) - a.recycle() - } - - override fun getSummary(): CharSequence? { - return mUrl ?: super.getSummary() - } - - override fun onClick() { - if (mUrl != null) { - context.openBrowser(mUrl) - } - } -} diff --git a/app/src/main/java/com/hippo/ehviewer/util/ClipboardUtil.kt b/app/src/main/java/com/hippo/ehviewer/util/ClipboardUtil.kt index ffad7eaab..148096fb7 100644 --- a/app/src/main/java/com/hippo/ehviewer/util/ClipboardUtil.kt +++ b/app/src/main/java/com/hippo/ehviewer/util/ClipboardUtil.kt @@ -27,7 +27,6 @@ import android.text.TextUtils import android.view.textclassifier.TextClassifier import com.hippo.ehviewer.R import com.hippo.ehviewer.ui.MainActivity -import com.hippo.ehviewer.ui.SettingsActivity import com.hippo.ehviewer.ui.scene.BaseScene import splitties.systemservices.clipboardManager @@ -52,8 +51,6 @@ fun Context.addTextToClipboard(text: CharSequence?, isSensitive: Boolean, useToa if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { if (this is MainActivity) { showTip(R.string.copied_to_clipboard, BaseScene.LENGTH_SHORT, useToast) - } else if (this is SettingsActivity) { - showTip(R.string.copied_to_clipboard, BaseScene.LENGTH_SHORT) } } } diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index d1857a999..55c6dc3f0 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -70,7 +70,7 @@ android:label="DownloadsScene" /> @color/divider - @style/PreferenceThemeOverlay.Rikka.Material3 @style/Snackbar @style/SnackbarButton diff --git a/app/src/main/res/xml/about_settings.xml b/app/src/main/res/xml/about_settings.xml deleted file mode 100644 index 4b0c52527..000000000 --- a/app/src/main/res/xml/about_settings.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/xml/advanced_settings.xml b/app/src/main/res/xml/advanced_settings.xml deleted file mode 100644 index 79f6575fb..000000000 --- a/app/src/main/res/xml/advanced_settings.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/xml/download_settings.xml b/app/src/main/res/xml/download_settings.xml deleted file mode 100644 index 072a92bd8..000000000 --- a/app/src/main/res/xml/download_settings.xml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/xml/eh_settings.xml b/app/src/main/res/xml/eh_settings.xml deleted file mode 100644 index 4c302c2eb..000000000 --- a/app/src/main/res/xml/eh_settings.xml +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/xml/privacy_settings.xml b/app/src/main/res/xml/privacy_settings.xml deleted file mode 100644 index a0bd1d812..000000000 --- a/app/src/main/res/xml/privacy_settings.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - diff --git a/app/src/main/res/xml/settings_headers.xml b/app/src/main/res/xml/settings_headers.xml deleted file mode 100644 index f8dae4a20..000000000 --- a/app/src/main/res/xml/settings_headers.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - -