From 50abb9b55299bc58b75a5c09b1391e4a94223c91 Mon Sep 17 00:00:00 2001 From: HapeLee <1321903405@qq.com> Date: Wed, 27 Aug 2025 03:03:18 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=95=8C=E9=9D=A2=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E9=A6=96=E6=AC=A1=E8=BF=9B=E5=85=A5=E5=BC=95?= =?UTF-8?q?=E5=AF=BC=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/AndroidManifest.xml | 4 +- app/src/main/assets/disclaimer.md | 2 - .../io/legato/kazusa/constant/PreferKey.kt | 2 +- .../io/legato/kazusa/help/config/AppConfig.kt | 6 + .../kazusa/lib/prefs/ThemeCardPreference.kt | 2 +- .../kazusa/lib/prefs/ThemeModePreference.kt | 27 ++- .../ui/book/read/config/BgTextConfigDialog.kt | 26 +-- .../ui/book/read/config/ReadStyleDialog.kt | 6 +- .../kazusa/ui/config/ThemeConfigFragment.kt | 9 +- .../io/legato/kazusa/ui/main/MainActivity.kt | 56 +---- .../kazusa/ui/welcome/PrivacyFragment.kt | 23 ++ .../legato/kazusa/ui/welcome/ThemeFragment.kt | 27 +++ .../kazusa/ui/welcome/WebDavFragment.kt | 204 ++++++++++++++++++ .../kazusa/ui/welcome/WelcomeActivity.kt | 141 ++++++------ .../res/color/chip_background_selector.xml | 5 + .../main/res/color/chip_stroke_selector.xml | 5 + .../main/res/layout/activity_book_search.xml | 2 + app/src/main/res/layout/activity_welcome.xml | 114 +++++----- .../main/res/layout/dialog_read_bg_text.xml | 114 +++++----- .../res/layout/dialog_read_book_style.xml | 18 +- app/src/main/res/layout/fragment_privacy.xml | 45 ++++ .../main/res/layout/fragment_webdav_auth.xml | 97 +++++++++ app/src/main/res/layout/item_bg_image.xml | 1 + app/src/main/res/layout/item_download.xml | 2 + app/src/main/res/layout/item_read_style.xml | 3 + app/src/main/res/layout/view_pref.xml | 1 + app/src/main/res/layout/view_theme_mode.xml | 10 +- app/src/main/res/values-night/themes.xml | 1 + app/src/main/res/values/dimens.xml | 2 +- app/src/main/res/values/styles.xml | 5 + app/src/main/res/values/themes.xml | 1 + app/src/main/res/xml/pref_strat_theme.xml | 14 ++ gradle/libs.versions.toml | 16 +- 33 files changed, 684 insertions(+), 307 deletions(-) create mode 100644 app/src/main/java/io/legato/kazusa/ui/welcome/PrivacyFragment.kt create mode 100644 app/src/main/java/io/legato/kazusa/ui/welcome/ThemeFragment.kt create mode 100644 app/src/main/java/io/legato/kazusa/ui/welcome/WebDavFragment.kt create mode 100644 app/src/main/res/color/chip_background_selector.xml create mode 100644 app/src/main/res/color/chip_stroke_selector.xml create mode 100644 app/src/main/res/layout/fragment_privacy.xml create mode 100644 app/src/main/res/layout/fragment_webdav_auth.xml create mode 100644 app/src/main/res/xml/pref_strat_theme.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 16643b883..0071c1b67 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -133,10 +133,12 @@ + diff --git a/app/src/main/assets/disclaimer.md b/app/src/main/assets/disclaimer.md index 5511655f5..f6870b2c3 100644 --- a/app/src/main/assets/disclaimer.md +++ b/app/src/main/assets/disclaimer.md @@ -1,5 +1,3 @@ -# 免责声明(Disclaimer) - * 阅读是一款解析指定规则并获取内容的工具,为广大网络文学爱好者提供一种方便、快捷舒适的试读体验。 * 当您搜索一本书的时,阅读会您所使用的规则将该书的书名以关键词的形式提交到各个第三方网络文学网站。 各第三方网站返回的内容与阅读无关,阅读对其概不负责,亦不承担任何法律责任。 diff --git a/app/src/main/java/io/legato/kazusa/constant/PreferKey.kt b/app/src/main/java/io/legato/kazusa/constant/PreferKey.kt index 52fbbf037..df20ed725 100644 --- a/app/src/main/java/io/legato/kazusa/constant/PreferKey.kt +++ b/app/src/main/java/io/legato/kazusa/constant/PreferKey.kt @@ -204,7 +204,7 @@ object PreferKey { const val mangaClickActionBL = "mangaClickActionBottomLeft" const val mangaClickActionBC = "mangaClickActionBottomCenter" const val mangaClickActionBR = "mangaClickActionBottomRight" - + const val isFirstLaunch = "isFirstLaunch" const val permissionChecked = "permissionChecked" const val notificationsPost = "notificationsPost" const val ignoreBatteryPermission = "ignoreBatteryPermission" diff --git a/app/src/main/java/io/legato/kazusa/help/config/AppConfig.kt b/app/src/main/java/io/legato/kazusa/help/config/AppConfig.kt index e9baa00f5..dcd67400c 100644 --- a/app/src/main/java/io/legato/kazusa/help/config/AppConfig.kt +++ b/app/src/main/java/io/legato/kazusa/help/config/AppConfig.kt @@ -149,6 +149,12 @@ object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener { } } + var isFirstLaunch: Boolean + get() = appCtx.getPrefBoolean(PreferKey.isFirstLaunch, true) + set(value) { + appCtx.putPrefBoolean(PreferKey.isFirstLaunch, value) + } + var showUnread: Boolean get() = appCtx.getPrefBoolean(PreferKey.showUnread, true) set(value) { diff --git a/app/src/main/java/io/legato/kazusa/lib/prefs/ThemeCardPreference.kt b/app/src/main/java/io/legato/kazusa/lib/prefs/ThemeCardPreference.kt index 8cdd4798c..849cf6527 100644 --- a/app/src/main/java/io/legato/kazusa/lib/prefs/ThemeCardPreference.kt +++ b/app/src/main/java/io/legato/kazusa/lib/prefs/ThemeCardPreference.kt @@ -24,7 +24,7 @@ class ThemeCardPreference(context: Context, attrs: AttributeSet) : Preference(co private var entries: Array = context.resources.getTextArray(R.array.themes_item) private var entryValues: Array = context.resources.getTextArray(R.array.themes_value).takeIf { it.isNotEmpty() } ?: arrayOf("0") - private var currentValue: String? = null + private var currentValue = "0" init { layoutResource = R.layout.preference_theme_card diff --git a/app/src/main/java/io/legato/kazusa/lib/prefs/ThemeModePreference.kt b/app/src/main/java/io/legato/kazusa/lib/prefs/ThemeModePreference.kt index 680cd5c81..96892f295 100644 --- a/app/src/main/java/io/legato/kazusa/lib/prefs/ThemeModePreference.kt +++ b/app/src/main/java/io/legato/kazusa/lib/prefs/ThemeModePreference.kt @@ -2,9 +2,6 @@ package io.legato.kazusa.lib.prefs import android.content.Context import android.util.AttributeSet -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup import androidx.preference.PreferenceViewHolder import com.google.android.material.button.MaterialButtonToggleGroup import io.legato.kazusa.R @@ -13,7 +10,7 @@ import io.legato.kazusa.help.config.ThemeConfig class ThemeModePreference(context: Context, attrs: AttributeSet) : Preference(context, attrs) { - private var currentValue: String? = null + private var currentValue: String = "0" init { layoutResource = R.layout.view_pref @@ -23,17 +20,21 @@ class ThemeModePreference(context: Context, attrs: AttributeSet) : Preference(co override fun onBindViewHolder(holder: PreferenceViewHolder) { super.onBindViewHolder(holder) - val toggleGroup = holder.itemView.findViewById(R.id.theme_toggle_group) - if (toggleGroup == null) { - val rootView = holder.itemView as ViewGroup - val inflater = LayoutInflater.from(context) - val themeToggleView = inflater.inflate(R.layout.view_theme_mode, rootView, false) - rootView.addView(themeToggleView) + val toggleGroup = + holder.itemView.findViewById(R.id.theme_toggle_group) + ?: return - setupToggleGroup(themeToggleView.findViewById(R.id.theme_toggle_group)) + // 根据 currentValue 设置选中 + when (currentValue) { + "0" -> toggleGroup.check(R.id.btn_system) + "1" -> toggleGroup.check(R.id.btn_light) + "2" -> toggleGroup.check(R.id.btn_dark) } + + setupToggleGroup(toggleGroup) } + private fun setupToggleGroup(toggleGroup: MaterialButtonToggleGroup) { when (currentValue) { @@ -65,8 +66,4 @@ class ThemeModePreference(context: Context, attrs: AttributeSet) : Preference(co currentValue = getPersistedString(defaultValue as? String ?: "0") } - override fun shouldDisableDependents(): Boolean { - return currentValue == null || super.shouldDisableDependents() - } - } \ No newline at end of file diff --git a/app/src/main/java/io/legato/kazusa/ui/book/read/config/BgTextConfigDialog.kt b/app/src/main/java/io/legato/kazusa/ui/book/read/config/BgTextConfigDialog.kt index 15d6bcab8..607b652a2 100644 --- a/app/src/main/java/io/legato/kazusa/ui/book/read/config/BgTextConfigDialog.kt +++ b/app/src/main/java/io/legato/kazusa/ui/book/read/config/BgTextConfigDialog.kt @@ -1,22 +1,21 @@ package io.legato.kazusa.ui.book.read.config +//import io.legado.app.lib.theme.bottomBackground +//import io.legado.app.lib.theme.getPrimaryTextColor +//import io.legado.app.lib.theme.getSecondaryTextColor import android.annotation.SuppressLint import android.content.DialogInterface import android.graphics.Color import android.graphics.PorterDuff import android.net.Uri import android.os.Bundle -import android.view.Gravity import android.view.View -import android.view.ViewGroup -import android.view.WindowManager import androidx.appcompat.widget.TooltipCompat import androidx.documentfile.provider.DocumentFile import com.google.android.material.slider.Slider import com.jaredrummler.android.colorpicker.ColorPickerDialog import io.legato.kazusa.R import io.legato.kazusa.base.BaseBottomSheetDialogFragment -import io.legato.kazusa.base.BaseDialogFragment import io.legato.kazusa.constant.AppLog import io.legato.kazusa.constant.EventBus import io.legato.kazusa.databinding.DialogEditTextBinding @@ -29,9 +28,6 @@ import io.legato.kazusa.help.http.okHttpClient import io.legato.kazusa.lib.dialogs.SelectItem import io.legato.kazusa.lib.dialogs.alert import io.legato.kazusa.lib.dialogs.selector -//import io.legado.app.lib.theme.bottomBackground -//import io.legado.app.lib.theme.getPrimaryTextColor -//import io.legado.app.lib.theme.getSecondaryTextColor import io.legato.kazusa.ui.book.read.ReadBookActivity import io.legato.kazusa.ui.file.HandleFileContract import io.legato.kazusa.utils.FileUtils @@ -116,22 +112,6 @@ class BgTextConfigDialog : BaseBottomSheetDialogFragment(R.layout.dialog_read_bg } private fun initView() = binding.run { -// val bg = requireContext().bottomBackground -// val isLight = ColorUtils.isColorLight(bg) -// primaryTextColor = requireContext().getPrimaryTextColor(isLight) -// secondaryTextColor = requireContext().getSecondaryTextColor(isLight) -// rootView.setBackgroundColor(bg) -// tvNameTitle.setTextColor(primaryTextColor) -// tvName.setTextColor(secondaryTextColor) -// ivEdit.setColorFilter(secondaryTextColor, PorterDuff.Mode.SRC_IN) -// tvRestore.setTextColor(primaryTextColor) -// swDarkStatusIcon.setTextColor(primaryTextColor) -// swUnderline.setTextColor(primaryTextColor) -// ivImport.setColorFilter(primaryTextColor, PorterDuff.Mode.SRC_IN) -// ivExport.setColorFilter(primaryTextColor, PorterDuff.Mode.SRC_IN) -// ivDelete.setColorFilter(primaryTextColor, PorterDuff.Mode.SRC_IN) -// tvBgAlpha.setTextColor(primaryTextColor) -// tvBgImage.setTextColor(primaryTextColor) recyclerView.adapter = adapter adapter.addHeaderView { ItemBgImageBinding.inflate(layoutInflater, it, false).apply { diff --git a/app/src/main/java/io/legato/kazusa/ui/book/read/config/ReadStyleDialog.kt b/app/src/main/java/io/legato/kazusa/ui/book/read/config/ReadStyleDialog.kt index e5f563cb7..d5642ec77 100644 --- a/app/src/main/java/io/legato/kazusa/ui/book/read/config/ReadStyleDialog.kt +++ b/app/src/main/java/io/legato/kazusa/ui/book/read/config/ReadStyleDialog.kt @@ -230,14 +230,14 @@ class ReadStyleDialog : BaseBottomSheetDialogFragment(R.layout.dialog_read_book_ llStyle.gravity = Gravity.TOP cdStyle.cardElevation = 1f.dpToPx() cdStyle.radius = 16f.dpToPx() - cdStyle.strokeWidth = 2 - cdStyle.strokeColor = item.curTextColor() + cdStyle.strokeWidth = 1.dpToPx() + //cdStyle.strokeColor = item.curTextColor() //tvStyle.setTextBold(true) } else { cdStyle.cardElevation = 2f.dpToPx() cdStyle.radius = 32f.dpToPx() cdStyle.strokeWidth = 0 - cdStyle.strokeColor = item.curTextColor() + //cdStyle.strokeColor = item.curTextColor() //tvStyle.setTextBold(false) } } diff --git a/app/src/main/java/io/legato/kazusa/ui/config/ThemeConfigFragment.kt b/app/src/main/java/io/legato/kazusa/ui/config/ThemeConfigFragment.kt index 1c9d34614..2e032b238 100644 --- a/app/src/main/java/io/legato/kazusa/ui/config/ThemeConfigFragment.kt +++ b/app/src/main/java/io/legato/kazusa/ui/config/ThemeConfigFragment.kt @@ -1,14 +1,12 @@ package io.legato.kazusa.ui.config +//import io.legado.app.lib.theme.primaryColor import android.annotation.SuppressLint -import android.content.Intent import android.content.SharedPreferences import android.net.Uri -import android.os.Build import android.os.Bundle import android.view.View import android.widget.SeekBar -import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat import io.legato.kazusa.R @@ -23,10 +21,8 @@ import io.legato.kazusa.help.config.ThemeConfig import io.legato.kazusa.lib.dialogs.alert import io.legato.kazusa.lib.dialogs.selector import io.legato.kazusa.lib.prefs.ColorPreference -import io.legato.kazusa.lib.prefs.NameListPreference import io.legato.kazusa.lib.prefs.ThemeCardPreference import io.legato.kazusa.lib.prefs.ThemeModePreference -//import io.legado.app.lib.theme.primaryColor import io.legato.kazusa.ui.widget.number.NumberPickerDialog import io.legato.kazusa.ui.widget.seekbar.SeekBarChangeListener import io.legato.kazusa.utils.ColorUtils @@ -72,9 +68,6 @@ class ThemeConfigFragment : PreferenceFragmentCompat(), override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.pref_config_theme) - if (Build.VERSION.SDK_INT < 26) { - preferenceScreen.removePreferenceRecursively(PreferKey.launcherIcon) - } upPreferenceSummary(PreferKey.bgImage, getPrefString(PreferKey.bgImage)) upPreferenceSummary(PreferKey.bgImageN, getPrefString(PreferKey.bgImageN)) diff --git a/app/src/main/java/io/legato/kazusa/ui/main/MainActivity.kt b/app/src/main/java/io/legato/kazusa/ui/main/MainActivity.kt index 7f53d4b3c..cde53ffb1 100644 --- a/app/src/main/java/io/legato/kazusa/ui/main/MainActivity.kt +++ b/app/src/main/java/io/legato/kazusa/ui/main/MainActivity.kt @@ -26,7 +26,6 @@ import io.legato.kazusa.constant.AppConst.appInfo import io.legato.kazusa.constant.EventBus import io.legato.kazusa.constant.PreferKey import io.legato.kazusa.databinding.ActivityMainBinding -import io.legato.kazusa.databinding.DialogEditTextBinding import io.legato.kazusa.help.AppWebDav import io.legato.kazusa.help.book.BookHelp import io.legato.kazusa.help.config.AppConfig @@ -43,6 +42,7 @@ import io.legato.kazusa.ui.main.bookshelf.books.BookshelfFragment3 import io.legato.kazusa.ui.main.explore.ExploreFragment import io.legato.kazusa.ui.main.my.MyFragment import io.legato.kazusa.ui.main.rss.RssFragment +import io.legato.kazusa.ui.welcome.WelcomeActivity import io.legato.kazusa.ui.widget.dialog.TextDialog import io.legato.kazusa.utils.gone import io.legato.kazusa.utils.hideSoftInput @@ -51,6 +51,7 @@ import io.legato.kazusa.utils.observeEvent import io.legato.kazusa.utils.setNavigationBarColorAuto import io.legato.kazusa.utils.shouldHideSoftInput import io.legato.kazusa.utils.showDialogFragment +import io.legato.kazusa.utils.startActivity import io.legato.kazusa.utils.themeColor import io.legato.kazusa.utils.toastOnUi import io.legato.kazusa.utils.viewbindingdelegate.viewBinding @@ -100,6 +101,12 @@ class MainActivity : VMBaseActivity(), override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + if (AppConfig.isFirstLaunch) { + startActivity() + finish() + return + } + onBackPressedDispatcher.addCallback(this) { if (pagePosition != 0) { binding.viewPagerMain.currentItem = 0 @@ -145,12 +152,9 @@ class MainActivity : VMBaseActivity(), override fun onPostCreate(savedInstanceState: Bundle?) { super.onPostCreate(savedInstanceState) lifecycleScope.launch { - //隐私协议 - if (!privacyPolicy()) return@launch //版本更新 upVersion() //设置本地密码 - setLocalPassword() notifyAppCrash() //备份同步 backupSync() @@ -217,27 +221,6 @@ class MainActivity : VMBaseActivity(), window.setNavigationBarColorAuto(themeColor(com.google.android.material.R.attr.colorSurfaceContainer)) } - /** - * 用户隐私与协议 - */ - private suspend fun privacyPolicy(): Boolean = suspendCoroutine { block -> - if (LocalConfig.privacyPolicyOk) { - block.resume(true) - return@suspendCoroutine - } - val privacyPolicy = String(assets.open("privacyPolicy.md").readBytes()) - alert(getString(R.string.privacy_policy), privacyPolicy) { - positiveButton(R.string.agree) { - LocalConfig.privacyPolicyOk = true - block.resume(true) - } - negativeButton(R.string.refuse) { - finish() - block.resume(false) - } - } - } - /** * 版本更新日志 */ @@ -269,29 +252,6 @@ class MainActivity : VMBaseActivity(), /** * 设置本地密码 */ - private suspend fun setLocalPassword() = suspendCoroutine { block -> - if (LocalConfig.password != null) { - block.resume(null) - return@suspendCoroutine - } - alert(R.string.set_local_password, R.string.set_local_password_summary) { - val editTextBinding = DialogEditTextBinding.inflate(layoutInflater).apply { - editView.hint = "password" - } - customView { - editTextBinding.root - } - onDismiss { - block.resume(null) - } - okButton { - LocalConfig.password = editTextBinding.editView.text.toString() - } - cancelButton { - LocalConfig.password = "" - } - } - } private fun notifyAppCrash() { if (!LocalConfig.appCrash || BuildConfig.DEBUG) { diff --git a/app/src/main/java/io/legato/kazusa/ui/welcome/PrivacyFragment.kt b/app/src/main/java/io/legato/kazusa/ui/welcome/PrivacyFragment.kt new file mode 100644 index 000000000..1bcbd08e2 --- /dev/null +++ b/app/src/main/java/io/legato/kazusa/ui/welcome/PrivacyFragment.kt @@ -0,0 +1,23 @@ +package io.legato.kazusa.ui.welcome + +import android.os.Bundle +import android.view.View +import io.legato.kazusa.R +import io.legato.kazusa.base.BaseFragment +import io.legato.kazusa.databinding.FragmentPrivacyBinding +import io.legato.kazusa.utils.viewbindingdelegate.viewBinding + +class PrivacyFragment : BaseFragment(R.layout.fragment_privacy) { + + private val binding by viewBinding(FragmentPrivacyBinding::bind) + + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { + + binding.tvPrivacy.text = + String(requireContext().assets.open("privacyPolicy.md").readBytes()) + binding.tvDisclaimer.text = + String(requireContext().assets.open("disclaimer.md").readBytes()) + + } + +} diff --git a/app/src/main/java/io/legato/kazusa/ui/welcome/ThemeFragment.kt b/app/src/main/java/io/legato/kazusa/ui/welcome/ThemeFragment.kt new file mode 100644 index 000000000..432ce689d --- /dev/null +++ b/app/src/main/java/io/legato/kazusa/ui/welcome/ThemeFragment.kt @@ -0,0 +1,27 @@ +package io.legato.kazusa.ui.welcome + +import android.os.Bundle +import androidx.preference.PreferenceFragmentCompat +import io.legato.kazusa.R +import io.legato.kazusa.constant.PreferKey +import io.legato.kazusa.lib.prefs.ThemeCardPreference +import io.legato.kazusa.lib.prefs.ThemeModePreference + +class ThemeFragment : PreferenceFragmentCompat() { + + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + setPreferencesFromResource(R.xml.pref_strat_theme, rootKey) + + findPreference(PreferKey.themeMode)?.let { + it.setOnPreferenceChangeListener { _, _ -> + true + } + } + + findPreference(PreferKey.themePref)?.let { + it.setOnPreferenceChangeListener { _, _ -> + true + } + } + } +} diff --git a/app/src/main/java/io/legato/kazusa/ui/welcome/WebDavFragment.kt b/app/src/main/java/io/legato/kazusa/ui/welcome/WebDavFragment.kt new file mode 100644 index 000000000..1d0b363d4 --- /dev/null +++ b/app/src/main/java/io/legato/kazusa/ui/welcome/WebDavFragment.kt @@ -0,0 +1,204 @@ +package io.legato.kazusa.ui.welcome + +import android.content.Context +import android.os.Bundle +import android.text.InputType +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ArrayAdapter +import androidx.core.content.edit +import androidx.core.widget.doAfterTextChanged +import androidx.lifecycle.lifecycleScope +import androidx.preference.PreferenceManager +import io.legato.kazusa.R +import io.legato.kazusa.base.BaseFragment +import io.legato.kazusa.constant.AppLog +import io.legato.kazusa.constant.PreferKey +import io.legato.kazusa.databinding.FragmentWebdavAuthBinding +import io.legato.kazusa.exception.NoStackTraceException +import io.legato.kazusa.help.AppWebDav +import io.legato.kazusa.help.AppWebDav.testWebDav +import io.legato.kazusa.help.config.LocalConfig +import io.legato.kazusa.help.coroutine.Coroutine +import io.legato.kazusa.help.storage.Restore +import io.legato.kazusa.lib.dialogs.alert +import io.legato.kazusa.lib.dialogs.selector +import io.legato.kazusa.ui.file.HandleFileContract +import io.legato.kazusa.ui.widget.dialog.WaitDialog +import io.legato.kazusa.utils.toastOnUi +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.Dispatchers.Main +import kotlinx.coroutines.Job +import kotlinx.coroutines.ensureActive +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import splitties.init.appCtx +import kotlin.coroutines.coroutineContext + +class WebDavFragment : BaseFragment(R.layout.fragment_webdav_auth) { + + private var _binding: FragmentWebdavAuthBinding? = null + private val binding get() = _binding!! + private var restoreJob: Job? = null + private val waitDialog by lazy { WaitDialog(requireContext()) } + + private val restoreDoc = registerForActivityResult(HandleFileContract()) { + it.uri?.let { uri -> + waitDialog.setText("恢复中…") + waitDialog.show() + val task = Coroutine.async { + Restore.restore(appCtx, uri) + }.onFinally { + waitDialog.dismiss() + } + waitDialog.setOnCancelListener { + task.cancel() + } + } + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + _binding = FragmentWebdavAuthBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onFragmentCreated(view: View, savedInstanceState: Bundle?) { + + val prefs = PreferenceManager.getDefaultSharedPreferences(requireContext()) + + val urls = listOf( + "https://dav.jianguoyun.com/dav/", + "https://webdav.aliyundrive.com/", + "https://dav.example.com/" + ) + + val adapter = ArrayAdapter( + requireContext(), + android.R.layout.simple_dropdown_item_1line, + urls + ) + + binding.editUrl.setAdapter(adapter) + + binding.editAccount.setText(prefs.getString(PreferKey.webDavAccount, "")) + binding.editPassword.setText(prefs.getString(PreferKey.webDavPassword, "")) + binding.editPassword.inputType = + InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD + + binding.etPassword.setText(LocalConfig.password ?: "") + + binding.etPassword.doAfterTextChanged { + LocalConfig.password = it.toString() + } + + binding.btnCheck.setOnClickListener { + saveWebDavConfig() + + lifecycleScope.launch { + testWebDav() + } + } + + binding.btnRestore.setOnClickListener { + restore() + } + + } + + fun saveWebDavConfig(onSaved: (() -> Unit)? = null) { + val url = binding.editUrl.text.toString() + val account = binding.editAccount.text.toString() + val password = binding.editPassword.text.toString() + + PreferenceManager.getDefaultSharedPreferences(requireContext()).edit { + putString(PreferKey.webDavUrl, url) + putString(PreferKey.webDavAccount, account) + putString(PreferKey.webDavPassword, password) + } + + onSaved?.invoke() + } + + fun restore() { + waitDialog.setText(R.string.loading) + waitDialog.setOnCancelListener { + restoreJob?.cancel() + } + waitDialog.show() + Coroutine.async { + restoreJob = coroutineContext[Job] + showRestoreDialog(requireContext()) + }.onError { + AppLog.put("恢复备份出错WebDavError\n${it.localizedMessage}", it) + if (context == null) { + return@onError + } + alert { + setTitle(R.string.restore) + setMessage("WebDavError\n${it.localizedMessage}\n将从本地备份恢复。") + okButton { + restoreFromLocal() + } + cancelButton() + } + }.onFinally { + waitDialog.dismiss() + } + } + + private suspend fun showRestoreDialog(context: Context) { + val names = withContext(IO) { AppWebDav.getBackupNames() } + if (AppWebDav.isJianGuoYun && names.size > 700) { + context.toastOnUi("由于坚果云限制列出文件数量,部分备份可能未显示,请及时清理旧备份") + } + if (names.isNotEmpty()) { + coroutineContext.ensureActive() + withContext(Main) { + context.selector( + title = context.getString(R.string.select_restore_file), + items = names + ) { _, index -> + if (index in names.indices) { + restoreWebDav(names[index]) + } + } + } + } else { + throw NoStackTraceException("Web dav no back up file") + } + } + + private fun restoreWebDav(name: String) { + waitDialog.setText("恢复中…") + waitDialog.show() + val task = Coroutine.async { + AppWebDav.restoreWebDav(name) + }.onError { + AppLog.put("WebDav恢复出错\n${it.localizedMessage}", it) + appCtx.toastOnUi("WebDav恢复出错\n${it.localizedMessage}") + }.onFinally { + waitDialog.dismiss() + } + waitDialog.setOnCancelListener { + task.cancel() + } + } + + private fun restoreFromLocal() { + restoreDoc.launch { + title = getString(R.string.select_restore_file) + mode = HandleFileContract.FILE + allowExtensions = arrayOf("zip") + } + } + + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} diff --git a/app/src/main/java/io/legato/kazusa/ui/welcome/WelcomeActivity.kt b/app/src/main/java/io/legato/kazusa/ui/welcome/WelcomeActivity.kt index 5227b349d..780c8fb8f 100644 --- a/app/src/main/java/io/legato/kazusa/ui/welcome/WelcomeActivity.kt +++ b/app/src/main/java/io/legato/kazusa/ui/welcome/WelcomeActivity.kt @@ -1,86 +1,101 @@ package io.legato.kazusa.ui.welcome -import android.content.Intent -import android.graphics.drawable.BitmapDrawable + import android.os.Bundle -import androidx.core.view.postDelayed +import androidx.activity.addCallback +import androidx.viewpager2.adapter.FragmentStateAdapter +import androidx.viewpager2.widget.ViewPager2 import io.legato.kazusa.base.BaseActivity -import io.legato.kazusa.constant.PreferKey -import io.legato.kazusa.constant.Theme import io.legato.kazusa.databinding.ActivityWelcomeBinding -import io.legato.kazusa.help.config.ThemeConfig -//import io.legado.app.lib.theme.accentColor -//import io.legado.app.lib.theme.backgroundColor -import io.legato.kazusa.ui.book.read.ReadBookActivity +import io.legato.kazusa.help.config.AppConfig +import io.legato.kazusa.help.config.LocalConfig import io.legato.kazusa.ui.main.MainActivity -import io.legato.kazusa.utils.* +import io.legato.kazusa.utils.startActivity import io.legato.kazusa.utils.viewbindingdelegate.viewBinding -open class WelcomeActivity : BaseActivity() { +class WelcomeActivity : BaseActivity() { override val binding by viewBinding(ActivityWelcomeBinding::inflate) + private val pages = listOf( + PrivacyFragment(), + WebDavFragment(), + ThemeFragment() + ) + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) -// binding.ivBook.setColorFilter(accentColor) -// binding.vwTitleLine.setBackgroundColor(accentColor) - // 避免从桌面启动程序后,会重新实例化入口类的activity - if (intent.flags and Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT != 0) { - finish() - } else { - binding.root.postDelayed(100) { startMainActivity() } - } - } -// override fun setupSystemBar() { -// fullScreen() -// //setStatusBarColorAuto(backgroundColor, true, fullScreen) -// upNavigationBarColor() -// } - - override fun upBackgroundImage() { - if (getPrefBoolean(PreferKey.customWelcome)) { - kotlin.runCatching { - when (ThemeConfig.getTheme()) { - Theme.Dark -> getPrefString(PreferKey.welcomeImageDark)?.let { path -> - val size = windowManager.windowSize - BitmapUtils.decodeBitmap(path, size.widthPixels, size.heightPixels).let { - binding.tvLegado.visible(getPrefBoolean(PreferKey.welcomeShowTextDark)) - binding.ivBook.visible(getPrefBoolean(PreferKey.welcomeShowIconDark)) - binding.tvGzh.visible(getPrefBoolean(PreferKey.welcomeShowTextDark)) - window.decorView.background = BitmapDrawable(resources, it) - return - } - } - else -> getPrefString(PreferKey.welcomeImage)?.let { path -> - val size = windowManager.windowSize - BitmapUtils.decodeBitmap(path, size.widthPixels, size.heightPixels).let { - binding.tvLegado.visible(getPrefBoolean(PreferKey.welcomeShowText)) - binding.ivBook.visible(getPrefBoolean(PreferKey.welcomeShowIcon)) - binding.tvGzh.visible(getPrefBoolean(PreferKey.welcomeShowText)) - window.decorView.background = BitmapDrawable(resources, it) - return - } - } + onBackPressedDispatcher.addCallback(this) { + val current = binding.viewPager.currentItem + if (current > 0) { + binding.viewPager.currentItem = current - 1 + } else { + finish() + } + } + + updateProgress(0) + + binding.viewPager.adapter = object : FragmentStateAdapter(this) { + override fun getItemCount() = pages.size + override fun createFragment(position: Int) = pages[position] + } + + binding.viewPager.isUserInputEnabled = false + + binding.viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { + override fun onPageSelected(position: Int) { + super.onPageSelected(position) + binding.btnNext.text = when (position) { + 0 -> "阅读并同意" // PrivacyFragment + pages.lastIndex -> "完成" + else -> "下一步" + } + binding.tvTitle.text = when (position) { + 0 -> "欢迎!" // PrivacyFragment + 1 -> "备份与恢复" + else -> "主题样式" + } + binding.tvSummary.text = when (position) { + 0 -> "请先阅读应用的服务条款与用户协议。" + 1 -> "此处可设置云同步与恢复应用备份。" + else -> "在这里设置您喜爱的样式。" } + updateProgress(position) + } + }) + + // 初始化按钮文字 + binding.btnNext.text = "阅读并同意" + + binding.btnNext.setOnClickListener { + val current = binding.viewPager.currentItem + when (current) { + 0 -> { + LocalConfig.privacyPolicyOk = true + binding.viewPager.currentItem = 1 + } + + pages.lastIndex -> { + updateProgress(2) + finishSetup() + } + + else -> binding.viewPager.currentItem = current + 1 } } - super.upBackgroundImage() } - private fun startMainActivity() { + private fun updateProgress(position: Int) { + val progressMax = pages.size + val progress = (position * 100 / progressMax) + binding.progressBar.setProgress(progress, true) + } + + private fun finishSetup() { + AppConfig.isFirstLaunch = false startActivity() - if (getPrefBoolean(PreferKey.defaultToRead)) { - startActivity() - } finish() } - } - -class Launcher1 : WelcomeActivity() -class Launcher2 : WelcomeActivity() -class Launcher3 : WelcomeActivity() -class Launcher4 : WelcomeActivity() -class Launcher5 : WelcomeActivity() -class Launcher6 : WelcomeActivity() \ No newline at end of file diff --git a/app/src/main/res/color/chip_background_selector.xml b/app/src/main/res/color/chip_background_selector.xml new file mode 100644 index 000000000..c3ad46f6c --- /dev/null +++ b/app/src/main/res/color/chip_background_selector.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/res/color/chip_stroke_selector.xml b/app/src/main/res/color/chip_stroke_selector.xml new file mode 100644 index 000000000..73f16062d --- /dev/null +++ b/app/src/main/res/color/chip_stroke_selector.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_book_search.xml b/app/src/main/res/layout/activity_book_search.xml index c930a94da..c123f5f09 100644 --- a/app/src/main/res/layout/activity_book_search.xml +++ b/app/src/main/res/layout/activity_book_search.xml @@ -33,6 +33,8 @@ android:id="@+id/refresh_progress_bar" android:layout_width="match_parent" android:layout_height="wrap_content" + app:waveAmplitude="8dp" + app:wavelength="80dp" android:indeterminate="true" android:visibility="gone"> diff --git a/app/src/main/res/layout/activity_welcome.xml b/app/src/main/res/layout/activity_welcome.xml index b437c516a..e0352757d 100644 --- a/app/src/main/res/layout/activity_welcome.xml +++ b/app/src/main/res/layout/activity_welcome.xml @@ -1,82 +1,76 @@ + android:animateLayoutChanges="true" + android:fitsSystemWindows="true"> - + android:orientation="vertical" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> - + - + android:layout_marginHorizontal="16dp" + android:text="欢迎!" + android:textSize="36sp" + android:textStyle="bold" /> - + android:layout_marginHorizontal="16dp" + android:layout_marginTop="8dp" + android:layout_marginBottom="16dp" + android:text="请先阅读应用的服务条款与用户协议。" + android:textStyle="bold" /> + + - + - - - + app:layout_constraintEnd_toEndOf="parent" /> - \ No newline at end of file + diff --git a/app/src/main/res/layout/dialog_read_bg_text.xml b/app/src/main/res/layout/dialog_read_bg_text.xml index 1120c642e..0852dd774 100644 --- a/app/src/main/res/layout/dialog_read_bg_text.xml +++ b/app/src/main/res/layout/dialog_read_bg_text.xml @@ -50,66 +50,70 @@ app:layout_constraintTop_toBottomOf="@id/tv_name_title" tools:text="文字" /> - - - + app:layout_constraintTop_toTopOf="@id/tv_name"> - + - + + + + + - - + app:layout_constraintTop_toBottomOf="@id/mbg_1"> + + + + + + + + + @@ -129,7 +133,7 @@ android:text="@string/text_underline" tools:ignore="TouchTargetSizeCheck" /> - - + diff --git a/app/src/main/res/layout/dialog_read_book_style.xml b/app/src/main/res/layout/dialog_read_book_style.xml index 1b8a8226f..9aa1e69a1 100644 --- a/app/src/main/res/layout/dialog_read_book_style.xml +++ b/app/src/main/res/layout/dialog_read_book_style.xml @@ -272,45 +272,37 @@ - - - - diff --git a/app/src/main/res/layout/fragment_privacy.xml b/app/src/main/res/layout/fragment_privacy.xml new file mode 100644 index 000000000..b9bc6e778 --- /dev/null +++ b/app/src/main/res/layout/fragment_privacy.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_webdav_auth.xml b/app/src/main/res/layout/fragment_webdav_auth.xml new file mode 100644 index 000000000..da44664fd --- /dev/null +++ b/app/src/main/res/layout/fragment_webdav_auth.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_bg_image.xml b/app/src/main/res/layout/item_bg_image.xml index b22ed8cc2..f3b86a871 100644 --- a/app/src/main/res/layout/item_bg_image.xml +++ b/app/src/main/res/layout/item_bg_image.xml @@ -7,6 +7,7 @@ android:orientation="vertical"> diff --git a/app/src/main/res/layout/item_download.xml b/app/src/main/res/layout/item_download.xml index 7574e1c10..803f1eafd 100644 --- a/app/src/main/res/layout/item_download.xml +++ b/app/src/main/res/layout/item_download.xml @@ -104,6 +104,8 @@ style="@style/Widget.Material3.LinearProgressIndicator" android:layout_width="match_parent" android:layout_height="wrap_content" + app:waveAmplitude="8dp" + app:wavelength="80dp" android:layout_marginTop="2dp" android:visibility="gone" app:layout_constraintTop_toBottomOf="@id/iv_download" /> diff --git a/app/src/main/res/layout/item_read_style.xml b/app/src/main/res/layout/item_read_style.xml index 8cc6a8328..aa3902e57 100644 --- a/app/src/main/res/layout/item_read_style.xml +++ b/app/src/main/res/layout/item_read_style.xml @@ -1,5 +1,6 @@ diff --git a/app/src/main/res/layout/view_pref.xml b/app/src/main/res/layout/view_pref.xml index 22373aef8..0b299992d 100644 --- a/app/src/main/res/layout/view_pref.xml +++ b/app/src/main/res/layout/view_pref.xml @@ -1,6 +1,7 @@ diff --git a/app/src/main/res/layout/view_theme_mode.xml b/app/src/main/res/layout/view_theme_mode.xml index 28faa6e0b..aee5936bf 100644 --- a/app/src/main/res/layout/view_theme_mode.xml +++ b/app/src/main/res/layout/view_theme_mode.xml @@ -4,16 +4,16 @@ android:id="@+id/theme_toggle_group" android:layout_width="match_parent" android:layout_height="wrap_content" - android:orientation="horizontal" + android:spacing="2dp" + app:innerCornerSize="8dp" android:layout_marginHorizontal="16dp" android:layout_marginVertical="8dp" - android:gravity="center" app:singleSelection="true" app:selectionRequired="true"> true false @style/Widget.App.TabLayout + @style/Widget.MyApp.Chip.Assist @drawable/popup_background @style/AppTheme.AlertDialog diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 91c5c825d..8f0874873 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -25,7 +25,7 @@ 16dp 48dp - 16dp + 12dp 8dp 8dp diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index fc6b9c24e..ce8154e24 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -32,6 +32,11 @@ @layout/m3_alert_dialog + + diff --git a/app/src/main/res/xml/pref_strat_theme.xml b/app/src/main/res/xml/pref_strat_theme.xml new file mode 100644 index 000000000..0d0a8f07e --- /dev/null +++ b/app/src/main/res/xml/pref_strat_theme.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a54fb6629..da6916e28 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,17 +1,17 @@ [versions] datastorePreferences = "1.1.7" -kotlin = "2.1.21" +kotlin = "2.2.10" ksp = "2.1.21-2.0.1" -agp = "8.12.0" +agp = "8.12.1" appcompat = "1.7.1" colorpicker = "1.1.0" -commonsText = "1.13.1" +commonsText = "1.14.0" constraintlayout = "2.2.1" -core = "1.16.0" -firebaseBom = "34.0.0" +core = "1.17.0" +firebaseBom = "34.1.0" flexbox = "3.0.0" -fragment = "1.8.8" +fragment = "1.8.9" #不要更新版本 hutool = "5.8.22" @@ -28,7 +28,7 @@ jsoupxpath = "2.5.3" coroutines = "1.10.2" liveeventbus = "1.8.14" markwon = "4.6.2" -material = "1.14.0-alpha03" +material = "1.14.0-alpha04" media = "1.7.0" media3 = "1.7.1" nanoHttpd = "2.3.1" @@ -52,7 +52,7 @@ viewpager2 = "1.0.0" webkit = "1.14.0" collection = "1.5.0" -zxingLite = "3.2.0" +zxingLite = "3.3.0" [libraries]