forked from mirrors/Fedilab
Export/Import all data
This commit is contained in:
parent
f858a870bd
commit
52ccfdb860
8 changed files with 456 additions and 174 deletions
|
@ -54,9 +54,9 @@ public class LoginActivity extends BaseActivity {
|
|||
|
||||
public static Account.API apiLogin;
|
||||
public static String currentInstanceLogin, client_idLogin, client_secretLogin, softwareLogin;
|
||||
private final int PICK_IMPORT = 5557;
|
||||
public static boolean requestedAdmin;
|
||||
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
public void proceedLogin(Activity activity, Account account) {
|
||||
new Thread(() -> {
|
||||
|
@ -154,6 +154,8 @@ public class LoginActivity extends BaseActivity {
|
|||
//The activity handles a redirect URI, it will extract token code and will proceed to authentication
|
||||
//That happens when the user wants to use an external browser
|
||||
manageItent(getIntent());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -176,7 +178,6 @@ public class LoginActivity extends BaseActivity {
|
|||
// automatically handle clicks on the Home/Up button, so long
|
||||
// as you specify a parent activity in AndroidManifest.xml.
|
||||
int id = item.getItemId();
|
||||
|
||||
if (id == R.id.action_proxy) {
|
||||
Intent intent = new Intent(LoginActivity.this, ProxyActivity.class);
|
||||
startActivity(intent);
|
||||
|
@ -188,20 +189,5 @@ public class LoginActivity extends BaseActivity {
|
|||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode,
|
||||
Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == PICK_IMPORT && resultCode == RESULT_OK) {
|
||||
if (data == null || data.getData() == null) {
|
||||
Toasty.error(LoginActivity.this, getString(R.string.toot_select_file_error), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
// String filename = Helper.getFilePathFromURI(LoginActivity.this, data.getData());
|
||||
// Sqlite.importDB(LoginActivity.this, filename);
|
||||
} else {
|
||||
Toasty.error(LoginActivity.this, getString(R.string.toot_select_file_error), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -312,7 +312,7 @@ public class Helper {
|
|||
public static final String INTENT_SEND_MODIFIED_IMAGE = "INTENT_SEND_MODIFIED_IMAGE";
|
||||
public static final String INTENT_COMPOSE_ERROR_MESSAGE = "INTENT_COMPOSE_ERROR_MESSAGE";
|
||||
public static final String TEMP_MEDIA_DIRECTORY = "TEMP_MEDIA_DIRECTORY";
|
||||
|
||||
public static final String TEMP_EXPORT_DATA = "TEMP_EXPORT_DATA";
|
||||
|
||||
public static final int EXTERNAL_STORAGE_REQUEST_CODE = 84;
|
||||
public static final int EXTERNAL_STORAGE_REQUEST_CODE_MEDIA_SAVE = 85;
|
||||
|
@ -1276,6 +1276,50 @@ public class Helper {
|
|||
}).start();
|
||||
}
|
||||
|
||||
|
||||
public static void createFileFromUri(Context context, Uri uri, OnFileCopied callBack) {
|
||||
new Thread(() -> {
|
||||
InputStream selectedFileInputStream;
|
||||
File file = null;
|
||||
try {
|
||||
String uriFullPath = uri.getPath();
|
||||
String[] uriFullPathStr = uriFullPath.split(":");
|
||||
String fullPath = uriFullPath;
|
||||
if (uriFullPathStr.length > 1) {
|
||||
fullPath = uriFullPathStr[1];
|
||||
}
|
||||
final String fileName = Helper.dateFileToString(context, new Date()) + ".zip";
|
||||
selectedFileInputStream = context.getContentResolver().openInputStream(uri);
|
||||
if (selectedFileInputStream != null) {
|
||||
final File certCacheDir = new File(context.getCacheDir(), TEMP_EXPORT_DATA);
|
||||
boolean isCertCacheDirExists = certCacheDir.exists();
|
||||
if (!isCertCacheDirExists) {
|
||||
isCertCacheDirExists = certCacheDir.mkdirs();
|
||||
}
|
||||
if (isCertCacheDirExists) {
|
||||
String filePath = certCacheDir.getAbsolutePath() + "/" + fileName;
|
||||
file = new File(filePath);
|
||||
OutputStream selectedFileOutPutStream = new FileOutputStream(filePath);
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while ((length = selectedFileInputStream.read(buffer)) > 0) {
|
||||
selectedFileOutPutStream.write(buffer, 0, length);
|
||||
}
|
||||
selectedFileOutPutStream.flush();
|
||||
selectedFileOutPutStream.close();
|
||||
}
|
||||
selectedFileInputStream.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
File finalFile = file;
|
||||
Runnable myRunnable = () -> callBack.onFileCopied(finalFile);
|
||||
mainHandler.post(myRunnable);
|
||||
}).start();
|
||||
}
|
||||
|
||||
public static void createAttachmentFromPAth(String path, OnAttachmentCopied callBack) {
|
||||
new Thread(() -> {
|
||||
Attachment attachment = new Attachment();
|
||||
|
@ -1954,6 +1998,10 @@ public class Helper {
|
|||
void onAttachmentCopied(Attachment attachment);
|
||||
}
|
||||
|
||||
public interface OnFileCopied {
|
||||
void onFileCopied(File file);
|
||||
}
|
||||
|
||||
public static void addMutedAccount(app.fedilab.android.client.entities.api.Account target) {
|
||||
if (MainActivity.filteredAccounts == null) {
|
||||
MainActivity.filteredAccounts = new ArrayList<>();
|
||||
|
|
|
@ -1,134 +0,0 @@
|
|||
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 static app.fedilab.android.helper.LogoHelper.getMainLogo;
|
||||
|
||||
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.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_settings_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(),
|
||||
getMainLogo(context)), 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, Uri srcUri) {
|
||||
boolean res = false;
|
||||
ObjectInputStream input = null;
|
||||
try {
|
||||
input = new ObjectInputStream(context.getContentResolver().openInputStream(srcUri));
|
||||
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;
|
||||
}
|
||||
}
|
294
app/src/main/java/app/fedilab/android/helper/ZipHelper.java
Normal file
294
app/src/main/java/app/fedilab/android/helper/ZipHelper.java
Normal file
|
@ -0,0 +1,294 @@
|
|||
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 static app.fedilab.android.helper.LogoHelper.getMainLogo;
|
||||
import static app.fedilab.android.sqlite.Sqlite.DB_NAME;
|
||||
import static app.fedilab.android.sqlite.Sqlite.db;
|
||||
|
||||
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 android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
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.nio.channels.FileChannel;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
import app.fedilab.android.R;
|
||||
import es.dmoral.toasty.Toasty;
|
||||
|
||||
|
||||
public class ZipHelper {
|
||||
|
||||
final static int BUFFER_SIZE = 2048;
|
||||
|
||||
public static void exportData(Context context) throws IOException {
|
||||
String suffix = Helper.dateFileToString(context, new Date());
|
||||
String fileName = "Fedilab_data_export_" + suffix + ".zip";
|
||||
String filePath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
|
||||
String zipFile = filePath + "/" + fileName;
|
||||
BufferedInputStream origin;
|
||||
try (ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)))) {
|
||||
byte[] data = new byte[BUFFER_SIZE];
|
||||
String settingsPath = storeSettings(context, suffix);
|
||||
if (settingsPath != null) {
|
||||
FileInputStream fi = new FileInputStream(settingsPath);
|
||||
origin = new BufferedInputStream(fi, BUFFER_SIZE);
|
||||
try {
|
||||
ZipEntry entry = new ZipEntry(settingsPath.substring(settingsPath.lastIndexOf("/") + 1));
|
||||
out.putNextEntry(entry);
|
||||
int count;
|
||||
while ((count = origin.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||
out.write(data, 0, count);
|
||||
}
|
||||
} finally {
|
||||
origin.close();
|
||||
}
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
new File(settingsPath).delete();
|
||||
} else {
|
||||
Toasty.error(context, context.getString(R.string.toast_error), Toasty.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
String dbPath = exportDB(context, suffix);
|
||||
if (dbPath != null) {
|
||||
FileInputStream fi = new FileInputStream(dbPath);
|
||||
origin = new BufferedInputStream(fi, BUFFER_SIZE);
|
||||
try {
|
||||
ZipEntry entry = new ZipEntry(dbPath.substring(dbPath.lastIndexOf("/") + 1));
|
||||
out.putNextEntry(entry);
|
||||
int count;
|
||||
while ((count = origin.read(data, 0, BUFFER_SIZE)) != -1) {
|
||||
out.write(data, 0, count);
|
||||
}
|
||||
} finally {
|
||||
origin.close();
|
||||
}
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
new File(dbPath).delete();
|
||||
} else {
|
||||
Toasty.error(context, context.getString(R.string.toast_error), Toasty.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
String message = context.getString(R.string.data_export_settings_success);
|
||||
Intent intentOpen = new Intent();
|
||||
intentOpen.setAction(android.content.Intent.ACTION_VIEW);
|
||||
Uri uri = Uri.parse("file://" + zipFile);
|
||||
intentOpen.setDataAndType(uri, "application/zip");
|
||||
String title = context.getString(R.string.data_export_settings);
|
||||
Helper.notify_user(context, currentAccount, intentOpen, BitmapFactory.decodeResource(context.getResources(),
|
||||
getMainLogo(context)), Helper.NotifType.BACKUP, title, message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressLint("UnspecifiedImmutableFlag")
|
||||
public static void importData(Context context, File file) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
int size;
|
||||
byte[] buffer = new byte[BUFFER_SIZE];
|
||||
|
||||
String uriFullPath = file.getAbsolutePath();
|
||||
String[] uriFullPathStr = uriFullPath.split(":");
|
||||
String fullPath = uriFullPath;
|
||||
if (uriFullPathStr.length > 1) {
|
||||
fullPath = uriFullPathStr[1];
|
||||
}
|
||||
fullPath = fullPath.replace(".zip", "");
|
||||
File f = new File(fullPath);
|
||||
if (!f.isDirectory()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
f.mkdirs();
|
||||
}
|
||||
boolean successful = true;
|
||||
try (ZipInputStream zin = new ZipInputStream(new FileInputStream(fullPath + ".zip"))) {
|
||||
ZipEntry ze;
|
||||
while ((ze = zin.getNextEntry()) != null) {
|
||||
if (!successful) {
|
||||
break;
|
||||
}
|
||||
String path = fullPath + ze.getName();
|
||||
File unzipFile = new File(path);
|
||||
FileOutputStream out = new FileOutputStream(unzipFile, false);
|
||||
BufferedOutputStream fout = new BufferedOutputStream(out, BUFFER_SIZE);
|
||||
try {
|
||||
while ((size = zin.read(buffer, 0, BUFFER_SIZE)) != -1) {
|
||||
fout.write(buffer, 0, size);
|
||||
}
|
||||
|
||||
zin.closeEntry();
|
||||
} finally {
|
||||
fout.flush();
|
||||
fout.close();
|
||||
}
|
||||
if (ze.getName().contains("settings")) {
|
||||
successful = restoreSettings(context, Uri.fromFile(new File(path)));
|
||||
} else if (ze.getName().contains("database")) {
|
||||
successful = importDB(context, path);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
boolean finalSuccessful = successful;
|
||||
Runnable myRunnable = () -> {
|
||||
if (finalSuccessful) {
|
||||
Helper.restart(context);
|
||||
} else {
|
||||
Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
};
|
||||
mainHandler.post(myRunnable);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
|
||||
}
|
||||
|
||||
private static String storeSettings(Context context, String suffix) {
|
||||
boolean res = false;
|
||||
ObjectOutputStream output = null;
|
||||
String fileName = "Fedilab_settings_export_" + suffix + ".fedilab";
|
||||
String filePath = context.getCacheDir().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;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (output != null) {
|
||||
output.flush();
|
||||
output.close();
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return res ? fullPath : null;
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
@SuppressWarnings("UnnecessaryUnboxing")
|
||||
private static boolean restoreSettings(Context context, Uri srcUri) {
|
||||
boolean res = false;
|
||||
ObjectInputStream input = null;
|
||||
try {
|
||||
input = new ObjectInputStream(context.getContentResolver().openInputStream(srcUri));
|
||||
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
SharedPreferences.Editor prefEdit = sharedpreferences.edit();
|
||||
prefEdit.clear();
|
||||
//noinspection unchecked
|
||||
Map<String, ?> entries = (Map<String, ?>) input.readObject();
|
||||
for (Map.Entry<String, ?> entry : entries.entrySet()) {
|
||||
Object v = entry.getValue();
|
||||
String key = entry.getKey();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
private static String exportDB(Context context, String suffix) {
|
||||
try {
|
||||
String fileName = "Fedilab_database_export_" + suffix + ".fedilab";
|
||||
String filePath = context.getCacheDir().getAbsolutePath();
|
||||
String fullPath = filePath + "/" + fileName;
|
||||
File dbSource = context.getDatabasePath(DB_NAME);
|
||||
File dbDest = new File(fullPath);
|
||||
FileChannel src = new FileInputStream(dbSource).getChannel();
|
||||
FileChannel dst = new FileOutputStream(dbDest).getChannel();
|
||||
dst.transferFrom(src, 0, src.size());
|
||||
src.close();
|
||||
dst.close();
|
||||
return fullPath;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean importDB(Context context, String backupDBPath) {
|
||||
try {
|
||||
if (db != null) {
|
||||
db.close();
|
||||
}
|
||||
File dbDest = context.getDatabasePath(DB_NAME);
|
||||
File dbSource = new File(backupDBPath);
|
||||
FileChannel src = new FileInputStream(dbSource).getChannel();
|
||||
FileChannel dst = new FileOutputStream(dbDest).getChannel();
|
||||
dst.transferFrom(src, 0, src.size());
|
||||
src.close();
|
||||
dst.close();
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ package app.fedilab.android.ui.fragment.login;
|
|||
* see <http://www.gnu.org/licenses>. */
|
||||
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static app.fedilab.android.activities.LoginActivity.apiLogin;
|
||||
import static app.fedilab.android.activities.LoginActivity.client_idLogin;
|
||||
import static app.fedilab.android.activities.LoginActivity.client_secretLogin;
|
||||
|
@ -22,8 +23,9 @@ import static app.fedilab.android.activities.LoginActivity.currentInstanceLogin;
|
|||
import static app.fedilab.android.activities.LoginActivity.requestedAdmin;
|
||||
import static app.fedilab.android.activities.LoginActivity.softwareLogin;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
|
@ -36,11 +38,13 @@ import android.view.ViewGroup;
|
|||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
|
@ -55,6 +59,7 @@ import app.fedilab.android.client.entities.app.InstanceSocial;
|
|||
import app.fedilab.android.databinding.FragmentLoginMainBinding;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.helper.MastodonHelper;
|
||||
import app.fedilab.android.helper.ZipHelper;
|
||||
import app.fedilab.android.viewmodel.mastodon.AppsVM;
|
||||
import app.fedilab.android.viewmodel.mastodon.InstanceSocialVM;
|
||||
import app.fedilab.android.viewmodel.mastodon.NodeInfoVM;
|
||||
|
@ -65,7 +70,9 @@ public class FragmentLoginMain extends Fragment {
|
|||
private FragmentLoginMainBinding binding;
|
||||
private boolean searchInstanceRunning = false;
|
||||
private String oldSearch;
|
||||
|
||||
private static final int REQUEST_CODE = 5412;
|
||||
private final int PICK_IMPORT = 5557;
|
||||
private ActivityResultLauncher<String> permissionLauncher;
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater,
|
||||
ViewGroup container, Bundle savedInstanceState) {
|
||||
|
@ -76,6 +83,24 @@ public class FragmentLoginMain extends Fragment {
|
|||
InstanceSocialVM instanceSocialVM = new ViewModelProvider(FragmentLoginMain.this).get(InstanceSocialVM.class);
|
||||
binding.menuIcon.setOnClickListener(this::showMenu);
|
||||
binding.loginInstance.setOnItemClickListener((parent, view, position, id) -> oldSearch = parent.getItemAtPosition(position).toString().trim());
|
||||
|
||||
permissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
|
||||
if (isGranted) {
|
||||
Intent openFileIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
openFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
openFileIntent.setType("application/zip");
|
||||
String[] mimeTypes = new String[]{"application/zip"};
|
||||
openFileIntent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
|
||||
//noinspection deprecation
|
||||
startActivityForResult(
|
||||
Intent.createChooser(
|
||||
openFileIntent,
|
||||
getString(R.string.load_settings)), PICK_IMPORT);
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(requireActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
|
||||
}
|
||||
});
|
||||
|
||||
binding.loginInstance.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
@ -184,7 +209,6 @@ public class FragmentLoginMain extends Fragment {
|
|||
MenuInflater menuInflater = popupMenu.getMenuInflater();
|
||||
menuInflater.inflate(R.menu.main_login, popupMenu.getMenu());
|
||||
MenuItem adminTabItem = popupMenu.getMenu().findItem(R.id.action_request_admin);
|
||||
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity());
|
||||
adminTabItem.setChecked(requestedAdmin);
|
||||
popupMenu.setOnMenuItemClickListener(item -> {
|
||||
int itemId = item.getItemId();
|
||||
|
@ -208,6 +232,8 @@ public class FragmentLoginMain extends Fragment {
|
|||
return false;
|
||||
}
|
||||
});
|
||||
} else if (itemId == R.id.action_import_data) {
|
||||
permissionLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
@ -258,4 +284,44 @@ public class FragmentLoginMain extends Fragment {
|
|||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode,
|
||||
Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
if (requestCode == PICK_IMPORT && resultCode == RESULT_OK) {
|
||||
if (data == null || data.getData() == null) {
|
||||
Toasty.error(requireActivity(), getString(R.string.toot_select_file_error), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
Helper.createFileFromUri(requireActivity(), data.getData(), file -> ZipHelper.importData(requireActivity(), file));
|
||||
} else {
|
||||
Toasty.error(requireActivity(), getString(R.string.toot_select_file_error), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||
if (requestCode == REQUEST_CODE) {
|
||||
if (grantResults.length > 0
|
||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
Intent openFileIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||
openFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
openFileIntent.setType("application/zip");
|
||||
String[] mimeTypes = new String[]{"application/zip"};
|
||||
openFileIntent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
|
||||
startActivityForResult(
|
||||
Intent.createChooser(
|
||||
openFileIntent,
|
||||
getString(R.string.load_settings)), PICK_IMPORT);
|
||||
} else {
|
||||
Toasty.error(requireActivity(), getString(R.string.permission_missing), Toasty.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,6 +19,8 @@ import android.app.Activity;
|
|||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.webkit.URLUtil;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
|
@ -30,8 +32,11 @@ import androidx.navigation.Navigation;
|
|||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import app.fedilab.android.R;
|
||||
import app.fedilab.android.helper.SettingsStorage;
|
||||
import app.fedilab.android.helper.Helper;
|
||||
import app.fedilab.android.helper.ZipHelper;
|
||||
import es.dmoral.toasty.Toasty;
|
||||
|
||||
public class FragmentSettingsCategories extends PreferenceFragmentCompat {
|
||||
|
@ -117,7 +122,11 @@ public class FragmentSettingsCategories extends PreferenceFragmentCompat {
|
|||
}
|
||||
ActivityResultLauncher<String> permissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), isGranted -> {
|
||||
if (isGranted) {
|
||||
SettingsStorage.saveSharedPreferencesToFile(requireActivity());
|
||||
try {
|
||||
ZipHelper.exportData(requireActivity());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
ActivityCompat.requestPermissions(requireActivity(), new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
|
||||
}
|
||||
|
@ -152,12 +161,18 @@ public class FragmentSettingsCategories extends PreferenceFragmentCompat {
|
|||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||
if (resultCode == Activity.RESULT_OK && requestCode == PICKUP_FILE) {
|
||||
boolean result = data != null && SettingsStorage.loadSharedPreferencesFromFile(requireActivity(), data.getData());
|
||||
if (result) {
|
||||
Toasty.success(requireActivity(), getString(R.string.data_import_settings_success), Toasty.LENGTH_LONG).show();
|
||||
} else {
|
||||
Toasty.error(requireActivity(), getString(R.string.toast_error), Toasty.LENGTH_LONG).show();
|
||||
if (data == null || data.getData() == null) {
|
||||
Toasty.error(requireActivity(), getString(R.string.toot_select_file_error), Toast.LENGTH_LONG).show();
|
||||
return;
|
||||
}
|
||||
String uriFullPath = data.getData().getPath();
|
||||
String[] uriFullPathStr = uriFullPath.split(":");
|
||||
String fullPath = uriFullPath;
|
||||
if (uriFullPathStr.length > 1) {
|
||||
fullPath = uriFullPathStr[1];
|
||||
}
|
||||
final String fileName = URLUtil.guessFileName(fullPath, null, null);
|
||||
Helper.createFileFromUri(requireActivity(), data.getData(), file -> ZipHelper.importData(requireActivity(), file));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,7 +182,11 @@ public class FragmentSettingsCategories extends PreferenceFragmentCompat {
|
|||
if (requestCode == REQUEST_CODE) {
|
||||
if (grantResults.length > 0
|
||||
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
SettingsStorage.saveSharedPreferencesToFile(requireActivity());
|
||||
try {
|
||||
ZipHelper.exportData(requireActivity());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
Toasty.error(requireActivity(), getString(R.string.permission_missing), Toasty.LENGTH_SHORT).show();
|
||||
}
|
||||
|
|
|
@ -21,15 +21,17 @@
|
|||
android:checkable="true"
|
||||
android:title="@string/admin_scope"
|
||||
app:actionViewClass="android.widget.CheckBox" />
|
||||
|
||||
<item
|
||||
android:id="@+id/action_import_data"
|
||||
android:title="@string/import_data"
|
||||
app:showAsAction="never" />
|
||||
|
||||
<!--
|
||||
<item
|
||||
android:id="@+id/action_import_data"
|
||||
android:title="@string/import_data"
|
||||
app:showAsAction="never" />
|
||||
<item
|
||||
android:id="@+id/action_provider"
|
||||
android:checkable="true"
|
||||
android:title="@string/set_security_provider"
|
||||
app:actionViewClass="android.widget.CheckBox" />
|
||||
-->
|
||||
<item
|
||||
android:id="@+id/action_provider"
|
||||
android:checkable="true"
|
||||
android:title="@string/set_security_provider"
|
||||
app:actionViewClass="android.widget.CheckBox" />
|
||||
-->
|
||||
</menu>
|
||||
|
|
|
@ -2107,4 +2107,5 @@
|
|||
<string name="add_all_users_home_muted">Add all users in muted home</string>
|
||||
<string name="put_all_accounts_in_home_muted">All accounts will be muted for the Home timeline.</string>
|
||||
<string name="mute_them_all">Mute them all</string>
|
||||
<string name="import_data">Import data</string>
|
||||
</resources>
|
Loading…
Reference in a new issue