Add option to import and option to export app preferences
This commit is contained in:
parent
874a17e515
commit
82cd8ea239
6 changed files with 181 additions and 0 deletions
|
@ -1,9 +1,11 @@
|
|||
package eu.siacs.conversations.ui.fragment.settings;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
@ -30,14 +32,27 @@ import com.google.common.primitives.Longs;
|
|||
import eu.siacs.conversations.Config;
|
||||
import eu.siacs.conversations.R;
|
||||
import eu.siacs.conversations.persistance.FileBackend;
|
||||
import eu.siacs.conversations.ui.activity.SettingsActivity;
|
||||
import eu.siacs.conversations.utils.ChatBackgroundHelper;
|
||||
import eu.siacs.conversations.worker.ExportBackupWorker;
|
||||
import me.drakeet.support.toast.ToastCompat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectOutputStream;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class BackupSettingsFragment extends XmppPreferenceFragment {
|
||||
|
||||
public static final String CREATE_ONE_OFF_BACKUP = "create_one_off_backup";
|
||||
private static final String RECURRING_BACKUP = "recurring_backup";
|
||||
public static final int REQUEST_EXPORT_SETTINGS = 0xbf8701;
|
||||
public static final int REQUEST_IMPORT_SETTINGS = 0xbf8703;
|
||||
|
||||
private final ActivityResultLauncher<String> requestStorageForBackupLauncher =
|
||||
registerForActivityResult(
|
||||
|
@ -75,6 +90,26 @@ public class BackupSettingsFragment extends XmppPreferenceFragment {
|
|||
recurringBackup,
|
||||
R.array.recurring_backup_values,
|
||||
value -> timeframeValueToName(requireContext(), value));
|
||||
|
||||
final var importSettingsPreference = findPreference("import_settings");
|
||||
if (importSettingsPreference != null) {
|
||||
importSettingsPreference.setOnPreferenceClickListener(preference -> {
|
||||
if (requireSettingsActivity().hasStoragePermission(REQUEST_IMPORT_SETTINGS)) {
|
||||
importSettings();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
final var exportSettingsPreference = findPreference("export_settings");
|
||||
if (exportSettingsPreference != null) {
|
||||
exportSettingsPreference.setOnPreferenceClickListener(preference -> {
|
||||
if (requireSettingsActivity().hasStoragePermission(REQUEST_EXPORT_SETTINGS)) {
|
||||
exportSettings();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -128,6 +163,27 @@ public class BackupSettingsFragment extends XmppPreferenceFragment {
|
|||
requireActivity().setTitle(R.string.backup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (grantResults.length > 0) {
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
if (requestCode == REQUEST_EXPORT_SETTINGS) {
|
||||
exportSettings();
|
||||
}
|
||||
if (requestCode == REQUEST_IMPORT_SETTINGS) {
|
||||
importSettings();
|
||||
}
|
||||
} else {
|
||||
ToastCompat.makeText(
|
||||
requireActivity(),
|
||||
|
||||
R.string.no_storage_permission,
|
||||
ToastCompat.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean onBackupPreferenceClicked(final Preference preference) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
if (ContextCompat.checkSelfPermission(
|
||||
|
@ -157,4 +213,93 @@ public class BackupSettingsFragment extends XmppPreferenceFragment {
|
|||
builder.setPositiveButton(R.string.ok, null);
|
||||
builder.create().show();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
private boolean importSettings() {
|
||||
boolean success;
|
||||
ObjectInputStream input = null;
|
||||
try {
|
||||
final File file = new File(FileBackend.getBackupDirectory(requireContext()).getAbsolutePath() + "/settings.dat");
|
||||
input = new ObjectInputStream(new FileInputStream(file));
|
||||
SharedPreferences.Editor prefEdit = PreferenceManager.getDefaultSharedPreferences(requireSettingsActivity()).edit();
|
||||
prefEdit.clear();
|
||||
Map<String, ?> entries = (Map<String, ?>) input.readObject();
|
||||
for (Map.Entry<String, ?> entry : entries.entrySet()) {
|
||||
Object value = entry.getValue();
|
||||
String key = entry.getKey();
|
||||
|
||||
if (value instanceof Boolean)
|
||||
prefEdit.putBoolean(key, ((Boolean) value).booleanValue());
|
||||
else if (value instanceof Float)
|
||||
prefEdit.putFloat(key, ((Float) value).floatValue());
|
||||
else if (value instanceof Integer)
|
||||
prefEdit.putInt(key, ((Integer) value).intValue());
|
||||
else if (value instanceof Long)
|
||||
prefEdit.putLong(key, ((Long) value).longValue());
|
||||
else if (value instanceof String)
|
||||
prefEdit.putString(key, ((String) value));
|
||||
}
|
||||
prefEdit.commit();
|
||||
success = true;
|
||||
} catch (Exception e) {
|
||||
success = false;
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (input != null) {
|
||||
input.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
if (success) {
|
||||
new Thread(() -> runOnUiThread(() -> requireActivity().recreate())).start();
|
||||
ToastCompat.makeText(requireActivity(), R.string.success_import_settings, ToastCompat.LENGTH_SHORT).show();
|
||||
} else {
|
||||
ToastCompat.makeText(requireActivity(), R.string.error_import_settings, ToastCompat.LENGTH_SHORT).show();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
private boolean exportSettings() {
|
||||
boolean success = false;
|
||||
ObjectOutputStream output = null;
|
||||
try {
|
||||
final File file = new File(FileBackend.getBackupDirectory(requireContext()).getAbsolutePath(), "settings.dat");
|
||||
final File directory = file.getParentFile();
|
||||
if (directory != null && directory.mkdirs()) {
|
||||
Log.d(Config.LOGTAG, "created backup directory " + directory.getAbsolutePath());
|
||||
}
|
||||
output = new ObjectOutputStream(new FileOutputStream(file));
|
||||
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(requireSettingsActivity());
|
||||
output.writeObject(pref.getAll());
|
||||
success = true;
|
||||
} catch (FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (output != null) {
|
||||
output.flush();
|
||||
output.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
public SettingsActivity requireSettingsActivity() {
|
||||
final var activity = requireActivity();
|
||||
if (activity instanceof SettingsActivity settingsActivity) {
|
||||
return settingsActivity;
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
String.format(
|
||||
"%s is not %s",
|
||||
activity.getClass().getName(), SettingsActivity.class.getName()));
|
||||
}
|
||||
}
|
||||
|
|
5
src/main/res/drawable/outline_reset_wrench_24.xml
Normal file
5
src/main/res/drawable/outline_reset_wrench_24.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="?colorControlNormal" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M653,752L565,840L480,755L568,667Q564,656 562,644Q560,632 560,620Q560,562 601,521Q642,480 700,480Q718,480 735,484.5Q752,489 767,497L672,592L728,648L823,554Q831,569 835.5,585.5Q840,602 840,620Q840,678 799,719Q758,760 700,760Q687,760 675.5,758Q664,756 653,752ZM831,400L748,400Q722,312 649,256Q576,200 480,200Q363,200 281.5,281.5Q200,363 200,480Q200,552 232.5,612Q265,672 320,710L320,600L400,600L400,840L160,840L160,760L254,760Q192,710 156,637.5Q120,565 120,480Q120,405 148.5,339.5Q177,274 225.5,225.5Q274,177 339.5,148.5Q405,120 480,120Q609,120 706.5,199.5Q804,279 831,400Z"/>
|
||||
|
||||
</vector>
|
5
src/main/res/drawable/rounded_settings_b_roll_24.xml
Normal file
5
src/main/res/drawable/rounded_settings_b_roll_24.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:tint="?colorControlNormal" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M723,700L666,758Q660,764 660,772Q660,780 666,786Q672,792 680,792Q688,792 694,786L772,708Q784,696 784,680Q784,664 772,652L694,574Q688,568 680,568Q672,568 666,574Q660,580 660,588Q660,596 666,602L724,660L580,660Q572,660 566,666Q560,672 560,680Q560,688 566,694Q572,700 580,700L723,700ZM680,880Q597,880 538.5,821.5Q480,763 480,680Q480,597 538.5,538.5Q597,480 680,480Q763,480 821.5,538.5Q880,597 880,680Q880,763 821.5,821.5Q763,880 680,880ZM423,880Q396,880 381.5,862Q367,844 363,818L354,752Q341,747 329.5,740Q318,733 307,725L245,751Q220,762 195,753Q170,744 156,721L109,639Q95,616 101,590Q107,564 128,547L181,507Q180,500 180,493.5Q180,487 180,480Q180,473 180,466.5Q180,460 181,453L128,413Q107,396 101,370Q95,344 109,321L156,239Q170,216 195,207Q220,198 245,209L307,235Q318,227 330,220Q342,213 354,208L363,142Q367,116 386.5,98Q406,80 433,80L527,80Q554,80 573.5,98Q593,116 597,142L606,208Q619,213 630.5,220Q642,227 653,235L715,209Q740,198 765,207Q790,216 804,239L851,321Q865,344 859,370Q853,396 832,413L808,431Q795,442 779,439.5Q763,437 752,424Q741,411 743,395Q745,379 758,368L777,354L738,286L639,328Q617,305 590.5,289.5Q564,274 533,266L520,160L441,160L427,266Q396,274 369.5,289.5Q343,305 321,327L222,286L183,354L269,418Q264,433 262,448Q260,463 260,480Q260,496 262,511Q264,526 269,541L183,606L222,674L321,632Q338,649 357.5,662.5Q377,676 400,685Q401,729 414.5,768.5Q428,808 451,841Q459,853 450,866.5Q441,880 423,880ZM480,480L480,480L480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480ZM480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480Q480,480 480,480ZM482,340Q424,340 383,380.5Q342,421 342,480Q342,501 348,521Q354,541 366,559Q377,574 394.5,578Q412,582 426,571Q440,561 442.5,544.5Q445,528 434,516Q428,508 425,499.5Q422,491 422,480Q422,455 439.5,437.5Q457,420 482,420Q492,420 501.5,423.5Q511,427 519,433Q531,442 546,439.5Q561,437 571,423Q581,409 577.5,392Q574,375 560,364Q546,352 526,346Q506,340 482,340Z"/>
|
||||
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="?colorControlNormal" android:viewportHeight="960" android:viewportWidth="960" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M480,840Q354,840 257,763.5Q160,687 131,568Q127,553 137,540.5Q147,528 164,526Q180,524 193,532Q206,540 211,556Q235,646 310,703Q385,760 480,760Q597,760 678.5,678.5Q760,597 760,480Q760,363 678.5,281.5Q597,200 480,200Q411,200 351,232Q291,264 250,320L320,320Q337,320 348.5,331.5Q360,343 360,360Q360,377 348.5,388.5Q337,400 320,400L160,400Q143,400 131.5,388.5Q120,377 120,360L120,200Q120,183 131.5,171.5Q143,160 160,160Q177,160 188.5,171.5Q200,183 200,200L200,254Q251,190 324.5,155Q398,120 480,120Q555,120 620.5,148.5Q686,177 734.5,225.5Q783,274 811.5,339.5Q840,405 840,480Q840,555 811.5,620.5Q783,686 734.5,734.5Q686,783 620.5,811.5Q555,840 480,840ZM480,560Q447,560 423.5,536.5Q400,513 400,480Q400,447 423.5,423.5Q447,400 480,400Q513,400 536.5,423.5Q560,447 560,480Q560,513 536.5,536.5Q513,560 480,560Z"/>
|
||||
|
||||
</vector>
|
|
@ -1320,4 +1320,11 @@
|
|||
<string name="pref_reset_dns_server_summary">Reset the default DNS servers</string>
|
||||
<string name="pref_reset_dns_server_title">Reset DNS</string>
|
||||
<string name="dns_server_reset">DNS reset</string>
|
||||
<string name="pref_category_settings">Settings</string>
|
||||
<string name="pref_import_settings">Import settings</string>
|
||||
<string name="pref_import_settings_summary">Import the settings.dat from the backup folder</string>
|
||||
<string name="pref_export_settings">Export settings</string>
|
||||
<string name="pref_export_settings_summary">Export the monocles chat app settings to the backup folder</string>
|
||||
<string name="success_import_settings">Settings successfully imported</string>
|
||||
<string name="error_import_settings">Error while importing the settings</string>
|
||||
</resources>
|
|
@ -17,4 +17,18 @@
|
|||
android:key="backup_directory"
|
||||
android:summary="@string/pref_create_backup_summary" />
|
||||
|
||||
<PreferenceCategory
|
||||
android:title="@string/pref_category_settings">
|
||||
<Preference
|
||||
android:icon="@drawable/rounded_settings_backup_restore_24"
|
||||
android:key="import_settings"
|
||||
android:summary="@string/pref_import_settings_summary"
|
||||
android:title="@string/pref_import_settings" />
|
||||
<Preference
|
||||
android:icon="@drawable/rounded_settings_b_roll_24"
|
||||
android:key="export_settings"
|
||||
android:summary="@string/pref_export_settings_summary"
|
||||
android:title="@string/pref_export_settings" />
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
Loading…
Reference in a new issue