Support SAF properly
This commit is contained in:
parent
1e09a1768e
commit
0f75024e03
23 changed files with 451 additions and 311 deletions
|
|
@ -2,13 +2,15 @@ package org.schabi.newpipe.settings;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.preference.Preference;
|
||||
|
|
@ -29,10 +31,14 @@ import org.schabi.newpipe.util.FilePickerActivityHelper;
|
|||
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 us.shandian.giga.io.StoredDirectoryHelper;
|
||||
import us.shandian.giga.io.StoredFileHelper;
|
||||
|
||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||
|
||||
public class ContentSettingsFragment extends BasePreferenceFragment {
|
||||
|
|
@ -57,24 +63,15 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||
addPreferencesFromResource(R.xml.content_settings);
|
||||
|
||||
final Preference importDataPreference = findPreference(getString(R.string.import_data));
|
||||
importDataPreference.setOnPreferenceClickListener(p -> {
|
||||
final Intent i = new Intent(getActivity(), FilePickerActivityHelper.class)
|
||||
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
|
||||
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, false)
|
||||
.putExtra(FilePickerActivityHelper.EXTRA_MODE,
|
||||
FilePickerActivityHelper.MODE_FILE);
|
||||
startActivityForResult(i, REQUEST_IMPORT_PATH);
|
||||
importDataPreference.setOnPreferenceClickListener((Preference p) -> {
|
||||
startActivityForResult(StoredFileHelper.getPicker(getContext()), REQUEST_IMPORT_PATH);
|
||||
return true;
|
||||
});
|
||||
|
||||
final Preference exportDataPreference = findPreference(getString(R.string.export_data));
|
||||
exportDataPreference.setOnPreferenceClickListener(p -> {
|
||||
final Intent i = new Intent(getActivity(), FilePickerActivityHelper.class)
|
||||
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
|
||||
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, true)
|
||||
.putExtra(FilePickerActivityHelper.EXTRA_MODE,
|
||||
FilePickerActivityHelper.MODE_DIR);
|
||||
startActivityForResult(i, REQUEST_EXPORT_PATH);
|
||||
exportDataPreference.setOnPreferenceClickListener((final Preference p) -> {
|
||||
startActivityForResult(StoredDirectoryHelper.getPicker(getContext()),
|
||||
REQUEST_EXPORT_PATH);
|
||||
return true;
|
||||
});
|
||||
|
||||
|
|
@ -89,7 +86,6 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||
.getDefaultSharedPreferences(requireContext()).getString("app_language_key", "en");
|
||||
|
||||
final Preference clearCookiePref = findPreference(getString(R.string.clear_cookie_key));
|
||||
|
||||
clearCookiePref.setOnPreferenceClickListener(preference -> {
|
||||
defaultPreferences.edit()
|
||||
.putString(getString(R.string.recaptcha_cookies_key), "").apply();
|
||||
|
|
@ -152,7 +148,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||
|
||||
@Override
|
||||
public void onActivityResult(final int requestCode, final int resultCode,
|
||||
@NonNull final Intent data) {
|
||||
@Nullable final Intent data) {
|
||||
assureCorrectAppLanguage(getContext());
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (DEBUG) {
|
||||
|
|
@ -163,31 +159,44 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||
}
|
||||
|
||||
if ((requestCode == REQUEST_IMPORT_PATH || requestCode == REQUEST_EXPORT_PATH)
|
||||
&& resultCode == Activity.RESULT_OK && data.getData() != null) {
|
||||
final String path = Utils.getFileForUri(data.getData()).getAbsolutePath();
|
||||
if (requestCode == REQUEST_EXPORT_PATH) {
|
||||
final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);
|
||||
exportDatabase(path + "/NewPipeData-" + sdf.format(new Date()) + ".zip");
|
||||
} else {
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
|
||||
builder.setMessage(R.string.override_current_data)
|
||||
.setPositiveButton(getString(R.string.finish),
|
||||
(d, id) -> importDatabase(path))
|
||||
.setNegativeButton(android.R.string.cancel,
|
||||
(d, id) -> d.cancel());
|
||||
builder.create().show();
|
||||
&& resultCode == Activity.RESULT_OK && data != null && data.getData() != null) {
|
||||
try {
|
||||
Uri uri = data.getData();
|
||||
if (FilePickerActivityHelper.isOwnFileUri(requireContext(), uri)) {
|
||||
uri = Uri.fromFile(Utils.getFileForUri(uri));
|
||||
}
|
||||
if (requestCode == REQUEST_EXPORT_PATH) {
|
||||
final StoredDirectoryHelper directory
|
||||
= new StoredDirectoryHelper(requireContext(), uri, null);
|
||||
final SimpleDateFormat sdf
|
||||
= new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);
|
||||
exportDatabase(directory.createFile("NewPipeData-"
|
||||
+ sdf.format(new Date()) + ".zip", "application/zip"));
|
||||
} else {
|
||||
final StoredFileHelper file = new StoredFileHelper(getContext(), uri,
|
||||
StoredFileHelper.DEFAULT_MIME);
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
|
||||
builder.setMessage(R.string.override_current_data)
|
||||
.setPositiveButton(R.string.finish,
|
||||
(DialogInterface d, int id) -> importDatabase(file))
|
||||
.setNegativeButton(R.string.cancel,
|
||||
(DialogInterface d, int id) -> d.cancel());
|
||||
builder.create().show();
|
||||
}
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void exportDatabase(final String path) {
|
||||
private void exportDatabase(final StoredFileHelper file) {
|
||||
try {
|
||||
//checkpoint before export
|
||||
NewPipeDatabase.checkpoint();
|
||||
|
||||
final SharedPreferences preferences = PreferenceManager
|
||||
.getDefaultSharedPreferences(requireContext());
|
||||
manager.exportDatabase(preferences, path);
|
||||
manager.exportDatabase(preferences, file);
|
||||
|
||||
Toast.makeText(getContext(), R.string.export_complete_toast, Toast.LENGTH_SHORT).show();
|
||||
} catch (final Exception e) {
|
||||
|
|
@ -195,9 +204,9 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||
}
|
||||
}
|
||||
|
||||
private void importDatabase(final String filePath) {
|
||||
private void importDatabase(final StoredFileHelper file) {
|
||||
// check if file is supported
|
||||
if (!ZipHelper.isValidZipFile(filePath)) {
|
||||
if (!ZipHelper.isValidZipFile(file)) {
|
||||
Toast.makeText(getContext(), R.string.no_valid_zip_file, Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
return;
|
||||
|
|
@ -208,13 +217,13 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||
throw new Exception("Could not create databases dir");
|
||||
}
|
||||
|
||||
if (!manager.extractDb(filePath)) {
|
||||
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(filePath)) {
|
||||
if (manager.extractSettings(file)) {
|
||||
final AlertDialog.Builder alert = new AlertDialog.Builder(requireContext());
|
||||
alert.setTitle(R.string.import_settings);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
package org.schabi.newpipe.settings
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import org.schabi.newpipe.streams.io.SharpOutputStream
|
||||
import org.schabi.newpipe.util.ZipHelper
|
||||
import us.shandian.giga.io.StoredFileHelper
|
||||
import java.io.BufferedOutputStream
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
|
|
@ -17,8 +19,9 @@ class ContentSettingsManager(private val fileLocator: NewPipeFileLocator) {
|
|||
* It also creates the file.
|
||||
*/
|
||||
@Throws(Exception::class)
|
||||
fun exportDatabase(preferences: SharedPreferences, outputPath: String) {
|
||||
ZipOutputStream(BufferedOutputStream(FileOutputStream(outputPath)))
|
||||
fun exportDatabase(preferences: SharedPreferences, file: StoredFileHelper) {
|
||||
file.create()
|
||||
ZipOutputStream(BufferedOutputStream(SharpOutputStream(file.stream)))
|
||||
.use { outZip ->
|
||||
ZipHelper.addFileToZip(outZip, fileLocator.db.path, "newpipe.db")
|
||||
|
||||
|
|
@ -48,8 +51,8 @@ class ContentSettingsManager(private val fileLocator: NewPipeFileLocator) {
|
|||
return fileLocator.dbDir.exists() || fileLocator.dbDir.mkdir()
|
||||
}
|
||||
|
||||
fun extractDb(filePath: String): Boolean {
|
||||
val success = ZipHelper.extractFileFromZip(filePath, fileLocator.db.path, "newpipe.db")
|
||||
fun extractDb(file: StoredFileHelper): Boolean {
|
||||
val success = ZipHelper.extractFileFromZip(file, fileLocator.db.path, "newpipe.db")
|
||||
if (success) {
|
||||
fileLocator.dbJournal.delete()
|
||||
fileLocator.dbWal.delete()
|
||||
|
|
@ -59,9 +62,8 @@ class ContentSettingsManager(private val fileLocator: NewPipeFileLocator) {
|
|||
return success
|
||||
}
|
||||
|
||||
fun extractSettings(filePath: String): Boolean {
|
||||
return ZipHelper
|
||||
.extractFileFromZip(filePath, fileLocator.settings.path, "newpipe.settings")
|
||||
fun extractSettings(file: StoredFileHelper): Boolean {
|
||||
return ZipHelper.extractFileFromZip(file, fileLocator.settings.path, "newpipe.settings")
|
||||
}
|
||||
|
||||
fun loadSharedPreferences(preferences: SharedPreferences) {
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@ import android.net.Uri;
|
|||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.SwitchPreference;
|
||||
|
||||
import com.nononsenseapps.filepicker.Utils;
|
||||
|
||||
|
|
@ -57,6 +57,14 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
|||
prefPathAudio = findPreference(downloadPathAudioPreference);
|
||||
prefStorageAsk = findPreference(downloadStorageAsk);
|
||||
|
||||
final SwitchPreference prefUseSaf = findPreference(storageUseSafPreference);
|
||||
prefUseSaf.setDefaultValue(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP);
|
||||
prefUseSaf.setChecked(NewPipeSettings.useStorageAccessFramework(ctx));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
|
||||
|| Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
prefUseSaf.setEnabled(false);
|
||||
}
|
||||
|
||||
updatePreferencesSummary();
|
||||
updatePathPickers(!defaultPreferences.getBoolean(downloadStorageAsk, false));
|
||||
|
||||
|
|
@ -177,8 +185,14 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
|||
final int request;
|
||||
|
||||
if (key.equals(storageUseSafPreference)) {
|
||||
Toast.makeText(getContext(), R.string.download_choose_new_path,
|
||||
Toast.LENGTH_LONG).show();
|
||||
if (!NewPipeSettings.useStorageAccessFramework(ctx)) {
|
||||
NewPipeSettings.saveDefaultVideoDownloadDirectory(ctx);
|
||||
NewPipeSettings.saveDefaultAudioDownloadDirectory(ctx);
|
||||
} else {
|
||||
defaultPreferences.edit().putString(downloadPathVideoPreference, null)
|
||||
.putString(downloadPathAudioPreference, null).apply();
|
||||
}
|
||||
updatePreferencesSummary();
|
||||
return true;
|
||||
} else if (key.equals(downloadPathVideoPreference)) {
|
||||
request = REQUEST_DOWNLOAD_VIDEO_PATH;
|
||||
|
|
@ -188,22 +202,7 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
|||
return super.onPreferenceTreeClick(preference);
|
||||
}
|
||||
|
||||
final Intent i;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
||||
&& NewPipeSettings.useStorageAccessFramework(ctx)) {
|
||||
i = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||
.putExtra("android.content.extra.SHOW_ADVANCED", true)
|
||||
.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
|
||||
| StoredDirectoryHelper.PERMISSION_FLAGS);
|
||||
} else {
|
||||
i = new Intent(getActivity(), FilePickerActivityHelper.class)
|
||||
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
|
||||
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, true)
|
||||
.putExtra(FilePickerActivityHelper.EXTRA_MODE,
|
||||
FilePickerActivityHelper.MODE_DIR);
|
||||
}
|
||||
|
||||
startActivityForResult(i, request);
|
||||
startActivityForResult(StoredDirectoryHelper.getPicker(ctx), request);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package org.schabi.newpipe.settings;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
|
@ -12,6 +13,8 @@ import org.schabi.newpipe.R;
|
|||
import java.io.File;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||
|
||||
/*
|
||||
* Created by k3b on 07.01.2016.
|
||||
*
|
||||
|
|
@ -65,32 +68,36 @@ public final class NewPipeSettings {
|
|||
PreferenceManager.setDefaultValues(context, R.xml.update_settings, true);
|
||||
PreferenceManager.setDefaultValues(context, R.xml.debug_settings, true);
|
||||
|
||||
getVideoDownloadFolder(context);
|
||||
getAudioDownloadFolder(context);
|
||||
saveDefaultVideoDownloadDirectory(context);
|
||||
saveDefaultAudioDownloadDirectory(context);
|
||||
|
||||
SettingMigrations.initMigrations(context, isFirstRun);
|
||||
}
|
||||
|
||||
private static void getVideoDownloadFolder(final Context context) {
|
||||
getDir(context, R.string.download_path_video_key, Environment.DIRECTORY_MOVIES);
|
||||
static void saveDefaultVideoDownloadDirectory(final Context context) {
|
||||
saveDefaultDirectory(context, R.string.download_path_video_key,
|
||||
Environment.DIRECTORY_MOVIES);
|
||||
}
|
||||
|
||||
private static void getAudioDownloadFolder(final Context context) {
|
||||
getDir(context, R.string.download_path_audio_key, Environment.DIRECTORY_MUSIC);
|
||||
static void saveDefaultAudioDownloadDirectory(final Context context) {
|
||||
saveDefaultDirectory(context, R.string.download_path_audio_key,
|
||||
Environment.DIRECTORY_MUSIC);
|
||||
}
|
||||
|
||||
private static void getDir(final Context context, final int keyID,
|
||||
final String defaultDirectoryName) {
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
final String key = context.getString(keyID);
|
||||
final String downloadPath = prefs.getString(key, null);
|
||||
if ((downloadPath != null) && (!downloadPath.isEmpty())) {
|
||||
return;
|
||||
private static void saveDefaultDirectory(final Context context, final int keyID,
|
||||
final String defaultDirectoryName) {
|
||||
if (!useStorageAccessFramework(context)) {
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
final String key = context.getString(keyID);
|
||||
final String downloadPath = prefs.getString(key, null);
|
||||
if (!isNullOrEmpty(downloadPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final SharedPreferences.Editor spEditor = prefs.edit();
|
||||
spEditor.putString(key, getNewPipeChildFolderPathForDir(getDir(defaultDirectoryName)));
|
||||
spEditor.apply();
|
||||
}
|
||||
|
||||
final SharedPreferences.Editor spEditor = prefs.edit();
|
||||
spEditor.putString(key, getNewPipeChildFolderPathForDir(getDir(defaultDirectoryName)));
|
||||
spEditor.apply();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
|
@ -103,10 +110,15 @@ public final class NewPipeSettings {
|
|||
}
|
||||
|
||||
public static boolean useStorageAccessFramework(final Context context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
return true;
|
||||
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final String key = context.getString(R.string.storage_use_saf);
|
||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
|
||||
return prefs.getBoolean(key, false);
|
||||
return prefs.getBoolean(key, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package org.schabi.newpipe.settings;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
|
@ -41,11 +40,6 @@ import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
|||
|
||||
public class SettingsActivity extends AppCompatActivity
|
||||
implements BasePreferenceFragment.OnPreferenceStartFragmentCallback {
|
||||
|
||||
public static void initSettings(final Context context) {
|
||||
NewPipeSettings.initSettings(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(final Bundle savedInstanceBundle) {
|
||||
setTheme(ThemeHelper.getSettingsThemeStyle(this));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue