Add import export settings

This commit is contained in:
Bnyro 2022-12-01 13:48:08 +01:00
parent 7eea8dc6ee
commit 8ce809d30f
11 changed files with 195 additions and 141 deletions

View File

@ -0,0 +1,8 @@
package com.github.libretube.obj
data class ImportPlaylist(
val name: String? = null,
val type: String? = null,
val visibility: String? = null,
val videos: List<String> = listOf()
)

View File

@ -0,0 +1,7 @@
package com.github.libretube.obj
data class ImportPlaylistFile(
val format: String? = null,
val version: Int? = null,
val playlists: List<ImportPlaylist>? = null
)

View File

@ -1,6 +1,7 @@
package com.github.libretube.ui.base package com.github.libretube.ui.base
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.preference.EditTextPreference import androidx.preference.EditTextPreference
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
@ -70,4 +71,10 @@ open class BasePreferenceFragment : PreferenceFragmentCompat() {
else -> super.onDisplayPreferenceDialog(preference) else -> super.onDisplayPreferenceDialog(preference)
} }
} }
fun Fragment?.runOnUiThread(action: () -> Unit) {
this ?: return
if (!isAdded) return // Fragment not attached to an Activity
activity?.runOnUiThread(action)
}
} }

View File

@ -1,49 +1,18 @@
package com.github.libretube.ui.preferences package com.github.libretube.ui.preferences
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
import com.github.libretube.R import com.github.libretube.R
import com.github.libretube.constants.PreferenceKeys import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.obj.BackupFile
import com.github.libretube.ui.activities.SettingsActivity import com.github.libretube.ui.activities.SettingsActivity
import com.github.libretube.ui.base.BasePreferenceFragment import com.github.libretube.ui.base.BasePreferenceFragment
import com.github.libretube.ui.dialogs.BackupDialog
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
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.time.LocalDate
import java.time.LocalTime
class AdvancedSettings : BasePreferenceFragment() { class AdvancedSettings : BasePreferenceFragment() {
// 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?) {
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)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.advanced_settings, rootKey) setPreferencesFromResource(R.xml.advanced_settings, rootKey)
@ -61,22 +30,6 @@ class AdvancedSettings : BasePreferenceFragment() {
showResetDialog() showResetDialog()
true true
} }
val advancesBackup = findPreference<Preference>("backup")
advancesBackup?.setOnPreferenceClickListener {
BackupDialog {
backupFile = it
createBackupFile.launch(getBackupFileName())
}
.show(childFragmentManager, null)
true
}
val restoreAdvancedBackup = findPreference<Preference>("restore")
restoreAdvancedBackup?.setOnPreferenceClickListener {
getBackupFile.launch("application/json")
true
}
} }
private fun showResetDialog() { private fun showResetDialog() {
@ -95,9 +48,4 @@ class AdvancedSettings : BasePreferenceFragment() {
} }
.show() .show()
} }
private fun getBackupFileName(): String {
val time = LocalTime.now().toString().split(".").firstOrNull()
return "libretube-backup-${LocalDate.now()}-$time.json"
}
} }

View File

@ -0,0 +1,98 @@
package com.github.libretube.ui.preferences
import android.net.Uri
import android.os.Bundle
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
import androidx.preference.Preference
import com.github.libretube.R
import com.github.libretube.constants.PreferenceKeys
import com.github.libretube.obj.BackupFile
import com.github.libretube.ui.base.BasePreferenceFragment
import com.github.libretube.ui.dialogs.BackupDialog
import com.github.libretube.util.BackupHelper
import com.github.libretube.util.ImportHelper
import java.time.LocalDate
import java.time.LocalTime
class BackupRestoreSettings : BasePreferenceFragment() {
// backup and restore database
private lateinit var getBackupFile: ActivityResultLauncher<String>
private lateinit var createBackupFile: ActivityResultLauncher<String>
private var backupFile = BackupFile()
/**
* result listeners for importing and exporting subscriptions
*/
private lateinit var getSubscriptionsFile: ActivityResultLauncher<String>
private lateinit var createSubscriptionsFile: ActivityResultLauncher<String>
override fun onCreate(savedInstanceState: Bundle?) {
getSubscriptionsFile =
registerForActivityResult(
ActivityResultContracts.GetContent()
) { uri: Uri? ->
ImportHelper(requireActivity()).importSubscriptions(uri)
}
createSubscriptionsFile = registerForActivityResult(
CreateDocument("application/json")
) { uri: Uri? ->
ImportHelper(requireActivity()).exportSubscriptions(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)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.import_export_settings, rootKey)
val importSubscriptions = findPreference<Preference>(PreferenceKeys.IMPORT_SUBS)
importSubscriptions?.setOnPreferenceClickListener {
// check StorageAccess
getSubscriptionsFile.launch("*/*")
true
}
val exportSubscriptions = findPreference<Preference>(PreferenceKeys.EXPORT_SUBS)
exportSubscriptions?.setOnPreferenceClickListener {
createSubscriptionsFile.launch("subscriptions.json")
true
}
val advancesBackup = findPreference<Preference>("backup")
advancesBackup?.setOnPreferenceClickListener {
BackupDialog {
backupFile = it
createBackupFile.launch(getBackupFileName())
}
.show(childFragmentManager, null)
true
}
val restoreAdvancedBackup = findPreference<Preference>("restore")
restoreAdvancedBackup?.setOnPreferenceClickListener {
getBackupFile.launch("application/json")
true
}
}
private fun getBackupFileName(): String {
val time = LocalTime.now().toString().split(".").firstOrNull()
return "libretube-backup-${LocalDate.now()}-$time.json"
}
}

View File

@ -1,12 +1,7 @@
package com.github.libretube.ui.preferences package com.github.libretube.ui.preferences
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.widget.Toast import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.result.contract.ActivityResultContracts.CreateDocument
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
@ -22,33 +17,10 @@ import com.github.libretube.ui.dialogs.CustomInstanceDialog
import com.github.libretube.ui.dialogs.DeleteAccountDialog import com.github.libretube.ui.dialogs.DeleteAccountDialog
import com.github.libretube.ui.dialogs.LoginDialog import com.github.libretube.ui.dialogs.LoginDialog
import com.github.libretube.ui.dialogs.LogoutDialog import com.github.libretube.ui.dialogs.LogoutDialog
import com.github.libretube.util.ImportHelper
import com.github.libretube.util.PreferenceHelper import com.github.libretube.util.PreferenceHelper
class InstanceSettings : BasePreferenceFragment() { class InstanceSettings : BasePreferenceFragment() {
/**
* result listeners for importing and exporting subscriptions
*/
private lateinit var getContent: ActivityResultLauncher<String>
private lateinit var createFile: ActivityResultLauncher<String>
override fun onCreate(savedInstanceState: Bundle?) {
getContent =
registerForActivityResult(
ActivityResultContracts.GetContent()
) { uri: Uri? ->
ImportHelper(requireActivity()).importSubscriptions(uri)
}
createFile = registerForActivityResult(
CreateDocument("application/json")
) { uri: Uri? ->
ImportHelper(requireActivity()).exportSubscriptions(uri)
}
super.onCreate(savedInstanceState)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.instance_settings, rootKey) setPreferencesFromResource(R.xml.instance_settings, rootKey)
@ -138,19 +110,6 @@ class InstanceSettings : BasePreferenceFragment() {
newFragment.show(childFragmentManager, DeleteAccountDialog::class.java.name) newFragment.show(childFragmentManager, DeleteAccountDialog::class.java.name)
true true
} }
val importSubscriptions = findPreference<Preference>(PreferenceKeys.IMPORT_SUBS)
importSubscriptions?.setOnPreferenceClickListener {
// check StorageAccess
getContent.launch("*/*")
true
}
val exportSubscriptions = findPreference<Preference>(PreferenceKeys.EXPORT_SUBS)
exportSubscriptions?.setOnPreferenceClickListener {
createFile.launch("subscriptions.json")
true
}
} }
private fun initCustomInstances(instancePref: ListPreference) { private fun initCustomInstances(instancePref: ListPreference) {
@ -201,10 +160,4 @@ class InstanceSettings : BasePreferenceFragment() {
PreferenceHelper.setToken("") PreferenceHelper.setToken("")
Toast.makeText(context, getString(R.string.loggedout), Toast.LENGTH_SHORT).show() Toast.makeText(context, getString(R.string.loggedout), Toast.LENGTH_SHORT).show()
} }
private fun Fragment?.runOnUiThread(action: () -> Unit) {
this ?: return
if (!isAdded) return // Fragment not attached to an Activity
activity?.runOnUiThread(action)
}
} }

View File

@ -23,65 +23,52 @@ class MainSettings : BasePreferenceFragment() {
val general = findPreference<Preference>("general") val general = findPreference<Preference>("general")
general?.setOnPreferenceClickListener { general?.setOnPreferenceClickListener {
val newFragment = GeneralSettings() navigateToSettingsFragment(GeneralSettings())
navigateToSettingsFragment(newFragment)
true
} }
val instance = findPreference<Preference>("instance") val instance = findPreference<Preference>("instance")
instance?.setOnPreferenceClickListener { instance?.setOnPreferenceClickListener {
val newFragment = InstanceSettings() navigateToSettingsFragment(InstanceSettings())
navigateToSettingsFragment(newFragment)
true
} }
val appearance = findPreference<Preference>("appearance") val appearance = findPreference<Preference>("appearance")
appearance?.setOnPreferenceClickListener { appearance?.setOnPreferenceClickListener {
val newFragment = AppearanceSettings() navigateToSettingsFragment(AppearanceSettings())
navigateToSettingsFragment(newFragment)
true
} }
val sponsorBlock = findPreference<Preference>("sponsorblock") val sponsorBlock = findPreference<Preference>("sponsorblock")
sponsorBlock?.setOnPreferenceClickListener { sponsorBlock?.setOnPreferenceClickListener {
val newFragment = SponsorBlockSettings() navigateToSettingsFragment(SponsorBlockSettings())
navigateToSettingsFragment(newFragment)
true
} }
val player = findPreference<Preference>("player") val player = findPreference<Preference>("player")
player?.setOnPreferenceClickListener { player?.setOnPreferenceClickListener {
val newFragment = PlayerSettings() navigateToSettingsFragment(PlayerSettings())
navigateToSettingsFragment(newFragment)
true
} }
val audioVideo = findPreference<Preference>("audio_video") val audioVideo = findPreference<Preference>("audio_video")
audioVideo?.setOnPreferenceClickListener { audioVideo?.setOnPreferenceClickListener {
val newFragment = AudioVideoSettings() navigateToSettingsFragment(AudioVideoSettings())
navigateToSettingsFragment(newFragment)
true
} }
val history = findPreference<Preference>("history") val history = findPreference<Preference>("history")
history?.setOnPreferenceClickListener { history?.setOnPreferenceClickListener {
val newFragment = HistorySettings() navigateToSettingsFragment(HistorySettings())
navigateToSettingsFragment(newFragment)
true
} }
val notifications = findPreference<Preference>("notifications") val notifications = findPreference<Preference>("notifications")
notifications?.setOnPreferenceClickListener { notifications?.setOnPreferenceClickListener {
val newFragment = NotificationSettings() navigateToSettingsFragment(NotificationSettings())
navigateToSettingsFragment(newFragment) }
true
val backupRestore = findPreference<Preference>("backup_restore")
backupRestore?.setOnPreferenceClickListener {
navigateToSettingsFragment(BackupRestoreSettings())
} }
val advanced = findPreference<Preference>("advanced") val advanced = findPreference<Preference>("advanced")
advanced?.setOnPreferenceClickListener { advanced?.setOnPreferenceClickListener {
val newFragment = AdvancedSettings() navigateToSettingsFragment(AdvancedSettings())
navigateToSettingsFragment(newFragment)
true
} }
val update = findPreference<Preference>("update") val update = findPreference<Preference>("update")
@ -131,9 +118,10 @@ class MainSettings : BasePreferenceFragment() {
} }
} }
private fun navigateToSettingsFragment(newFragment: Fragment) { private fun navigateToSettingsFragment(newFragment: Fragment): Boolean {
parentFragmentManager.beginTransaction() parentFragmentManager.beginTransaction()
.replace(R.id.settings, newFragment) .replace(R.id.settings, newFragment)
.commitNow() .commitNow()
return true
} }
} }

View File

@ -403,6 +403,10 @@
<string name="double_tap_seek_summary">Tap twice at the left or right to rewind or forward the player position.</string> <string name="double_tap_seek_summary">Tap twice at the left or right to rewind or forward the player position.</string>
<string name="all_caught_up">You\'re all caught up</string> <string name="all_caught_up">You\'re all caught up</string>
<string name="all_caught_up_summary">You\'ve seen all new videos</string> <string name="all_caught_up_summary">You\'ve seen all new videos</string>
<string name="import_playlists">Import playlists</string>
<string name="export_playlists">Export playlists</string>
<string name="app_backup">App Backup</string>
<string name="backup_restore_summary">Import &amp; export subscriptions, playlists, ...</string>
<!-- Notification channel strings --> <!-- Notification channel strings -->
<string name="download_channel_name">Download Service</string> <string name="download_channel_name">Download Service</string>

View File

@ -39,20 +39,6 @@
</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>
<PreferenceCategory app:title="@string/misc"> <PreferenceCategory app:title="@string/misc">
<Preference <Preference

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<PreferenceCategory app:title="@string/subscriptions">
<Preference
android:icon="@drawable/ic_download_filled"
android:summary="@string/import_from_yt_summary"
app:key="import_from_yt"
app:title="@string/import_from_yt" />
<Preference
android:icon="@drawable/ic_upload"
app:key="export_subs"
app:title="@string/export_subscriptions" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/playlists">
<Preference
android:icon="@drawable/ic_download_filled"
android:summary="@string/import_playlists"
app:key="import_from_yt"
app:title="@string/import_from_yt" />
<Preference
android:icon="@drawable/ic_upload"
app:key="export_subs"
app:title="@string/export_playlists" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/app_backup">
<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>

View File

@ -50,6 +50,12 @@
app:key="notifications" app:key="notifications"
app:title="@string/notifications" /> app:title="@string/notifications" />
<Preference
android:icon="@drawable/ic_backup"
app:key="backup_restore"
app:summary="@string/backup_restore_summary"
app:title="@string/backup_restore" />
<Preference <Preference
android:icon="@drawable/ic_list" android:icon="@drawable/ic_list"
app:key="advanced" app:key="advanced"