|
@@ -1,17 +1,30 @@
|
|
|
package com.grkj.iscs.features.main.fragment.data_manage
|
|
package com.grkj.iscs.features.main.fragment.data_manage
|
|
|
|
|
|
|
|
|
|
+import androidx.activity.result.ActivityResultCallback
|
|
|
import androidx.fragment.app.viewModels
|
|
import androidx.fragment.app.viewModels
|
|
|
import com.drake.brv.BindingAdapter
|
|
import com.drake.brv.BindingAdapter
|
|
|
import com.drake.brv.utils.linear
|
|
import com.drake.brv.utils.linear
|
|
|
import com.drake.brv.utils.models
|
|
import com.drake.brv.utils.models
|
|
|
import com.drake.brv.utils.setup
|
|
import com.drake.brv.utils.setup
|
|
|
|
|
+import com.grkj.data.data.EventConstants
|
|
|
import com.grkj.data.database.BackupScheduler
|
|
import com.grkj.data.database.BackupScheduler
|
|
|
|
|
+import com.grkj.data.database.ISCSDatabase
|
|
|
import com.grkj.data.database.RoomBackupManager
|
|
import com.grkj.data.database.RoomBackupManager
|
|
|
|
|
+import com.grkj.data.enums.BackupFrequencyWeekEnum
|
|
|
|
|
+import com.grkj.data.utils.event.BackupCompleteEvent
|
|
|
import com.grkj.iscs.R
|
|
import com.grkj.iscs.R
|
|
|
import com.grkj.iscs.databinding.FragmentBackupAndRestoreBinding
|
|
import com.grkj.iscs.databinding.FragmentBackupAndRestoreBinding
|
|
|
import com.grkj.iscs.databinding.ItemBackupBinding
|
|
import com.grkj.iscs.databinding.ItemBackupBinding
|
|
|
|
|
+import com.grkj.iscs.features.main.dialog.TextDropDownDialog
|
|
|
import com.grkj.iscs.features.main.viewmodel.data_manage.BackupAndRestoreViewModel
|
|
import com.grkj.iscs.features.main.viewmodel.data_manage.BackupAndRestoreViewModel
|
|
|
|
|
+import com.grkj.shared.model.EventBean
|
|
|
|
|
+import com.grkj.shared.utils.FilePickerUtils
|
|
|
|
|
+import com.grkj.shared.utils.SAFHelper.moveFileToDir
|
|
|
|
|
+import com.grkj.shared.utils.i18n.I18nManager
|
|
|
import com.grkj.ui_base.base.BaseFragment
|
|
import com.grkj.ui_base.base.BaseFragment
|
|
|
|
|
+import com.grkj.ui_base.dialog.TipDialog
|
|
|
|
|
+import com.grkj.ui_base.dialog.WheelTimePickerDialog
|
|
|
|
|
+import com.grkj.ui_base.utils.event.LoadingEvent
|
|
|
import com.sik.sikcore.extension.setDebouncedClickListener
|
|
import com.sik.sikcore.extension.setDebouncedClickListener
|
|
|
import dagger.hilt.android.AndroidEntryPoint
|
|
import dagger.hilt.android.AndroidEntryPoint
|
|
|
|
|
|
|
@@ -26,17 +39,111 @@ class BackupAndRestoreFragment : BaseFragment<FragmentBackupAndRestoreBinding>()
|
|
|
return R.layout.fragment_backup_and_restore
|
|
return R.layout.fragment_backup_and_restore
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 文件选择器
|
|
|
|
|
+ */
|
|
|
|
|
+ private lateinit var filePickerUtils: FilePickerUtils
|
|
|
|
|
+
|
|
|
override fun initView() {
|
|
override fun initView() {
|
|
|
binding.back.setDebouncedClickListener {
|
|
binding.back.setDebouncedClickListener {
|
|
|
navController.popBackStack()
|
|
navController.popBackStack()
|
|
|
}
|
|
}
|
|
|
|
|
+ binding.maximumNumberOfBackups.setText("${viewModel.scheduleData.keep}")
|
|
|
|
|
+ binding.statusRg.setOnCheckedChangeListener(null)
|
|
|
|
|
+ binding.enableRb.isChecked = viewModel.scheduleData.enabled
|
|
|
|
|
+ binding.disableRb.isChecked = !viewModel.scheduleData.enabled
|
|
|
|
|
+ filePickerUtils = FilePickerUtils(this)
|
|
|
|
|
+ binding.statusRg.setOnCheckedChangeListener { _, checkedId ->
|
|
|
|
|
+ viewModel.scheduleData.enabled = checkedId == binding.enableRb.id
|
|
|
|
|
+ }
|
|
|
|
|
+ viewModel.selectedBackupFrequencyData =
|
|
|
|
|
+ BackupFrequencyWeekEnum.getSelectedDaysText(viewModel.scheduleData.daysMask)
|
|
|
|
|
+ binding.backupFrequency.text =
|
|
|
|
|
+ if (viewModel.selectedBackupFrequencyData.size == 7) I18nManager.t("backup_frequency_every_day")
|
|
|
|
|
+ else viewModel.selectedBackupFrequencyData.joinToString(",") { it.showText }
|
|
|
|
|
+ binding.backupFrequency.setDebouncedClickListener {
|
|
|
|
|
+ TextDropDownDialog.showMulti(
|
|
|
|
|
+ viewModel.backupFrequencyData,
|
|
|
|
|
+ binding.backupFrequency
|
|
|
|
|
+ ) { selectedData ->
|
|
|
|
|
+ viewModel.selectedBackupFrequencyData = BackupFrequencyWeekEnum.values()
|
|
|
|
|
+ .filter {
|
|
|
|
|
+ selectedData?.map { it.getShowText() }?.contains(it.showText) == true
|
|
|
|
|
+ }
|
|
|
|
|
+ binding.backupFrequency.text =
|
|
|
|
|
+ if (viewModel.selectedBackupFrequencyData.size == 7) I18nManager.t("backup_frequency_every_day")
|
|
|
|
|
+ else viewModel.selectedBackupFrequencyData.joinToString(",") { it.showText }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ binding.save.setDebouncedClickListener {
|
|
|
|
|
+ if (checkSchedule()) {
|
|
|
|
|
+ viewModel.scheduleData.keep = binding.maximumNumberOfBackups.text.toString().toInt()
|
|
|
|
|
+ viewModel.selectedBackupFrequencyData.map {
|
|
|
|
|
+ it.type
|
|
|
|
|
+ }.let {
|
|
|
|
|
+ viewModel.scheduleData.daysMask =
|
|
|
|
|
+ BackupFrequencyWeekEnum.getMaskFromTypes(it)
|
|
|
|
|
+ }
|
|
|
|
|
+ viewModel.setAndApply().observe(this) {
|
|
|
|
|
+ showToast(I18nManager.t("save_success"))
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ binding.backupPath.text = RoomBackupManager.backupDir.absolutePath
|
|
|
binding.backupPath.isEnabled = false
|
|
binding.backupPath.isEnabled = false
|
|
|
|
|
+ binding.backupTime.text = "${viewModel.scheduleData.hour}:${viewModel.scheduleData.minute}"
|
|
|
|
|
+ binding.backupTime.setDebouncedClickListener {
|
|
|
|
|
+ val selectedTime = "${viewModel.scheduleData.hour}:${viewModel.scheduleData.minute}"
|
|
|
|
|
+ WheelTimePickerDialog.show(selectedTime) {
|
|
|
|
|
+ val split = it.split(":")
|
|
|
|
|
+ viewModel.scheduleData.hour = split[0].toInt()
|
|
|
|
|
+ viewModel.scheduleData.minute = split[1].toInt()
|
|
|
|
|
+ binding.backupTime.text = it
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
binding.backupNow.setDebouncedClickListener {
|
|
binding.backupNow.setDebouncedClickListener {
|
|
|
- BackupScheduler.backupNow(requireContext())
|
|
|
|
|
|
|
+ if (viewModel.backupItemDatas.size == viewModel.scheduleData.keep) {
|
|
|
|
|
+ TipDialog.showInfo(I18nManager.t("max_backup_tip"), onConfirmClick = {
|
|
|
|
|
+ LoadingEvent.sendLoadingEvent(I18nManager.t("backup_now_please_wait"))
|
|
|
|
|
+ BackupScheduler.backupNow(requireContext())
|
|
|
|
|
+ })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ LoadingEvent.sendLoadingEvent(I18nManager.t("backup_now_please_wait"))
|
|
|
|
|
+ BackupScheduler.backupNow(requireContext())
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ binding.batchDelete.setDebouncedClickListener {
|
|
|
|
|
+ TipDialog.showInfo(
|
|
|
|
|
+ I18nManager.t("delete_selected_backup_file_confirm"),
|
|
|
|
|
+ onConfirmClick = {
|
|
|
|
|
+ viewModel.deleteBackupFiles(viewModel.backupItemDatas.filter { it.isSelected })
|
|
|
|
|
+ .observe(this) {
|
|
|
|
|
+ getData()
|
|
|
|
|
+ showToast(I18nManager.t("delete_success"))
|
|
|
|
|
+ viewModel.backupItemDatas.forEach {
|
|
|
|
|
+ it.isSelected = false
|
|
|
|
|
+ }
|
|
|
|
|
+ checkAndSetSelectAllListener()
|
|
|
|
|
+ binding.listRv.adapter?.notifyDataSetChanged()
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
}
|
|
}
|
|
|
binding.batchExport.setDebouncedClickListener {
|
|
binding.batchExport.setDebouncedClickListener {
|
|
|
-
|
|
|
|
|
|
|
+ filePickerUtils.pickDirectory { treeUri ->
|
|
|
|
|
+ viewModel.backupItemDatas.filter { it.isSelected }.forEach {
|
|
|
|
|
+ treeUri?.let { treeUri ->
|
|
|
|
|
+ requireContext().moveFileToDir(treeUri, it.file)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ viewModel.backupItemDatas.forEach {
|
|
|
|
|
+ it.isSelected = false
|
|
|
|
|
+ }
|
|
|
|
|
+ checkAndSetSelectAllListener()
|
|
|
|
|
+ binding.listRv.adapter?.notifyDataSetChanged()
|
|
|
|
|
+ showToast(I18nManager.t("export_success"))
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
+ binding.state.emptyLayout = com.grkj.ui_base.R.layout.layout_no_backup
|
|
|
binding.listRv.linear().setup {
|
|
binding.listRv.linear().setup {
|
|
|
addType<RoomBackupManager.BackupItem>(R.layout.item_backup)
|
|
addType<RoomBackupManager.BackupItem>(R.layout.item_backup)
|
|
|
onBind {
|
|
onBind {
|
|
@@ -45,14 +152,67 @@ class BackupAndRestoreFragment : BaseFragment<FragmentBackupAndRestoreBinding>()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 检查并设置是否全选
|
|
|
|
|
+ */
|
|
|
|
|
+ private fun checkAndSetSelectAllListener() {
|
|
|
|
|
+ binding.selectAll.setOnCheckedChangeListener(null)
|
|
|
|
|
+ binding.selectAll.isChecked = viewModel.backupItemDatas.all { it.isSelected }
|
|
|
|
|
+ binding.selectAll.setOnCheckedChangeListener { v, isChecked ->
|
|
|
|
|
+ viewModel.backupItemDatas.forEach { it.isSelected = isChecked }
|
|
|
|
|
+ binding.listRv.adapter?.notifyDataSetChanged()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ override fun onEvent(event: EventBean<Any>) {
|
|
|
|
|
+ super.onEvent(event)
|
|
|
|
|
+ when (event.code) {
|
|
|
|
|
+ EventConstants.EVENT_BACKUP_COMPLETE_CODE -> {
|
|
|
|
|
+ (event.data as BackupCompleteEvent).let {
|
|
|
|
|
+ LoadingEvent.sendLoadingEvent()
|
|
|
|
|
+ if (it.backupResult) {
|
|
|
|
|
+ showToast(I18nManager.t("backup_success"))
|
|
|
|
|
+ } else {
|
|
|
|
|
+ showToast(I18nManager.t("backup_failed"))
|
|
|
|
|
+ }
|
|
|
|
|
+ getData()
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 检查计划
|
|
|
|
|
+ */
|
|
|
|
|
+ private fun checkSchedule(): Boolean {
|
|
|
|
|
+ if (viewModel.selectedBackupFrequencyData.isEmpty()) {
|
|
|
|
|
+ showToast(I18nManager.t("please_select_backup_frequency"))
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ val keep = binding.maximumNumberOfBackups.text.toString().toInt()
|
|
|
|
|
+ if (keep !in 5..20) {
|
|
|
|
|
+ showToast(I18nManager.t("maximumNumberOfBackupsNotCorrect"))
|
|
|
|
|
+ return false
|
|
|
|
|
+ }
|
|
|
|
|
+ return true
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
override fun initData() {
|
|
override fun initData() {
|
|
|
super.initData()
|
|
super.initData()
|
|
|
getData()
|
|
getData()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private fun getData() {
|
|
private fun getData() {
|
|
|
|
|
+ LoadingEvent.sendLoadingEvent(I18nManager.t("loading_backup"))
|
|
|
viewModel.getBackupList().observe(this) {
|
|
viewModel.getBackupList().observe(this) {
|
|
|
|
|
+ LoadingEvent.sendLoadingEvent()
|
|
|
|
|
+ if (it.isEmpty()) {
|
|
|
|
|
+ binding.state.showEmpty()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ binding.state.showContent()
|
|
|
|
|
+ }
|
|
|
binding.listRv.models = it
|
|
binding.listRv.models = it
|
|
|
|
|
+ checkAndSetSelectAllListener()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -60,16 +220,34 @@ class BackupAndRestoreFragment : BaseFragment<FragmentBackupAndRestoreBinding>()
|
|
|
val item = getModel<RoomBackupManager.BackupItem>()
|
|
val item = getModel<RoomBackupManager.BackupItem>()
|
|
|
val itemBinding = getBinding<ItemBackupBinding>()
|
|
val itemBinding = getBinding<ItemBackupBinding>()
|
|
|
itemBinding.backupName.text = item.name
|
|
itemBinding.backupName.text = item.name
|
|
|
|
|
+ itemBinding.select.setOnCheckedChangeListener(null)
|
|
|
|
|
+ itemBinding.select.isChecked = item.isSelected
|
|
|
|
|
+ itemBinding.select.setOnCheckedChangeListener { v, isChecked ->
|
|
|
|
|
+ item.isSelected = isChecked
|
|
|
|
|
+ checkAndSetSelectAllListener()
|
|
|
|
|
+ }
|
|
|
itemBinding.delete.setDebouncedClickListener {
|
|
itemBinding.delete.setDebouncedClickListener {
|
|
|
-
|
|
|
|
|
|
|
+ TipDialog.showInfo(I18nManager.t("delete_backup_file_confirm"), onConfirmClick = {
|
|
|
|
|
+ viewModel.deleteBackupFile(item).observe(this@BackupAndRestoreFragment) {
|
|
|
|
|
+ showToast(I18nManager.t("delete_success"))
|
|
|
|
|
+ getData()
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
}
|
|
}
|
|
|
itemBinding.export.setDebouncedClickListener {
|
|
itemBinding.export.setDebouncedClickListener {
|
|
|
-
|
|
|
|
|
|
|
+ filePickerUtils.pickDirectory { treeUri ->
|
|
|
|
|
+ treeUri?.let { treeUri ->
|
|
|
|
|
+ requireContext().moveFileToDir(treeUri, item.file)
|
|
|
|
|
+ }
|
|
|
|
|
+ showToast(I18nManager.t("export_success"))
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
itemBinding.restore.setDebouncedClickListener {
|
|
itemBinding.restore.setDebouncedClickListener {
|
|
|
- viewModel.restoreBackUp(item).observe(this@BackupAndRestoreFragment) {
|
|
|
|
|
- showToast("还原成功")
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ TipDialog.showInfo(I18nManager.t("restore_backup_confirm"), onConfirmClick = {
|
|
|
|
|
+ viewModel.restoreBackUp(item).observe(this@BackupAndRestoreFragment) {
|
|
|
|
|
+ showToast(I18nManager.t("restore_backup_success"))
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|