export settings

This commit is contained in:
Thomas 2022-09-06 11:30:19 +02:00
parent 190b800a6e
commit 7f28d208a3
7 changed files with 217 additions and 0 deletions

View file

@ -36,6 +36,8 @@ class SettingsActivity : BaseActivity() {
val navController = findNavController(R.id.fragment_container) val navController = findNavController(R.id.fragment_container)
appBarConfiguration = AppBarConfiguration(navController.graph) appBarConfiguration = AppBarConfiguration(navController.graph)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
setupActionBarWithNavController(navController, appBarConfiguration) setupActionBarWithNavController(navController, appBarConfiguration)
} }

View file

@ -0,0 +1,134 @@
package app.fedilab.android.helper;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Environment;
import androidx.preference.PreferenceManager;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Date;
import java.util.Map;
import app.fedilab.android.R;
//From https://stackoverflow.com/a/10864463
public class SettingsStorage {
public static boolean saveSharedPreferencesToFile(Context context) {
boolean res = false;
ObjectOutputStream output = null;
String fileName = "Fedilab_settings_export_" + Helper.dateFileToString(context, new Date()) + ".txt";
String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
String fullPath = filePath + "/" + fileName;
File dst = new File(fullPath);
try {
output = new ObjectOutputStream(new FileOutputStream(dst));
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
output.writeObject(sharedpreferences.getAll());
res = true;
String message = context.getString(R.string.data_export_theme_success);
Intent intentOpen = new Intent();
intentOpen.setAction(android.content.Intent.ACTION_VIEW);
Uri uri = Uri.parse("file://" + fullPath);
intentOpen.setDataAndType(uri, "text/txt");
String title = context.getString(R.string.data_export_settings);
Helper.notify_user(context, currentAccount, intentOpen, BitmapFactory.decodeResource(context.getResources(),
R.mipmap.ic_launcher), Helper.NotifType.BACKUP, title, message);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (output != null) {
output.flush();
output.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return res;
}
@SuppressLint("ApplySharedPref")
@SuppressWarnings({"unchecked", "UnnecessaryUnboxing"})
public static boolean loadSharedPreferencesFromFile(Context context, File src) {
boolean res = false;
ObjectInputStream input = null;
try {
input = new ObjectInputStream(new FileInputStream(src));
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor prefEdit = sharedpreferences.edit();
prefEdit.clear();
Map<String, ?> entries = (Map<String, ?>) input.readObject();
for (Map.Entry<String, ?> entry : entries.entrySet()) {
Object v = entry.getValue();
String key = entry.getKey();
//We skip some values
if (key.compareTo(Helper.PREF_USER_ID) == 0) {
continue;
}
if (key.compareTo(Helper.PREF_INSTANCE) == 0) {
continue;
}
if (key.compareTo(Helper.PREF_USER_INSTANCE) == 0) {
continue;
}
if (key.compareTo(Helper.PREF_USER_TOKEN) == 0) {
continue;
}
if (v instanceof Boolean)
prefEdit.putBoolean(key, ((Boolean) v).booleanValue());
else if (v instanceof Float)
prefEdit.putFloat(key, ((Float) v).floatValue());
else if (v instanceof Integer)
prefEdit.putInt(key, ((Integer) v).intValue());
else if (v instanceof Long)
prefEdit.putLong(key, ((Long) v).longValue());
else if (v instanceof String)
prefEdit.putString(key, ((String) v));
}
prefEdit.commit();
res = true;
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if (input != null) {
input.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
return res;
}
}

View file

@ -14,15 +14,23 @@ package app.fedilab.android.ui.fragment.settings
* You should have received a copy of the GNU General Public License along with Fedilab; if not, * You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */ * see <http://www.gnu.org/licenses>. */
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import app.fedilab.android.BaseMainActivity.currentAccount import app.fedilab.android.BaseMainActivity.currentAccount
import app.fedilab.android.R import app.fedilab.android.R
import app.fedilab.android.helper.SettingsStorage
class FragmentSettingsCategories : PreferenceFragmentCompat() { class FragmentSettingsCategories : PreferenceFragmentCompat() {
private val REQUEST_CODE = 5412
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.pref_categories, rootKey) setPreferencesFromResource(R.xml.pref_categories, rootKey)
@ -61,6 +69,25 @@ class FragmentSettingsCategories : PreferenceFragmentCompat() {
false false
} }
findPreference<Preference>(getString(R.string.pref_export_settings))?.setOnPreferenceClickListener {
val permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted ->
if (isGranted) {
SettingsStorage.saveSharedPreferencesToFile(context)
} else {
requestPermissions(arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), REQUEST_CODE)
}
}
permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE)
false
}
findPreference<Preference>(getString(R.string.pref_import_settings))?.setOnPreferenceClickListener {
false
}
val adminPreference = findPreference<Preference>(getString(R.string.pref_category_key_administration)) val adminPreference = findPreference<Preference>(getString(R.string.pref_category_key_administration))
adminPreference?.isVisible = currentAccount.admin adminPreference?.isVisible = currentAccount.admin
adminPreference?.setOnPreferenceClickListener { false } adminPreference?.setOnPreferenceClickListener { false }
@ -70,4 +97,16 @@ class FragmentSettingsCategories : PreferenceFragmentCompat() {
false false
} }
} }
@Deprecated("Deprecated in Java")
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
REQUEST_CODE -> if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
SettingsStorage.saveSharedPreferencesToFile(context)
} else {
Toast.makeText(context, getString(R.string.permission_missing), Toast.LENGTH_SHORT).show()
}
else -> {}
}
}
} }

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M7.41,8.59L12,13.17l4.59,-4.58L18,10l-6,6 -6,-6 1.41,-1.41z" />
</vector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M7.41,15.41L12,10.83l4.59,4.58L18,14l-6,-6 -6,6z" />
</vector>

View file

@ -616,6 +616,7 @@
<string name="pref_custom_theme">Use a custom theme</string> <string name="pref_custom_theme">Use a custom theme</string>
<string name="theming">Theming</string> <string name="theming">Theming</string>
<string name="data_export_theme">The theme was exported</string> <string name="data_export_theme">The theme was exported</string>
<string name="data_export_settings">The settings were exported</string>
<string name="data_export_theme_success">The theme has been successfully exported in CSV</string> <string name="data_export_theme_success">The theme has been successfully exported in CSV</string>
<string name="import_theme">Import a theme</string> <string name="import_theme">Import a theme</string>
<string name="import_theme_title">Tap here to import a theme from a previous export</string> <string name="import_theme_title">Tap here to import a theme from a previous export</string>
@ -1428,4 +1429,10 @@
<string name="pref_category_key_theming" translatable="false">pref_category_theming</string> <string name="pref_category_key_theming" translatable="false">pref_category_theming</string>
<string name="pref_category_key_administration" translatable="false">pref_category_administration</string> <string name="pref_category_key_administration" translatable="false">pref_category_administration</string>
<string name="pref_category_key_languages" translatable="false">pref_category_languages</string> <string name="pref_category_key_languages" translatable="false">pref_category_languages</string>
<string name="pref_export_settings" translatable="false">pref_export_settings</string>
<string name="pref_import_settings" translatable="false">pref_import_settings</string>
<string name="export_settings">Export settings</string>
<string name="import_settings">Import settings</string>
<string name="permission_missing">Permission not granted!</string>
</resources> </resources>

View file

@ -67,4 +67,19 @@
app:icon="@drawable/ic_language" app:icon="@drawable/ic_language"
app:key="@string/pref_category_key_languages" /> app:key="@string/pref_category_key_languages" />
<Preference
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:title="@string/export_settings"
app:icon="@drawable/ic_baseline_keyboard_arrow_down_24"
app:key="@string/pref_export_settings" />
<Preference
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:title="@string/import_settings"
app:icon="@drawable/ic_baseline_keyboard_arrow_up_24"
app:key="@string/pref_import_settings" />
</androidx.preference.PreferenceScreen> </androidx.preference.PreferenceScreen>