diff --git a/app/src/main/java/cn/lyric/getter/tool/BackupTools.kt b/app/src/main/java/cn/lyric/getter/tool/BackupTools.kt new file mode 100644 index 0000000..c0bc7eb --- /dev/null +++ b/app/src/main/java/cn/lyric/getter/tool/BackupTools.kt @@ -0,0 +1,76 @@ +package cn.lyric.getter.tool + +import android.app.Activity +import android.content.SharedPreferences +import android.net.Uri +import cn.xiaowine.xkt.AcTool.showToast +import cn.xiaowine.xkt.Tool.isNotNull +import org.json.JSONObject +import java.io.BufferedReader +import java.io.BufferedWriter +import java.io.InputStreamReader +import java.io.OutputStreamWriter + + +object BackupTools { + fun handleReadDocument(activity: Activity, sp: SharedPreferences, data: Uri) { + val edit = sp.edit() + try { + activity.contentResolver.openInputStream(data)?.let { loadFile -> + BufferedReader(InputStreamReader(loadFile)).apply { + val sb = StringBuffer() + var line = readLine() + while (line.isNotNull()) { + sb.append(line) + line = readLine() + } + val read = sb.toString() + JSONObject(read).apply { + val key = keys() + while (key.hasNext()) { + val keys = key.next() + when (val value = get(keys)) { + is String -> { + if (value.startsWith("Float:")) { + edit.putFloat(keys, value.substring(value.indexOf("Float:")).toFloat() / 1000) + } else { + edit.putString(keys, value) + } + } + + is Boolean -> edit.putBoolean(keys, value) + is Int -> edit.putInt(keys, value) + } + } + } + close() + } + } + edit.apply() + "load ok".showToast() + } catch (e: Exception) { + "load fail\n${e.message}".showToast() + } + } + + fun handleCreateDocument(activity: Activity, sp: SharedPreferences, data: Uri) { + try { + activity.contentResolver.openOutputStream(data)?.let { saveFile -> + BufferedWriter(OutputStreamWriter(saveFile)).apply { + write(JSONObject().also { + for (entry: Map.Entry in sp.all) { + when (entry.value) { + Float -> it.put(entry.key, "Float:" + (entry.value as Float * 1000).toInt().toString()) + else -> it.put(entry.key, entry.value) + } + } + }.toString()) + close() + } + } + "save ok".showToast() + } catch (e: Exception) { + "save fail\n${e.message}".showToast() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/cn/lyric/getter/ui/fragment/HomeFragment.kt b/app/src/main/java/cn/lyric/getter/ui/fragment/HomeFragment.kt index ffae587..b52f138 100644 --- a/app/src/main/java/cn/lyric/getter/ui/fragment/HomeFragment.kt +++ b/app/src/main/java/cn/lyric/getter/ui/fragment/HomeFragment.kt @@ -10,26 +10,51 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels import cn.lyric.getter.BuildConfig import cn.lyric.getter.R import cn.lyric.getter.config.ActivityOwnSP.config +import cn.lyric.getter.config.ActivityOwnSP.ownSP import cn.lyric.getter.databinding.FragmentHomeBinding import cn.lyric.getter.tool.ActivityTools.getAppRules +import cn.lyric.getter.tool.BackupTools import cn.lyric.getter.tool.Tools.restartTheScopedSoftware import cn.lyric.getter.ui.viewmodel.HomeViewModel import cn.lyric.getter.ui.viewmodel.ShareViewModel import cn.xiaowine.xkt.AcTool.restartApp +import cn.xiaowine.xkt.Tool.isNotNull import cn.xiaowine.xkt.Tool.toUpperFirstCaseAndLowerOthers import com.google.android.material.color.MaterialColors +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import java.text.SimpleDateFormat import java.util.Locale class HomeFragment : Fragment() { + private var recoveryPickerLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { + it.isNotNull { uri -> + BackupTools.handleReadDocument(requireActivity(), ownSP, uri) + MaterialAlertDialogBuilder(requireContext()).apply { + setTitle(R.string.recovery) + setCancelable(false) + setMessage(R.string.recovery_summary) + setPositiveButton(R.string.restart) { _, _ -> + restartApp() + } + show() + } + } + } + private var backupPickerLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument("application/json")) { + it.isNotNull { uri -> + BackupTools.handleCreateDocument(requireActivity(), ownSP, uri) + } + } + private val shareViewModel: ShareViewModel by activityViewModels() private val homeViewModel: HomeViewModel by viewModels() @@ -80,16 +105,26 @@ class HomeFragment : Fragment() { isChecked = config.hideDesktopIcons } setOnMenuItemClickListener { - if (it.itemId == R.id.show_hide_desktop_icons) { - it.isChecked = !it.isChecked - config.hideDesktopIcons = it.isChecked - requireContext().packageManager.setComponentEnabledSetting( - ComponentName(requireContext(), "${BuildConfig.APPLICATION_ID}.launcher"), if (it.isChecked) { - PackageManager.COMPONENT_ENABLED_STATE_DISABLED - } else { - PackageManager.COMPONENT_ENABLED_STATE_ENABLED - }, PackageManager.DONT_KILL_APP - ) + when (it.itemId) { + R.id.backup -> { + backupPickerLauncher.launch("LyricGetter_Backup_${SimpleDateFormat("yyyy-MM-dd-HH:mm", Locale.getDefault()).format(System.currentTimeMillis())}.json") + } + + R.id.recovery -> { + recoveryPickerLauncher.launch("application/json") + } + + R.id.show_hide_desktop_icons -> { + it.isChecked = !it.isChecked + config.hideDesktopIcons = it.isChecked + requireContext().packageManager.setComponentEnabledSetting( + ComponentName(requireContext(), "${BuildConfig.APPLICATION_ID}.launcher"), if (it.isChecked) { + PackageManager.COMPONENT_ENABLED_STATE_DISABLED + } else { + PackageManager.COMPONENT_ENABLED_STATE_ENABLED + }, PackageManager.DONT_KILL_APP + ) + } } true } diff --git a/app/src/main/res/menu/home_menu.xml b/app/src/main/res/menu/home_menu.xml index 2ba72ca..b066bc8 100644 --- a/app/src/main/res/menu/home_menu.xml +++ b/app/src/main/res/menu/home_menu.xml @@ -10,4 +10,15 @@ android:layout_height="wrap_content" android:title="@string/show_hide_desktop_icons" /> + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2e9df79..96c1d1b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -44,4 +44,7 @@ 更新 检查更新时出现错误 APP规则API版本 + 备份 + 恢复 + 重启应用程序生效 \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d955d07..5b58cdd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -agp = "8.1.0" +agp = "8.1.1" kotlin = "1.9.0" [libraries] diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2e5730f..11623d2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #Tue Jan 25 15:10:00 CST 2022 distributionBase=GRADLE_USER_HOME -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME