更新界面
增加首次进入引导界面
This commit is contained in:
1 parent
ab98072ec3
commit
50abb9b552
33 files changed
+684
-307
No files matched your search
@@ -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())
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<ThemeModePreference>(PreferKey.themeMode)?.let {
|
||||
it.setOnPreferenceChangeListener { _, _ ->
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
findPreference<ThemeCardPreference>(PreferKey.themePref)?.let {
|
||||
it.setOnPreferenceChangeListener { _, _ ->
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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<ActivityWelcomeBinding>() {
|
||||
class WelcomeActivity : BaseActivity<ActivityWelcomeBinding>() {
|
||||
|
||||
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<MainActivity>()
|
||||
if (getPrefBoolean(PreferKey.defaultToRead)) {
|
||||
startActivity<ReadBookActivity>()
|
||||
}
|
||||
finish()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Launcher1 : WelcomeActivity()
|
||||
class Launcher2 : WelcomeActivity()
|
||||
class Launcher3 : WelcomeActivity()
|
||||
class Launcher4 : WelcomeActivity()
|
||||
class Launcher5 : WelcomeActivity()
|
||||
class Launcher6 : WelcomeActivity()
|
||||
Reference in new issue
Block a user