mirror of
https://github.com/libre-tube/LibreTube.git
synced 2025-01-06 01:20:29 +05:30
commit
e16ff990f7
@ -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<Int>,
|
||||||
|
private val onChange: (position: Int, isChecked: Boolean) -> Unit
|
||||||
|
) : RecyclerView.Adapter<BackupOptionsViewHolder>() {
|
||||||
|
|
||||||
|
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)
|
@ -0,0 +1,71 @@
|
|||||||
|
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.extensions.await
|
||||||
|
import com.github.libretube.obj.BackupFile
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
|
||||||
|
class BackupDialog(
|
||||||
|
private val createBackupFile: (BackupFile) -> Unit
|
||||||
|
) : DialogFragment() {
|
||||||
|
private lateinit var binding: DialogBackupBinding
|
||||||
|
|
||||||
|
val backupFile = BackupFile()
|
||||||
|
|
||||||
|
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.backup_customInstances
|
||||||
|
)
|
||||||
|
|
||||||
|
val selected = mutableListOf(false, false, false, false, false)
|
||||||
|
|
||||||
|
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) { _, _ ->
|
||||||
|
Thread {
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}.await()
|
||||||
|
|
||||||
|
createBackupFile(backupFile)
|
||||||
|
}
|
||||||
|
.create()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.github.libretube.extensions
|
||||||
|
|
||||||
|
fun query(block: () -> Unit) {
|
||||||
|
Thread(block).start()
|
||||||
|
}
|
15
app/src/main/java/com/github/libretube/obj/BackupFile.kt
Normal file
15
app/src/main/java/com/github/libretube/obj/BackupFile.kt
Normal file
@ -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<WatchHistoryItem>? = null,
|
||||||
|
var watchPositions: List<WatchPosition>? = null,
|
||||||
|
var searchHistory: List<SearchHistoryItem>? = null,
|
||||||
|
var localSubscriptions: List<LocalSubscription>? = null,
|
||||||
|
var customInstances: List<CustomInstance>? = null
|
||||||
|
)
|
@ -10,6 +10,8 @@ import androidx.preference.Preference
|
|||||||
import com.github.libretube.R
|
import com.github.libretube.R
|
||||||
import com.github.libretube.activities.SettingsActivity
|
import com.github.libretube.activities.SettingsActivity
|
||||||
import com.github.libretube.constants.PreferenceKeys
|
import com.github.libretube.constants.PreferenceKeys
|
||||||
|
import com.github.libretube.dialogs.BackupDialog
|
||||||
|
import com.github.libretube.obj.BackupFile
|
||||||
import com.github.libretube.util.BackupHelper
|
import com.github.libretube.util.BackupHelper
|
||||||
import com.github.libretube.util.ImageHelper
|
import com.github.libretube.util.ImageHelper
|
||||||
import com.github.libretube.util.PreferenceHelper
|
import com.github.libretube.util.PreferenceHelper
|
||||||
@ -18,24 +20,41 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
|||||||
|
|
||||||
class AdvancedSettings : MaterialPreferenceFragment() {
|
class AdvancedSettings : MaterialPreferenceFragment() {
|
||||||
|
|
||||||
/**
|
// backup and restore prefs
|
||||||
* result listeners for importing and exporting subscriptions
|
private lateinit var getPrefFile: ActivityResultLauncher<String>
|
||||||
*/
|
private lateinit var createPrefFile: ActivityResultLauncher<String>
|
||||||
private lateinit var getContent: ActivityResultLauncher<String>
|
|
||||||
private lateinit var createFile: ActivityResultLauncher<String>
|
// backup and restore database
|
||||||
|
private lateinit var getBackupFile: ActivityResultLauncher<String>
|
||||||
|
private lateinit var createBackupFile: ActivityResultLauncher<String>
|
||||||
|
private var backupFile = BackupFile()
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
getContent =
|
getPrefFile =
|
||||||
registerForActivityResult(
|
registerForActivityResult(
|
||||||
ActivityResultContracts.GetContent()
|
ActivityResultContracts.GetContent()
|
||||||
) { uri: Uri? ->
|
) { uri: Uri? ->
|
||||||
BackupHelper(requireContext()).restoreSharedPreferences(uri)
|
BackupHelper(requireContext()).restoreSharedPreferences(uri)
|
||||||
}
|
}
|
||||||
createFile = registerForActivityResult(
|
createPrefFile = registerForActivityResult(
|
||||||
CreateDocument("application/json")
|
CreateDocument("application/json")
|
||||||
) { uri: Uri? ->
|
) { uri: Uri? ->
|
||||||
BackupHelper(requireContext()).backupSharedPreferences(uri)
|
BackupHelper(requireContext()).backupSharedPreferences(uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBackupFile =
|
||||||
|
registerForActivityResult(
|
||||||
|
ActivityResultContracts.GetContent()
|
||||||
|
) { uri: Uri? ->
|
||||||
|
BackupHelper(requireContext()).restoreAdvancedBackup(uri)
|
||||||
|
}
|
||||||
|
|
||||||
|
createBackupFile = registerForActivityResult(
|
||||||
|
CreateDocument("application/json")
|
||||||
|
) { uri: Uri? ->
|
||||||
|
BackupHelper(requireContext()).advancedBackup(uri, backupFile)
|
||||||
|
}
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,18 +78,34 @@ class AdvancedSettings : MaterialPreferenceFragment() {
|
|||||||
|
|
||||||
val backupSettings = findPreference<Preference>(PreferenceKeys.BACKUP_SETTINGS)
|
val backupSettings = findPreference<Preference>(PreferenceKeys.BACKUP_SETTINGS)
|
||||||
backupSettings?.setOnPreferenceClickListener {
|
backupSettings?.setOnPreferenceClickListener {
|
||||||
createFile.launch("preferences.xml")
|
createPrefFile.launch("preferences.xml")
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
val restoreSettings = findPreference<Preference>(PreferenceKeys.RESTORE_SETTINGS)
|
val restoreSettings = findPreference<Preference>(PreferenceKeys.RESTORE_SETTINGS)
|
||||||
restoreSettings?.setOnPreferenceClickListener {
|
restoreSettings?.setOnPreferenceClickListener {
|
||||||
getContent.launch("*/*")
|
getPrefFile.launch("*/*")
|
||||||
// reset the token
|
// reset the token
|
||||||
PreferenceHelper.setToken("")
|
PreferenceHelper.setToken("")
|
||||||
activity?.recreate()
|
activity?.recreate()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val advancesBackup = findPreference<Preference>("backup")
|
||||||
|
advancesBackup?.setOnPreferenceClickListener {
|
||||||
|
BackupDialog {
|
||||||
|
backupFile = it
|
||||||
|
createBackupFile.launch("backup.json")
|
||||||
|
}
|
||||||
|
.show(childFragmentManager, null)
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
val restoreAdvancedBackup = findPreference<Preference>("restore")
|
||||||
|
restoreAdvancedBackup?.setOnPreferenceClickListener {
|
||||||
|
getBackupFile.launch("application/json")
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showResetDialog() {
|
private fun showResetDialog() {
|
||||||
|
@ -4,6 +4,10 @@ import android.content.Context
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import androidx.preference.PreferenceManager
|
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.FileInputStream
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.ObjectInputStream
|
import java.io.ObjectInputStream
|
||||||
@ -64,4 +68,54 @@ class BackupHelper(private val context: Context) {
|
|||||||
e.printStackTrace()
|
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()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
22
app/src/main/res/layout/backup_row.xml
Normal file
22
app/src/main/res/layout/backup_row.xml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="30dp"
|
||||||
|
android:paddingVertical="5dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="5dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<com.google.android.material.materialswitch.MaterialSwitch
|
||||||
|
android:id="@+id/switchWidget"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
11
app/src/main/res/layout/dialog_backup.xml
Normal file
11
app/src/main/res/layout/dialog_backup.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/backupOptionsRecycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -324,6 +324,9 @@
|
|||||||
<string name="skip_segment">Skip segment</string>
|
<string name="skip_segment">Skip segment</string>
|
||||||
<string name="sb_skip_manual">Skip manually</string>
|
<string name="sb_skip_manual">Skip manually</string>
|
||||||
<string name="sb_skip_manual_summary">Don\'t skip segments automatically, always prompt before.</string>
|
<string name="sb_skip_manual_summary">Don\'t skip segments automatically, always prompt before.</string>
|
||||||
|
<string name="local_subscriptions">Local subscriptions</string>
|
||||||
|
<string name="preferences">Preferences</string>
|
||||||
|
<string name="backup_customInstances">Custom Instances</string>
|
||||||
|
|
||||||
<!-- Notification channel strings -->
|
<!-- Notification channel strings -->
|
||||||
<string name="download_channel_name">Download Service</string>
|
<string name="download_channel_name">Download Service</string>
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory app:title="@string/backup_restore">
|
<PreferenceCategory app:title="@string/preferences">
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:icon="@drawable/ic_backup"
|
android:icon="@drawable/ic_backup"
|
||||||
@ -46,4 +46,18 @@
|
|||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
|
<PreferenceCategory app:title="@string/backup_restore">
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:icon="@drawable/ic_backup"
|
||||||
|
app:key="backup"
|
||||||
|
app:title="@string/backup" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:icon="@drawable/ic_restore"
|
||||||
|
app:key="restore"
|
||||||
|
app:title="@string/restore" />
|
||||||
|
|
||||||
|
</PreferenceCategory>
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
Loading…
Reference in New Issue
Block a user