Create new settings category: Backup and restore
Following settings have been move to the new category: - import database (from ContenttSettings) - export database (from ContenttSettings) - reset settings (from DebugSettings)
This commit is contained in:
parent
ad0855ac83
commit
f2e352832a
11 changed files with 304 additions and 269 deletions
|
@ -0,0 +1,271 @@
|
||||||
|
package org.schabi.newpipe.settings;
|
||||||
|
|
||||||
|
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
|
||||||
|
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResult;
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.NewPipeDatabase;
|
||||||
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.error.ErrorUtil;
|
||||||
|
import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard;
|
||||||
|
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
||||||
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
|
import org.schabi.newpipe.util.ZipHelper;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public class BackupRestoreSettingsFragment extends BasePreferenceFragment {
|
||||||
|
|
||||||
|
private static final String ZIP_MIME_TYPE = "application/zip";
|
||||||
|
|
||||||
|
private final SimpleDateFormat exportDateFormat =
|
||||||
|
new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);
|
||||||
|
private ContentSettingsManager manager;
|
||||||
|
private String importExportDataPathKey;
|
||||||
|
private final ActivityResultLauncher<Intent> requestImportPathLauncher =
|
||||||
|
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
|
||||||
|
this::requestImportPathResult);
|
||||||
|
private final ActivityResultLauncher<Intent> requestExportPathLauncher =
|
||||||
|
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
|
||||||
|
this::requestExportPathResult);
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreatePreferences(@Nullable final Bundle savedInstanceState,
|
||||||
|
@Nullable final String rootKey) {
|
||||||
|
final File homeDir = ContextCompat.getDataDir(requireContext());
|
||||||
|
Objects.requireNonNull(homeDir);
|
||||||
|
manager = new ContentSettingsManager(new NewPipeFileLocator(homeDir));
|
||||||
|
manager.deleteSettingsFile();
|
||||||
|
|
||||||
|
importExportDataPathKey = getString(R.string.import_export_data_path);
|
||||||
|
|
||||||
|
|
||||||
|
addPreferencesFromResourceRegistry();
|
||||||
|
|
||||||
|
final Preference importDataPreference = requirePreference(R.string.import_data);
|
||||||
|
importDataPreference.setOnPreferenceClickListener((Preference p) -> {
|
||||||
|
NoFileManagerSafeGuard.launchSafe(
|
||||||
|
requestImportPathLauncher,
|
||||||
|
StoredFileHelper.getPicker(requireContext(),
|
||||||
|
ZIP_MIME_TYPE, getImportExportDataUri()),
|
||||||
|
TAG,
|
||||||
|
getContext()
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
final Preference exportDataPreference = requirePreference(R.string.export_data);
|
||||||
|
exportDataPreference.setOnPreferenceClickListener((final Preference p) -> {
|
||||||
|
NoFileManagerSafeGuard.launchSafe(
|
||||||
|
requestExportPathLauncher,
|
||||||
|
StoredFileHelper.getNewPicker(requireContext(),
|
||||||
|
"NewPipeData-" + exportDateFormat.format(new Date()) + ".zip",
|
||||||
|
ZIP_MIME_TYPE, getImportExportDataUri()),
|
||||||
|
TAG,
|
||||||
|
getContext()
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
final Preference resetSettings = findPreference(getString(R.string.reset_settings));
|
||||||
|
// Resets all settings by deleting shared preference and restarting the app
|
||||||
|
// A dialogue will pop up to confirm if user intends to reset all settings
|
||||||
|
assert resetSettings != null;
|
||||||
|
resetSettings.setOnPreferenceClickListener(preference -> {
|
||||||
|
// Show Alert Dialogue
|
||||||
|
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||||
|
builder.setMessage(R.string.reset_all_settings);
|
||||||
|
builder.setCancelable(true);
|
||||||
|
builder.setPositiveButton(R.string.ok, (dialogInterface, i) -> {
|
||||||
|
// Deletes all shared preferences xml files.
|
||||||
|
final SharedPreferences sharedPreferences =
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(requireContext());
|
||||||
|
sharedPreferences.edit().clear().apply();
|
||||||
|
// Restarts the app
|
||||||
|
if (getActivity() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NavigationHelper.restartApp(getActivity());
|
||||||
|
});
|
||||||
|
builder.setNegativeButton(R.string.cancel, (dialogInterface, i) -> {
|
||||||
|
});
|
||||||
|
final AlertDialog alertDialog = builder.create();
|
||||||
|
alertDialog.show();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestExportPathResult(final ActivityResult result) {
|
||||||
|
assureCorrectAppLanguage(requireContext());
|
||||||
|
if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
|
||||||
|
// will be saved only on success
|
||||||
|
final Uri lastExportDataUri = result.getData().getData();
|
||||||
|
|
||||||
|
final StoredFileHelper file = new StoredFileHelper(
|
||||||
|
requireContext(), result.getData().getData(), ZIP_MIME_TYPE);
|
||||||
|
|
||||||
|
exportDatabase(file, lastExportDataUri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void requestImportPathResult(final ActivityResult result) {
|
||||||
|
assureCorrectAppLanguage(requireContext());
|
||||||
|
if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
|
||||||
|
// will be saved only on success
|
||||||
|
final Uri lastImportDataUri = result.getData().getData();
|
||||||
|
|
||||||
|
final StoredFileHelper file = new StoredFileHelper(
|
||||||
|
requireContext(), result.getData().getData(), ZIP_MIME_TYPE);
|
||||||
|
|
||||||
|
new androidx.appcompat.app.AlertDialog.Builder(requireActivity())
|
||||||
|
.setMessage(R.string.override_current_data)
|
||||||
|
.setPositiveButton(R.string.ok, (d, id) ->
|
||||||
|
importDatabase(file, lastImportDataUri))
|
||||||
|
.setNegativeButton(R.string.cancel, (d, id) ->
|
||||||
|
d.cancel())
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void exportDatabase(final StoredFileHelper file, final Uri exportDataUri) {
|
||||||
|
try {
|
||||||
|
//checkpoint before export
|
||||||
|
NewPipeDatabase.checkpoint();
|
||||||
|
|
||||||
|
final SharedPreferences preferences = PreferenceManager
|
||||||
|
.getDefaultSharedPreferences(requireContext());
|
||||||
|
manager.exportDatabase(preferences, file);
|
||||||
|
|
||||||
|
saveLastImportExportDataUri(exportDataUri); // save export path only on success
|
||||||
|
Toast.makeText(requireContext(), R.string.export_complete_toast, Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
|
} catch (final Exception e) {
|
||||||
|
ErrorUtil.showUiErrorSnackbar(this, "Exporting database", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importDatabase(final StoredFileHelper file, final Uri importDataUri) {
|
||||||
|
// check if file is supported
|
||||||
|
if (!ZipHelper.isValidZipFile(file)) {
|
||||||
|
Toast.makeText(requireContext(), R.string.no_valid_zip_file, Toast.LENGTH_SHORT)
|
||||||
|
.show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!manager.ensureDbDirectoryExists()) {
|
||||||
|
throw new IOException("Could not create databases dir");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!manager.extractDb(file)) {
|
||||||
|
Toast.makeText(requireContext(), R.string.could_not_import_all_files,
|
||||||
|
Toast.LENGTH_LONG)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if settings file exist, ask if it should be imported.
|
||||||
|
if (manager.extractSettings(file)) {
|
||||||
|
new androidx.appcompat.app.AlertDialog.Builder(requireContext())
|
||||||
|
.setTitle(R.string.import_settings)
|
||||||
|
.setNegativeButton(R.string.cancel, (dialog, which) -> {
|
||||||
|
dialog.dismiss();
|
||||||
|
finishImport(importDataUri);
|
||||||
|
})
|
||||||
|
.setPositiveButton(R.string.ok, (dialog, which) -> {
|
||||||
|
dialog.dismiss();
|
||||||
|
final Context context = requireContext();
|
||||||
|
final SharedPreferences prefs = PreferenceManager
|
||||||
|
.getDefaultSharedPreferences(context);
|
||||||
|
manager.loadSharedPreferences(prefs);
|
||||||
|
cleanImport(context, prefs);
|
||||||
|
finishImport(importDataUri);
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
} else {
|
||||||
|
finishImport(importDataUri);
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
ErrorUtil.showUiErrorSnackbar(this, "Importing database", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove settings that are not supposed to be imported on different devices
|
||||||
|
* and reset them to default values.
|
||||||
|
* @param context the context used for the import
|
||||||
|
* @param prefs the preferences used while running the import
|
||||||
|
*/
|
||||||
|
private void cleanImport(@NonNull final Context context,
|
||||||
|
@NonNull final SharedPreferences prefs) {
|
||||||
|
// Check if media tunnelling needs to be disabled automatically,
|
||||||
|
// if it was disabled automatically in the imported preferences.
|
||||||
|
final String tunnelingKey = context.getString(R.string.disable_media_tunneling_key);
|
||||||
|
final String automaticTunnelingKey =
|
||||||
|
context.getString(R.string.disabled_media_tunneling_automatically_key);
|
||||||
|
// R.string.disable_media_tunneling_key should always be true
|
||||||
|
// if R.string.disabled_media_tunneling_automatically_key equals 1,
|
||||||
|
// but we double check here just to be sure and to avoid regressions
|
||||||
|
// caused by possible later modification of the media tunneling functionality.
|
||||||
|
// R.string.disabled_media_tunneling_automatically_key == 0:
|
||||||
|
// automatic value overridden by user in settings
|
||||||
|
// R.string.disabled_media_tunneling_automatically_key == -1: not set
|
||||||
|
final boolean wasMediaTunnelingDisabledAutomatically =
|
||||||
|
prefs.getInt(automaticTunnelingKey, -1) == 1
|
||||||
|
&& prefs.getBoolean(tunnelingKey, false);
|
||||||
|
if (wasMediaTunnelingDisabledAutomatically) {
|
||||||
|
prefs.edit()
|
||||||
|
.putInt(automaticTunnelingKey, -1)
|
||||||
|
.putBoolean(tunnelingKey, false)
|
||||||
|
.apply();
|
||||||
|
NewPipeSettings.setMediaTunneling(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save import path and restart system.
|
||||||
|
*
|
||||||
|
* @param importDataUri The import path to save
|
||||||
|
*/
|
||||||
|
private void finishImport(final Uri importDataUri) {
|
||||||
|
// save import path only on success
|
||||||
|
saveLastImportExportDataUri(importDataUri);
|
||||||
|
// restart app to properly load db
|
||||||
|
NavigationHelper.restartApp(requireActivity());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Uri getImportExportDataUri() {
|
||||||
|
final String path = defaultPreferences.getString(importExportDataPathKey, null);
|
||||||
|
return isBlank(path) ? null : Uri.parse(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveLastImportExportDataUri(final Uri importExportDataUri) {
|
||||||
|
final SharedPreferences.Editor editor = defaultPreferences.edit()
|
||||||
|
.putString(importExportDataPathKey, importExportDataUri.toString());
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,104 +1,34 @@
|
||||||
package org.schabi.newpipe.settings;
|
package org.schabi.newpipe.settings;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
|
|
||||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.activity.result.ActivityResult;
|
|
||||||
import androidx.activity.result.ActivityResultLauncher;
|
|
||||||
import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceManager;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.DownloaderImpl;
|
import org.schabi.newpipe.DownloaderImpl;
|
||||||
import org.schabi.newpipe.NewPipeDatabase;
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.error.ErrorUtil;
|
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.localization.ContentCountry;
|
import org.schabi.newpipe.extractor.localization.ContentCountry;
|
||||||
import org.schabi.newpipe.extractor.localization.Localization;
|
import org.schabi.newpipe.extractor.localization.Localization;
|
||||||
import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard;
|
|
||||||
import org.schabi.newpipe.streams.io.StoredFileHelper;
|
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
|
||||||
import org.schabi.newpipe.util.PicassoHelper;
|
import org.schabi.newpipe.util.PicassoHelper;
|
||||||
import org.schabi.newpipe.util.ZipHelper;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
public class ContentSettingsFragment extends BasePreferenceFragment {
|
public class ContentSettingsFragment extends BasePreferenceFragment {
|
||||||
private static final String ZIP_MIME_TYPE = "application/zip";
|
|
||||||
|
|
||||||
private final SimpleDateFormat exportDateFormat =
|
|
||||||
new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);
|
|
||||||
|
|
||||||
private ContentSettingsManager manager;
|
|
||||||
|
|
||||||
private String importExportDataPathKey;
|
|
||||||
private String youtubeRestrictedModeEnabledKey;
|
private String youtubeRestrictedModeEnabledKey;
|
||||||
|
|
||||||
private Localization initialSelectedLocalization;
|
private Localization initialSelectedLocalization;
|
||||||
private ContentCountry initialSelectedContentCountry;
|
private ContentCountry initialSelectedContentCountry;
|
||||||
private String initialLanguage;
|
private String initialLanguage;
|
||||||
private final ActivityResultLauncher<Intent> requestImportPathLauncher =
|
|
||||||
registerForActivityResult(new StartActivityForResult(), this::requestImportPathResult);
|
|
||||||
private final ActivityResultLauncher<Intent> requestExportPathLauncher =
|
|
||||||
registerForActivityResult(new StartActivityForResult(), this::requestExportPathResult);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
||||||
final File homeDir = ContextCompat.getDataDir(requireContext());
|
|
||||||
Objects.requireNonNull(homeDir);
|
|
||||||
manager = new ContentSettingsManager(new NewPipeFileLocator(homeDir));
|
|
||||||
manager.deleteSettingsFile();
|
|
||||||
|
|
||||||
importExportDataPathKey = getString(R.string.import_export_data_path);
|
|
||||||
youtubeRestrictedModeEnabledKey = getString(R.string.youtube_restricted_mode_enabled);
|
youtubeRestrictedModeEnabledKey = getString(R.string.youtube_restricted_mode_enabled);
|
||||||
|
|
||||||
addPreferencesFromResourceRegistry();
|
addPreferencesFromResourceRegistry();
|
||||||
|
|
||||||
final Preference importDataPreference = requirePreference(R.string.import_data);
|
|
||||||
importDataPreference.setOnPreferenceClickListener((Preference p) -> {
|
|
||||||
NoFileManagerSafeGuard.launchSafe(
|
|
||||||
requestImportPathLauncher,
|
|
||||||
StoredFileHelper.getPicker(requireContext(),
|
|
||||||
ZIP_MIME_TYPE, getImportExportDataUri()),
|
|
||||||
TAG,
|
|
||||||
getContext()
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
final Preference exportDataPreference = requirePreference(R.string.export_data);
|
|
||||||
exportDataPreference.setOnPreferenceClickListener((final Preference p) -> {
|
|
||||||
NoFileManagerSafeGuard.launchSafe(
|
|
||||||
requestExportPathLauncher,
|
|
||||||
StoredFileHelper.getNewPicker(requireContext(),
|
|
||||||
"NewPipeData-" + exportDateFormat.format(new Date()) + ".zip",
|
|
||||||
ZIP_MIME_TYPE, getImportExportDataUri()),
|
|
||||||
TAG,
|
|
||||||
getContext()
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
initialSelectedLocalization = org.schabi.newpipe.util.Localization
|
initialSelectedLocalization = org.schabi.newpipe.util.Localization
|
||||||
.getPreferredLocalization(requireContext());
|
.getPreferredLocalization(requireContext());
|
||||||
initialSelectedContentCountry = org.schabi.newpipe.util.Localization
|
initialSelectedContentCountry = org.schabi.newpipe.util.Localization
|
||||||
|
@ -154,151 +84,4 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
||||||
NewPipe.setupLocalization(selectedLocalization, selectedContentCountry);
|
NewPipe.setupLocalization(selectedLocalization, selectedContentCountry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void requestExportPathResult(final ActivityResult result) {
|
|
||||||
assureCorrectAppLanguage(getContext());
|
|
||||||
if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
|
|
||||||
// will be saved only on success
|
|
||||||
final Uri lastExportDataUri = result.getData().getData();
|
|
||||||
|
|
||||||
final StoredFileHelper file =
|
|
||||||
new StoredFileHelper(getContext(), result.getData().getData(), ZIP_MIME_TYPE);
|
|
||||||
|
|
||||||
exportDatabase(file, lastExportDataUri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void requestImportPathResult(final ActivityResult result) {
|
|
||||||
assureCorrectAppLanguage(getContext());
|
|
||||||
if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
|
|
||||||
// will be saved only on success
|
|
||||||
final Uri lastImportDataUri = result.getData().getData();
|
|
||||||
|
|
||||||
final StoredFileHelper file =
|
|
||||||
new StoredFileHelper(getContext(), result.getData().getData(), ZIP_MIME_TYPE);
|
|
||||||
|
|
||||||
new AlertDialog.Builder(requireActivity())
|
|
||||||
.setMessage(R.string.override_current_data)
|
|
||||||
.setPositiveButton(R.string.ok, (d, id) ->
|
|
||||||
importDatabase(file, lastImportDataUri))
|
|
||||||
.setNegativeButton(R.string.cancel, (d, id) ->
|
|
||||||
d.cancel())
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void exportDatabase(final StoredFileHelper file, final Uri exportDataUri) {
|
|
||||||
try {
|
|
||||||
//checkpoint before export
|
|
||||||
NewPipeDatabase.checkpoint();
|
|
||||||
|
|
||||||
final SharedPreferences preferences = PreferenceManager
|
|
||||||
.getDefaultSharedPreferences(requireContext());
|
|
||||||
manager.exportDatabase(preferences, file);
|
|
||||||
|
|
||||||
saveLastImportExportDataUri(exportDataUri); // save export path only on success
|
|
||||||
Toast.makeText(getContext(), R.string.export_complete_toast, Toast.LENGTH_SHORT).show();
|
|
||||||
} catch (final Exception e) {
|
|
||||||
ErrorUtil.showUiErrorSnackbar(this, "Exporting database", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void importDatabase(final StoredFileHelper file, final Uri importDataUri) {
|
|
||||||
// check if file is supported
|
|
||||||
if (!ZipHelper.isValidZipFile(file)) {
|
|
||||||
Toast.makeText(getContext(), R.string.no_valid_zip_file, Toast.LENGTH_SHORT)
|
|
||||||
.show();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!manager.ensureDbDirectoryExists()) {
|
|
||||||
throw new IOException("Could not create databases dir");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!manager.extractDb(file)) {
|
|
||||||
Toast.makeText(getContext(), R.string.could_not_import_all_files, Toast.LENGTH_LONG)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if settings file exist, ask if it should be imported.
|
|
||||||
if (manager.extractSettings(file)) {
|
|
||||||
new AlertDialog.Builder(requireContext())
|
|
||||||
.setTitle(R.string.import_settings)
|
|
||||||
.setNegativeButton(R.string.cancel, (dialog, which) -> {
|
|
||||||
dialog.dismiss();
|
|
||||||
finishImport(importDataUri);
|
|
||||||
})
|
|
||||||
.setPositiveButton(R.string.ok, (dialog, which) -> {
|
|
||||||
dialog.dismiss();
|
|
||||||
final Context context = requireContext();
|
|
||||||
final SharedPreferences prefs = PreferenceManager
|
|
||||||
.getDefaultSharedPreferences(context);
|
|
||||||
manager.loadSharedPreferences(prefs);
|
|
||||||
cleanImport(context, prefs);
|
|
||||||
finishImport(importDataUri);
|
|
||||||
})
|
|
||||||
.show();
|
|
||||||
} else {
|
|
||||||
finishImport(importDataUri);
|
|
||||||
}
|
|
||||||
} catch (final Exception e) {
|
|
||||||
ErrorUtil.showUiErrorSnackbar(this, "Importing database", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove settings that are not supposed to be imported on different devices
|
|
||||||
* and reset them to default values.
|
|
||||||
* @param context the context used for the import
|
|
||||||
* @param prefs the preferences used while running the import
|
|
||||||
*/
|
|
||||||
private void cleanImport(@NonNull final Context context,
|
|
||||||
@NonNull final SharedPreferences prefs) {
|
|
||||||
// Check if media tunnelling needs to be disabled automatically,
|
|
||||||
// if it was disabled automatically in the imported preferences.
|
|
||||||
final String tunnelingKey = context.getString(R.string.disable_media_tunneling_key);
|
|
||||||
final String automaticTunnelingKey =
|
|
||||||
context.getString(R.string.disabled_media_tunneling_automatically_key);
|
|
||||||
// R.string.disable_media_tunneling_key should always be true
|
|
||||||
// if R.string.disabled_media_tunneling_automatically_key equals 1,
|
|
||||||
// but we double check here just to be sure and to avoid regressions
|
|
||||||
// caused by possible later modification of the media tunneling functionality.
|
|
||||||
// R.string.disabled_media_tunneling_automatically_key == 0:
|
|
||||||
// automatic value overridden by user in settings
|
|
||||||
// R.string.disabled_media_tunneling_automatically_key == -1: not set
|
|
||||||
final boolean wasMediaTunnelingDisabledAutomatically =
|
|
||||||
prefs.getInt(automaticTunnelingKey, -1) == 1
|
|
||||||
&& prefs.getBoolean(tunnelingKey, false);
|
|
||||||
if (wasMediaTunnelingDisabledAutomatically) {
|
|
||||||
prefs.edit()
|
|
||||||
.putInt(automaticTunnelingKey, -1)
|
|
||||||
.putBoolean(tunnelingKey, false)
|
|
||||||
.apply();
|
|
||||||
NewPipeSettings.setMediaTunneling(context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save import path and restart system.
|
|
||||||
*
|
|
||||||
* @param importDataUri The import path to save
|
|
||||||
*/
|
|
||||||
private void finishImport(final Uri importDataUri) {
|
|
||||||
// save import path only on success
|
|
||||||
saveLastImportExportDataUri(importDataUri);
|
|
||||||
// restart app to properly load db
|
|
||||||
NavigationHelper.restartApp(requireActivity());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Uri getImportExportDataUri() {
|
|
||||||
final String path = defaultPreferences.getString(importExportDataPathKey, null);
|
|
||||||
return isBlank(path) ? null : Uri.parse(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveLastImportExportDataUri(final Uri importExportDataUri) {
|
|
||||||
final SharedPreferences.Editor editor = defaultPreferences.edit()
|
|
||||||
.putString(importExportDataPathKey, importExportDataUri.toString());
|
|
||||||
editor.apply();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,15 @@
|
||||||
package org.schabi.newpipe.settings;
|
package org.schabi.newpipe.settings;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.PreferenceManager;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.error.ErrorInfo;
|
import org.schabi.newpipe.error.ErrorInfo;
|
||||||
import org.schabi.newpipe.error.ErrorUtil;
|
import org.schabi.newpipe.error.ErrorUtil;
|
||||||
import org.schabi.newpipe.error.UserAction;
|
import org.schabi.newpipe.error.UserAction;
|
||||||
import org.schabi.newpipe.local.feed.notifications.NotificationWorker;
|
import org.schabi.newpipe.local.feed.notifications.NotificationWorker;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
|
||||||
import org.schabi.newpipe.util.PicassoHelper;
|
import org.schabi.newpipe.util.PicassoHelper;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -39,8 +35,6 @@ public class DebugSettingsFragment extends BasePreferenceFragment {
|
||||||
findPreference(getString(R.string.show_error_snackbar_key));
|
findPreference(getString(R.string.show_error_snackbar_key));
|
||||||
final Preference createErrorNotificationPreference =
|
final Preference createErrorNotificationPreference =
|
||||||
findPreference(getString(R.string.create_error_notification_key));
|
findPreference(getString(R.string.create_error_notification_key));
|
||||||
final Preference resetSettings =
|
|
||||||
findPreference(getString(R.string.reset_settings));
|
|
||||||
|
|
||||||
assert allowHeapDumpingPreference != null;
|
assert allowHeapDumpingPreference != null;
|
||||||
assert showMemoryLeaksPreference != null;
|
assert showMemoryLeaksPreference != null;
|
||||||
|
@ -92,32 +86,6 @@ public class DebugSettingsFragment extends BasePreferenceFragment {
|
||||||
new ErrorInfo(new RuntimeException(DUMMY), UserAction.UI_ERROR, DUMMY));
|
new ErrorInfo(new RuntimeException(DUMMY), UserAction.UI_ERROR, DUMMY));
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Resets all settings by deleting shared preference and restarting the app
|
|
||||||
// A dialogue will pop up to confirm if user intends to reset all settings
|
|
||||||
assert resetSettings != null;
|
|
||||||
resetSettings.setOnPreferenceClickListener(preference -> {
|
|
||||||
// Show Alert Dialogue
|
|
||||||
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
|
||||||
builder.setMessage(R.string.reset_all_settings);
|
|
||||||
builder.setCancelable(true);
|
|
||||||
builder.setPositiveButton(R.string.ok, (dialogInterface, i) -> {
|
|
||||||
// Deletes all shared preferences xml files.
|
|
||||||
final SharedPreferences sharedPreferences =
|
|
||||||
PreferenceManager.getDefaultSharedPreferences(requireContext());
|
|
||||||
sharedPreferences.edit().clear().apply();
|
|
||||||
// Restarts the app
|
|
||||||
if (getActivity() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NavigationHelper.restartApp(getActivity());
|
|
||||||
});
|
|
||||||
builder.setNegativeButton(R.string.cancel, (dialogInterface, i) -> {
|
|
||||||
});
|
|
||||||
final AlertDialog alertDialog = builder.create();
|
|
||||||
alertDialog.show();
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -63,6 +63,7 @@ public final class NewPipeSettings {
|
||||||
PreferenceManager.setDefaultValues(context, R.xml.player_notification_settings, true);
|
PreferenceManager.setDefaultValues(context, R.xml.player_notification_settings, true);
|
||||||
PreferenceManager.setDefaultValues(context, R.xml.update_settings, true);
|
PreferenceManager.setDefaultValues(context, R.xml.update_settings, true);
|
||||||
PreferenceManager.setDefaultValues(context, R.xml.debug_settings, true);
|
PreferenceManager.setDefaultValues(context, R.xml.debug_settings, true);
|
||||||
|
PreferenceManager.setDefaultValues(context, R.xml.backup_restore_settings, true);
|
||||||
|
|
||||||
saveDefaultVideoDownloadDirectory(context);
|
saveDefaultVideoDownloadDirectory(context);
|
||||||
saveDefaultAudioDownloadDirectory(context);
|
saveDefaultAudioDownloadDirectory(context);
|
||||||
|
|
|
@ -41,6 +41,7 @@ public final class SettingsResourceRegistry {
|
||||||
add(UpdateSettingsFragment.class, R.xml.update_settings);
|
add(UpdateSettingsFragment.class, R.xml.update_settings);
|
||||||
add(VideoAudioSettingsFragment.class, R.xml.video_audio_settings);
|
add(VideoAudioSettingsFragment.class, R.xml.video_audio_settings);
|
||||||
add(ExoPlayerSettingsFragment.class, R.xml.exoplayer_settings);
|
add(ExoPlayerSettingsFragment.class, R.xml.exoplayer_settings);
|
||||||
|
add(BackupRestoreSettingsFragment.class, R.xml.backup_restore_settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
private SettingRegistryEntry add(
|
private SettingRegistryEntry add(
|
||||||
|
|
|
@ -223,7 +223,6 @@
|
||||||
<string name="prefer_descriptive_audio_key">prefer_descriptive_audio</string>
|
<string name="prefer_descriptive_audio_key">prefer_descriptive_audio</string>
|
||||||
<string name="last_resize_mode">last_resize_mode</string>
|
<string name="last_resize_mode">last_resize_mode</string>
|
||||||
|
|
||||||
<!-- RESET ONLY -->
|
|
||||||
<string name="reset_settings">reset_settings</string>
|
<string name="reset_settings">reset_settings</string>
|
||||||
|
|
||||||
<!-- DEBUG ONLY -->
|
<!-- DEBUG ONLY -->
|
||||||
|
|
|
@ -155,6 +155,7 @@
|
||||||
<string name="settings_category_updates_title">Updates</string>
|
<string name="settings_category_updates_title">Updates</string>
|
||||||
<string name="settings_category_player_notification_title">Player notification</string>
|
<string name="settings_category_player_notification_title">Player notification</string>
|
||||||
<string name="settings_category_player_notification_summary">Configure current playing stream notification</string>
|
<string name="settings_category_player_notification_summary">Configure current playing stream notification</string>
|
||||||
|
<string name="settings_category_backup_restore_title">Backup and restore</string>
|
||||||
<string name="background_player_playing_toast">Playing in background</string>
|
<string name="background_player_playing_toast">Playing in background</string>
|
||||||
<string name="popup_playing_toast">Playing in popup mode</string>
|
<string name="popup_playing_toast">Playing in popup mode</string>
|
||||||
<string name="content">Content</string>
|
<string name="content">Content</string>
|
||||||
|
|
24
app/src/main/res/xml/backup_restore_settings.xml
Normal file
24
app/src/main/res/xml/backup_restore_settings.xml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<?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"
|
||||||
|
android:title="@string/settings_category_backup_restore_title">
|
||||||
|
<Preference
|
||||||
|
android:key="@string/import_data"
|
||||||
|
android:summary="@string/import_data_summary"
|
||||||
|
android:title="@string/import_data_title"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="@string/export_data"
|
||||||
|
android:summary="@string/export_data_summary"
|
||||||
|
android:title="@string/export_data_title"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="@string/reset_settings"
|
||||||
|
android:title="@string/settings_category_reset_title"
|
||||||
|
app:singleLineTitle="false"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
</PreferenceScreen>
|
|
@ -124,20 +124,6 @@
|
||||||
app:singleLineTitle="false"
|
app:singleLineTitle="false"
|
||||||
app:iconSpaceReserved="false" />
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="@string/import_data"
|
|
||||||
android:summary="@string/import_data_summary"
|
|
||||||
android:title="@string/import_data_title"
|
|
||||||
app:singleLineTitle="false"
|
|
||||||
app:iconSpaceReserved="false" />
|
|
||||||
|
|
||||||
<Preference
|
|
||||||
android:key="@string/export_data"
|
|
||||||
android:summary="@string/export_data_summary"
|
|
||||||
android:title="@string/export_data_title"
|
|
||||||
app:singleLineTitle="false"
|
|
||||||
app:iconSpaceReserved="false" />
|
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:layout="@layout/settings_category_header_layout"
|
android:layout="@layout/settings_category_header_layout"
|
||||||
android:title="@string/settings_category_feed_title"
|
android:title="@string/settings_category_feed_title"
|
||||||
|
|
|
@ -71,9 +71,4 @@
|
||||||
android:title="@string/create_error_notification"
|
android:title="@string/create_error_notification"
|
||||||
app:singleLineTitle="false"
|
app:singleLineTitle="false"
|
||||||
app:iconSpaceReserved="false" />
|
app:iconSpaceReserved="false" />
|
||||||
<Preference
|
|
||||||
android:key="@string/reset_settings"
|
|
||||||
android:title="@string/settings_category_reset_title"
|
|
||||||
app:singleLineTitle="false"
|
|
||||||
app:iconSpaceReserved="false" />
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
|
|
@ -47,6 +47,12 @@
|
||||||
android:title="@string/settings_category_updates_title"
|
android:title="@string/settings_category_updates_title"
|
||||||
app:iconSpaceReserved="false" />
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
android:fragment="org.schabi.newpipe.settings.BackupRestoreSettingsFragment"
|
||||||
|
android:icon="@drawable/ic_settings_backup_restore"
|
||||||
|
android:title="@string/settings_category_backup_restore_title"
|
||||||
|
app:iconSpaceReserved="false" />
|
||||||
|
|
||||||
<PreferenceScreen
|
<PreferenceScreen
|
||||||
android:fragment="org.schabi.newpipe.settings.DebugSettingsFragment"
|
android:fragment="org.schabi.newpipe.settings.DebugSettingsFragment"
|
||||||
android:icon="@drawable/ic_bug_report"
|
android:icon="@drawable/ic_bug_report"
|
||||||
|
|
Loading…
Reference in a new issue