From 26ec53f654d9c649a20297e13cf80f048e8a21ea Mon Sep 17 00:00:00 2001 From: Bnyro Date: Sun, 18 Sep 2022 12:41:35 +0200 Subject: [PATCH] codebase for unified backup --- .../adapters/BackupOptionsAdapter.kt | 38 +++++++++++++ .../github/libretube/dialogs/BackupDialog.kt | 49 +++++++++++++++++ .../com/github/libretube/extensions/Query.kt | 5 ++ .../com/github/libretube/obj/BackupFile.kt | 15 ++++++ .../com/github/libretube/util/BackupHelper.kt | 54 +++++++++++++++++++ app/src/main/res/layout/backup_row.xml | 22 ++++++++ app/src/main/res/layout/dialog_backup.xml | 11 ++++ app/src/main/res/values/strings.xml | 2 + 8 files changed, 196 insertions(+) create mode 100644 app/src/main/java/com/github/libretube/adapters/BackupOptionsAdapter.kt create mode 100644 app/src/main/java/com/github/libretube/dialogs/BackupDialog.kt create mode 100644 app/src/main/java/com/github/libretube/extensions/Query.kt create mode 100644 app/src/main/java/com/github/libretube/obj/BackupFile.kt create mode 100644 app/src/main/res/layout/backup_row.xml create mode 100644 app/src/main/res/layout/dialog_backup.xml diff --git a/app/src/main/java/com/github/libretube/adapters/BackupOptionsAdapter.kt b/app/src/main/java/com/github/libretube/adapters/BackupOptionsAdapter.kt new file mode 100644 index 000000000..afae49d93 --- /dev/null +++ b/app/src/main/java/com/github/libretube/adapters/BackupOptionsAdapter.kt @@ -0,0 +1,38 @@ +package com.github.libretube.adapters + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.github.libretube.databinding.BackupRowBinding + +class BackupOptionsAdapter( + private val options: List, + private val onChange: (position: Int, isChecked: Boolean) -> Unit +) : RecyclerView.Adapter() { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BackupOptionsViewHolder { + val binding = BackupRowBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ) + return BackupOptionsViewHolder(binding) + } + + override fun getItemCount(): Int { + return options.size + } + + override fun onBindViewHolder(holder: BackupOptionsViewHolder, position: Int) { + holder.binding.apply { + title.text = root.context?.getString(options[position]) + switchWidget.setOnCheckedChangeListener { _, isChecked -> + onChange.invoke(position, isChecked) + } + } + } +} + +class BackupOptionsViewHolder( + val binding: BackupRowBinding +) : RecyclerView.ViewHolder(binding.root) diff --git a/app/src/main/java/com/github/libretube/dialogs/BackupDialog.kt b/app/src/main/java/com/github/libretube/dialogs/BackupDialog.kt new file mode 100644 index 000000000..48dd885b0 --- /dev/null +++ b/app/src/main/java/com/github/libretube/dialogs/BackupDialog.kt @@ -0,0 +1,49 @@ +package com.github.libretube.dialogs + +import android.app.Dialog +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import androidx.recyclerview.widget.LinearLayoutManager +import com.github.libretube.R +import com.github.libretube.adapters.BackupOptionsAdapter +import com.github.libretube.databinding.DialogBackupBinding +import com.github.libretube.db.DatabaseHolder +import com.github.libretube.obj.BackupFile +import com.google.android.material.dialog.MaterialAlertDialogBuilder + +class BackupDialog() : DialogFragment() { + private lateinit var binding: DialogBackupBinding + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val backupOptions = listOf( + R.string.watch_history, + R.string.watch_positions, + R.string.search_history, + R.string.local_subscriptions, + R.string.customInstance + ) + + val selected = mutableListOf(false, false, false, false, false) + + val backupFile = BackupFile() + + binding = DialogBackupBinding.inflate(layoutInflater) + binding.backupOptionsRecycler.layoutManager = LinearLayoutManager(context) + binding.backupOptionsRecycler.adapter = BackupOptionsAdapter(backupOptions) { position, isChecked -> + selected[position] = isChecked + } + + return MaterialAlertDialogBuilder(requireContext()) + .setTitle(R.string.backup) + .setView(binding.root) + .setNegativeButton(R.string.cancel, null) + .setPositiveButton(R.string.backup) { _, _ -> + if (selected[0]) backupFile.watchHistory = DatabaseHolder.db.watchHistoryDao().getAll() + if (selected[1]) backupFile.watchPositions = DatabaseHolder.db.watchPositionDao().getAll() + if (selected[2]) backupFile.searchHistory = DatabaseHolder.db.searchHistoryDao().getAll() + if (selected[3]) backupFile.localSubscriptions = DatabaseHolder.db.localSubscriptionDao().getAll() + if (selected[4]) backupFile.customInstances = DatabaseHolder.db.customInstanceDao().getAll() + } + .create() + } +} diff --git a/app/src/main/java/com/github/libretube/extensions/Query.kt b/app/src/main/java/com/github/libretube/extensions/Query.kt new file mode 100644 index 000000000..3cc5a81ff --- /dev/null +++ b/app/src/main/java/com/github/libretube/extensions/Query.kt @@ -0,0 +1,5 @@ +package com.github.libretube.extensions + +fun query(block: () -> Unit) { + Thread(block).start() +} diff --git a/app/src/main/java/com/github/libretube/obj/BackupFile.kt b/app/src/main/java/com/github/libretube/obj/BackupFile.kt new file mode 100644 index 000000000..3ab5320ce --- /dev/null +++ b/app/src/main/java/com/github/libretube/obj/BackupFile.kt @@ -0,0 +1,15 @@ +package com.github.libretube.obj + +import com.github.libretube.db.obj.CustomInstance +import com.github.libretube.db.obj.LocalSubscription +import com.github.libretube.db.obj.SearchHistoryItem +import com.github.libretube.db.obj.WatchHistoryItem +import com.github.libretube.db.obj.WatchPosition + +data class BackupFile( + var watchHistory: List? = null, + var watchPositions: List? = null, + var searchHistory: List? = null, + var localSubscriptions: List? = null, + var customInstances: List? = null +) diff --git a/app/src/main/java/com/github/libretube/util/BackupHelper.kt b/app/src/main/java/com/github/libretube/util/BackupHelper.kt index 97db72faa..9b002297d 100644 --- a/app/src/main/java/com/github/libretube/util/BackupHelper.kt +++ b/app/src/main/java/com/github/libretube/util/BackupHelper.kt @@ -4,6 +4,10 @@ import android.content.Context import android.net.Uri import androidx.core.content.edit import androidx.preference.PreferenceManager +import com.fasterxml.jackson.databind.ObjectMapper +import com.github.libretube.db.DatabaseHolder +import com.github.libretube.extensions.query +import com.github.libretube.obj.BackupFile import java.io.FileInputStream import java.io.FileOutputStream import java.io.ObjectInputStream @@ -64,4 +68,54 @@ class BackupHelper(private val context: Context) { e.printStackTrace() } } + + /** + * Backup the database + */ + fun advancedBackup(uri: Uri?, backupFile: BackupFile) { + if (uri == null) return + try { + context.contentResolver.openFileDescriptor(uri, "w")?.use { + FileOutputStream(it.fileDescriptor).use { fileOutputStream -> + fileOutputStream.write( + ObjectMapper().writeValueAsBytes(backupFile) + ) + } + } + } catch (e: Exception) { + e.printStackTrace() + } + } + + /** + * Restore a database backup + */ + fun restoreAdvancedBackup(uri: Uri?) { + if (uri == null) return + + val mapper = ObjectMapper() + val json = context.contentResolver.openInputStream(uri)?.use { + it.bufferedReader().use { reader -> reader.readText() } + }.orEmpty() + + val backupFile = mapper.readValue(json, BackupFile::class.java) + + query { + DatabaseHolder.db.watchHistoryDao().insertAll( + *backupFile.watchHistory?.toTypedArray().orEmpty() + ) + DatabaseHolder.db.searchHistoryDao().insertAll( + *backupFile.searchHistory?.toTypedArray().orEmpty() + ) + DatabaseHolder.db.watchPositionDao().insertAll( + *backupFile.watchPositions?.toTypedArray().orEmpty() + ) + DatabaseHolder.db.localSubscriptionDao().insertAll( + *backupFile.localSubscriptions?.toTypedArray().orEmpty() + ) + DatabaseHolder.db.customInstanceDao().insertAll( + *backupFile.customInstances?.toTypedArray().orEmpty() + ) + } + } } diff --git a/app/src/main/res/layout/backup_row.xml b/app/src/main/res/layout/backup_row.xml new file mode 100644 index 000000000..503d0a923 --- /dev/null +++ b/app/src/main/res/layout/backup_row.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_backup.xml b/app/src/main/res/layout/dialog_backup.xml new file mode 100644 index 000000000..5b4fe20df --- /dev/null +++ b/app/src/main/res/layout/dialog_backup.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0f38bb167..c0bea1be9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -324,6 +324,8 @@ Skip segment Skip manually Don\'t skip segments automatically, always prompt before. + Local subscriptions + Preferences Download Service