1
0
mirror of https://github.com/MGislv/NekoX.git synced 2024-07-02 10:33:36 +00:00

Export & Import settings. close #467

This commit is contained in:
世界 2021-04-19 22:42:59 +08:00
parent 4546cdaaa1
commit d1b90f29e6
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
5 changed files with 257 additions and 5 deletions

View File

@ -3,8 +3,8 @@ import cn.hutool.core.util.RuntimeUtil
apply plugin: "com.android.application"
apply plugin: "kotlin-android"
def verName = "7.7.2-rc01"
def verCode = 290 + 3 * 1
def verName = "7.7.2-rc02"
def verCode = 290 + 3 * 2
if (System.getenv("DEBUG_BUILD") == "true") {
verName += "-" + RuntimeUtil.execForStr("git log --pretty=format:'%h' -n 1)")

View File

@ -254,6 +254,7 @@ import tw.nekomimi.nekogram.NekoConfig;
import tw.nekomimi.nekogram.NekoXConfig;
import tw.nekomimi.nekogram.parts.MessageTransKt;
import tw.nekomimi.nekogram.parts.PollTransUpdatesKt;
import tw.nekomimi.nekogram.settings.NekoSettingsActivity;
import tw.nekomimi.nekogram.transtale.Translator;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.PGPUtil;
@ -11739,6 +11740,8 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
return 21;
} else if ((messageObject.getDocumentName().toLowerCase().endsWith(".nekox-stickers.json"))) {
return 22;
} else if ((messageObject.getDocumentName().toLowerCase().endsWith(".nekox-settings.json"))) {
return 23;
} else if (!messageObject.isNewGif() && mime.endsWith("/mp4") || mime.endsWith("/png") || mime.endsWith("/jpg") || mime.endsWith("/jpeg")) {
return 6;
}
@ -19215,14 +19218,17 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
items.add(LocaleController.getString("ShareFile", R.string.ShareFile));
options.add(6);
icons.add(R.drawable.baseline_share_24);
} else if (type == 21 || type == 22) {
} else if (type == 21 || type == 22 || type == 23) {
options.add(5);
if (type == 21) {
items.add(LocaleController.getString("ImportProxyList", R.string.ImportProxyList));
icons.add(R.drawable.baseline_security_24);
} else {
} else if (type == 22) {
items.add(LocaleController.getString("ImportStickersList", R.string.ImportStickersList));
icons.add(R.drawable.deproko_baseline_stickers_filled_24);
} else {
items.add(LocaleController.getString("ImportSettings", R.string.ImportSettings));
icons.add(R.drawable.baseline_security_24);
}
items.add(LocaleController.getString("SaveToDownloads", R.string.SaveToDownloads));
options.add(10);
@ -20316,6 +20322,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
presentFragment(new StickersActivity(finalLocFile));
});
} else if (locFile.getName().toLowerCase().endsWith(".nekox-settings.json")) {
File finalLocFile = locFile;
NekoSettingsActivity.importSettings(getParentActivity(), finalLocFile);
}
}
break;
@ -22948,6 +22960,12 @@ public class ChatActivity extends BaseFragment implements NotificationCenter.Not
presentFragment(new StickersActivity(finalLocFile));
});
} else if (message.getDocumentName().toLowerCase().endsWith(".nekox-settings.json")) {
File finalLocFile = locFile;
NekoSettingsActivity.importSettings(getParentActivity(), finalLocFile);
} else {
boolean handled = false;
if (message.canPreviewDocument()) {

View File

@ -1,7 +1,13 @@
package tw.nekomimi.nekogram.settings;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.os.Build;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@ -10,12 +16,24 @@ import android.widget.FrameLayout;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.jakewharton.processphoenix.ProcessPhoenix;
import org.json.JSONException;
import org.json.JSONObject;
import org.telegram.messenger.AndroidUtilities;
import org.telegram.messenger.ApplicationLoader;
import org.telegram.messenger.LocaleController;
import org.telegram.messenger.MessagesController;
import org.telegram.messenger.R;
import org.telegram.messenger.SendMessagesHelper;
import org.telegram.messenger.browser.Browser;
import org.telegram.ui.ActionBar.ActionBar;
import org.telegram.ui.ActionBar.ActionBarMenu;
import org.telegram.ui.ActionBar.ActionBarMenuItem;
import org.telegram.ui.ActionBar.AlertDialog;
import org.telegram.ui.ActionBar.BaseFragment;
import org.telegram.ui.ActionBar.Theme;
import org.telegram.ui.ActionBar.ThemeDescription;
@ -30,10 +48,21 @@ import org.telegram.ui.Cells.TextInfoPrivacyCell;
import org.telegram.ui.Cells.TextSettingsCell;
import org.telegram.ui.Components.LayoutHelper;
import org.telegram.ui.Components.RecyclerListView;
import org.telegram.ui.DocumentSelectActivity;
import org.telegram.ui.LaunchActivity;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
import java.util.function.Function;
import kotlin.text.StringsKt;
import tw.nekomimi.nekogram.ExternalGcm;
import tw.nekomimi.nekogram.utils.AlertUtil;
import tw.nekomimi.nekogram.utils.FileUtil;
import tw.nekomimi.nekogram.utils.GsonUtil;
import tw.nekomimi.nekogram.utils.ShareUtil;
@SuppressLint("RtlHardcoded")
public class NekoSettingsActivity extends BaseFragment {
@ -66,12 +95,21 @@ public class NekoSettingsActivity extends BaseFragment {
return true;
}
private static final int backup_settings = 1;
private static final int import_settings = 2;
@SuppressLint("NewApi")
@Override
public View createView(Context context) {
actionBar.setBackButtonImage(R.drawable.ic_ab_back);
actionBar.setTitle(LocaleController.getString("NekoSettings", R.string.NekoSettings));
ActionBarMenu menu = actionBar.createMenu();
ActionBarMenuItem otherMenu = menu.addItem(0, R.drawable.ic_ab_other);
otherMenu.addSubItem(backup_settings, LocaleController.getString("BackupSettings", R.string.BackupSettings));
otherMenu.addSubItem(import_settings, LocaleController.getString("ImportSettings", R.string.ImportSettings));
if (AndroidUtilities.isTablet()) {
actionBar.setOccupyStatusBar(false);
}
@ -80,6 +118,35 @@ public class NekoSettingsActivity extends BaseFragment {
public void onItemClick(int id) {
if (id == -1) {
finishFragment();
} else if (id == backup_settings) {
backupSettings();
} else if (id == import_settings) {
try {
if (Build.VERSION.SDK_INT >= 23 && getParentActivity().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
getParentActivity().requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 4);
return;
}
} catch (Throwable ignore) {
}
DocumentSelectActivity fragment = new DocumentSelectActivity(false);
fragment.setMaxSelectedFiles(1);
fragment.setAllowPhoto(false);
fragment.setDelegate(new DocumentSelectActivity.DocumentSelectActivityDelegate() {
@Override
public void didSelectFiles(DocumentSelectActivity activity, ArrayList<String> files, String caption, boolean notify, int scheduleDate) {
activity.finishFragment();
importSettings(getParentActivity(), new File(files.get(0)));
}
@Override
public void didSelectPhotos(ArrayList<SendMessagesHelper.SendingMediaInfo> photos, boolean notify, int scheduleDate) {
}
@Override
public void startDocumentSelectActivity() {
}
});
presentFragment(fragment);
}
}
});
@ -120,6 +187,164 @@ public class NekoSettingsActivity extends BaseFragment {
return fragmentView;
}
private void backupSettings() {
try {
File cacheFile = new File(ApplicationLoader.applicationContext.getCacheDir(), new Date().toLocaleString() + ".nekox-settings.json");
FileUtil.writeUtf8String(backupSettingsJson(), cacheFile);
ShareUtil.shareFile(getParentActivity(), cacheFile);
} catch (JSONException e) {
AlertUtil.showSimpleAlert(getParentActivity(), e);
}
}
private String backupSettingsJson() throws JSONException {
JSONObject configJson = new JSONObject();
ArrayList<String> userconfig = new ArrayList<>();
userconfig.add("saveIncomingPhotos");
userconfig.add("passcodeHash");
userconfig.add("passcodeType");
userconfig.add("passcodeHash");
userconfig.add("autoLockIn");
userconfig.add("useFingerprint");
spToJSON("userconfing", configJson, userconfig::contains);
ArrayList<String> mainconfig = new ArrayList<>();
mainconfig.add("saveToGallery");
mainconfig.add("autoplayGifs");
mainconfig.add("autoplayVideo");
mainconfig.add("mapPreviewType");
mainconfig.add("raiseToSpeak");
mainconfig.add("customTabs");
mainconfig.add("directShare");
mainconfig.add("shuffleMusic");
mainconfig.add("playOrderReversed");
mainconfig.add("inappCamera");
mainconfig.add("repeatMode");
mainconfig.add("fontSize");
mainconfig.add("bubbleRadius");
mainconfig.add("ivFontSize");
mainconfig.add("allowBigEmoji");
mainconfig.add("streamMedia");
mainconfig.add("saveStreamMedia");
mainconfig.add("smoothKeyboard");
mainconfig.add("pauseMusicOnRecord");
mainconfig.add("streamAllVideo");
mainconfig.add("streamMkv");
mainconfig.add("suggestStickers");
mainconfig.add("sortContactsByName");
mainconfig.add("sortFilesByName");
mainconfig.add("noSoundHintShowed");
mainconfig.add("directShareHash");
mainconfig.add("useThreeLinesLayout");
mainconfig.add("archiveHidden");
mainconfig.add("distanceSystemType");
mainconfig.add("loopStickers");
mainconfig.add("keepMedia");
mainconfig.add("noStatusBar");
mainconfig.add("lastKeepMediaCheckTime");
mainconfig.add("searchMessagesAsListHintShows");
mainconfig.add("searchMessagesAsListUsed");
mainconfig.add("stickersReorderingHintUsed");
mainconfig.add("textSelectionHintShows");
mainconfig.add("scheduledOrNoSoundHintShows");
mainconfig.add("lockRecordAudioVideoHint");
mainconfig.add("disableVoiceAudioEffects");
mainconfig.add("chatSwipeAction");
mainconfig.add("theme");
spToJSON("mainconfig", configJson, mainconfig::contains);
spToJSON("themeconfig", configJson, null);
spToJSON("nekoconfig", configJson, null);
return configJson.toString(4);
}
private static void spToJSON(String sp, JSONObject object, Function<String, Boolean> filter) throws JSONException {
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(sp, Activity.MODE_PRIVATE);
JSONObject jsonConfig = new JSONObject();
for (Map.Entry<String, ?> entry : preferences.getAll().entrySet()) {
String key = entry.getKey();
if (filter != null && !filter.apply(key)) continue;
if (entry.getValue() instanceof Long) {
key = key + "_long";
} else if (entry.getValue() instanceof Float) {
key = key + "_float";
}
jsonConfig.put(key, entry.getValue());
}
object.put(sp, jsonConfig);
}
public static void importSettings(Context context, File settingsFile) {
AlertUtil.showConfirm(context,
LocaleController.getString("ImportSettingsAlert", R.string.ImportSettingsAlert),
R.drawable.baseline_security_24,
LocaleController.getString("Import", R.string.Import),
true,
() -> importSettingsConfirmed(context, settingsFile));
}
public static void importSettingsConfirmed(Context context, File settingsFile) {
try {
JsonObject configJson = GsonUtil.toJsonObject(FileUtil.readUtf8String(settingsFile));
importSettings(configJson);
AlertDialog restart = new AlertDialog(context, 0);
restart.setTitle(LocaleController.getString("NekoX", R.string.NekoX));
restart.setMessage(LocaleController.getString("RestartAppToTakeEffect", R.string.RestartAppToTakeEffect));
restart.setPositiveButton(LocaleController.getString("OK", R.string.OK), (__, ___) -> {
ProcessPhoenix.triggerRebirth(context, new Intent(context, LaunchActivity.class));
});
restart.show();
} catch (Exception e) {
AlertUtil.showSimpleAlert(context, e);
}
}
@SuppressLint("ApplySharedPref")
public static void importSettings(JsonObject configJson) throws JSONException {
for (Map.Entry<String, JsonElement> element : configJson.entrySet()) {
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences(element.getKey(), Activity.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
for (Map.Entry<String, JsonElement> config : ((JsonObject) element.getValue()).entrySet()) {
String key = config.getKey();
JsonPrimitive value = (JsonPrimitive) config.getValue();
if (value.isBoolean()) {
editor.putBoolean(key, value.getAsBoolean());
} else if (value.isNumber()) {
boolean isLong = false;
boolean isFloat = false;
if (key.endsWith("_long")) {
key = StringsKt.substringBeforeLast(key, "_long", key);
isLong = true;
} else if (key.endsWith("_float")) {
key = StringsKt.substringBeforeLast(key, "_float", key);
isFloat = true;
}
if (isLong) {
editor.putLong(key, value.getAsLong());
} else if (isFloat) {
editor.putFloat(key, value.getAsFloat());
} else {
editor.putInt(key, value.getAsInt());
}
} else {
editor.putString(key, value.getAsString());
}
}
editor.commit();
}
}
@Override
public void onResume() {
super.onResume();
@ -139,7 +364,7 @@ public class NekoSettingsActivity extends BaseFragment {
aboutRow = rowCount++;
channelRow = rowCount++;
fdroidRow = rowCount ++;
fdroidRow = rowCount++;
if (ExternalGcm.checkPlayServices()) {
googlePlayRow = rowCount++;
} else {

View File

@ -1,6 +1,7 @@
package tw.nekomimi.nekogram.utils
import com.google.gson.Gson
import com.google.gson.JsonObject
import com.google.gson.internal.Streams
import com.google.gson.stream.JsonWriter
import java.io.StringWriter
@ -21,4 +22,9 @@ object GsonUtil {
return stringWriter.toString()
}
@JvmStatic
fun toJsonObject(json: String): JsonObject {
return gson.fromJson(json, JsonObject::class.java)
}
}

View File

@ -233,4 +233,7 @@
<string name="WsPayload">Payload</string>
<string name="AutoLockImmediately">Immediately</string>
<string name="WsNeedLogin">Due to technical limitations, Ws Relay cannot be used before logging in.</string>
<string name="BackupSettings">Backup settings</string>
<string name="ImportSettings">Import settings</string>
<string name="ImportSettingsAlert">Are you sure you want to overwrite the settings? Importing settings from unknown sources may cause the pin to be overwritten and cause the application to be locked.</string>
</resources>