Added an option to export or import the app data

This commit is contained in:
Pranshul committed 2024-12-10 16:16:05 +05:30
1 parent d616a5ce25
commit 20c4f77eae
3 files changed
+239 -11

No files matched your search

+17 -10
View File
@@ -22,9 +22,12 @@ function handleStorageChange(event) {
break;
case 'selectedMainWeatherProvider':
setTimeout(() => {
window.location.reload();
sendThemeToAndroid('overcast')
}, 1500);
if(localStorage.getItem('selectedMainWeatherProvider') === 'Accuweather' && !localStorage.getItem('ApiForAccu')){
} else{
window.location.reload();
sendThemeToAndroid('overcast')
}
}, 1500);
break;
case 'ApiForAccu':
setTimeout(() => {
@@ -53,14 +56,18 @@ window.addEventListener('storage', handleStorageChange);
// apply when options are changed
function HandleNoReloadSettings() {
let debounceTimer;
const renderLocation = localStorage.getItem('CurrentLocationName')
setTimeout(() =>{
LoadLocationOnRequest(localStorage.getItem('currentLat'), localStorage.getItem('currentLong'), renderLocation)
onAllLocationsLoaded()
}, 300);
}
function HandleNoReloadSettings() {
const renderLocation = localStorage.getItem('CurrentLocationName');
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => {
LoadLocationOnRequest(localStorage.getItem('currentLat'), localStorage.getItem('currentLong'), renderLocation);
onAllLocationsLoaded();
}, 500);
}
function RemoveDisplayedAnimations() {
+67
View File
@@ -324,6 +324,20 @@
<md-icon icon-outlined slot="end">open_in_new</md-icon>
</md-list-item>
<md-list-item type="button" id="exportAppData">
<md-icon icon-filled slot="start">upgrade</md-icon>
<div slot="headline">Export data</div>
<div slot="supporting-text">Export all your settings, locations, and their last fetched weather data—literally everything!</div>
</md-list-item>
<md-list-item type="button" id="importAppData">
<md-icon icon-filled slot="start">download</md-icon>
<div slot="headline">Import data</div>
<div slot="supporting-text" style="color: var(--Error);">Warning: Importing will erase your current app data</div>
</md-list-item>
<input type="file" id="ImportFile" style="display:none;" accept="application/json">
</md-list>
@@ -1093,6 +1107,59 @@ function ChangeSelectedMainProviderName() {
} else{
document.getElementById('useWeatherAlerts').selected = true
}
document.getElementById("exportAppData").addEventListener("click", () => {
const data = { ...localStorage };
// Check if local storage has data
if (Object.keys(data).length > 0) {
// Convert data to JSON string
const jsonData = JSON.stringify(data, null, 2);
// Use Android interface to save the file
Android.saveFile(jsonData);
} else {
// Show toast message if no data is found
ShowSnackMessage.ShowSnack("No data found", "short");
}
});
document.getElementById('importAppData').addEventListener('click', () => {
Android.importFile();
});
function handleImportedData(importedData) {
try {
const data = JSON.parse(importedData);
if (typeof data !== "object" || data === null) {
throw new Error("Invalid data format");
}
localStorage.clear();
setTimeout(() => {
for (const [key, value] of Object.entries(data)) {
localStorage.setItem(key, value);
}
ShowSnackMessage.ShowSnack("Data imported successfully!", "short");
}, 1000);
setTimeout(() => {
Android.reloadTheApp();
}, 1500);
} catch (error) {
ShowSnackMessage.ShowSnack("Error parsing the imported JSON data. Please ensure it is valid and correctly formatted.", "long");
console.error(error);
}
}
</script>
</script>
@@ -21,6 +21,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
@@ -30,6 +32,7 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
@@ -38,9 +41,26 @@ import androidx.core.content.res.ResourcesCompat;
import com.google.android.material.snackbar.Snackbar;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStream;
public class SettingsActivity extends AppCompatActivity {
private WebView webview;
private ValueCallback<Uri[]> filePathCallback;
private final static int FILECHOOSER_RESULTCODE = 1;
private final static int EXPORT_REQUEST_CODE = 2;
private static final int PERMISSION_REQUEST_CODE = 1;
private static final int SAVE_DOCUMENT_REQUEST_CODE = 2;
private static final int IMPORT_REQUEST_CODE = 3;
private String dataToSave;
private boolean isFirstLoad = true;
public void onBackPressed() {
@@ -75,6 +95,7 @@ public class SettingsActivity extends AppCompatActivity {
webview.addJavascriptInterface(androidInterface, "AndroidInterface");
webview.addJavascriptInterface(new ShowToastInterface(this), "ToastAndroidShow");
webview.addJavascriptInterface(new ShowSnackInterface(this), "ShowSnackMessage");
webview.addJavascriptInterface(new WebAppInterface(), "Android");
webview.setBackgroundColor(getResources().getColor(R.color.yellowBg));
webview.loadUrl("file:///android_asset/pages/settings.html");
@@ -107,12 +128,141 @@ public class SettingsActivity extends AppCompatActivity {
webview.evaluateJavascript(jsCodePrimaryColor, null);
}
}
});
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == FILECHOOSER_RESULTCODE) {
if (filePathCallback != null) {
Uri[] results = null;
if (resultCode == RESULT_OK && data != null) {
String dataString = data.getDataString();
if (dataString != null) {
results = new Uri[]{Uri.parse(dataString)};
}
}
filePathCallback.onReceiveValue(results);
filePathCallback = null;
}
} else if (requestCode == SAVE_DOCUMENT_REQUEST_CODE) {
if (resultCode == RESULT_OK && data != null && data.getData() != null) {
saveToUri(data.getData());
} else {
Toast.makeText(this, "Error exporting", Toast.LENGTH_SHORT).show();
}
} else if (requestCode == IMPORT_REQUEST_CODE) {
if (resultCode == RESULT_OK && data != null && data.getData() != null) {
importFromUri(data.getData());
} else {
Toast.makeText(this, "Error importing file", Toast.LENGTH_SHORT).show();
}
}
}
private void restartApp() {
Toast.makeText(this, "App is restarting...", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
}
public class WebAppInterface {
@JavascriptInterface
public void saveFile(String data) {
dataToSave = data;
openFilePickerExport();
}
@JavascriptInterface
public void importFile() {
openFilePickerImport(); // Open file picker for importing JSON data
}
@JavascriptInterface
public void reloadTheApp() {
restartApp(); // Open file picker for importing JSON data
}
}
private void openFilePickerExport() {
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/json");
intent.putExtra(Intent.EXTRA_TITLE, "WeatherMasterData.json");
startActivityForResult(intent, SAVE_DOCUMENT_REQUEST_CODE);
}
private void openFilePickerImport() {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/json");
startActivityForResult(intent, IMPORT_REQUEST_CODE);
}
private void importFromUri(Uri uri) {
try {
InputStream inputStream = getContentResolver().openInputStream(uri);
if (inputStream != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
reader.close();
inputStream.close();
String importedData = stringBuilder.toString();
String escapedData = importedData.replace("'", "\\'").replace("\"", "\\\"");
runOnUiThread(() -> {
String jsCode = "handleImportedData('" + escapedData + "');";
webview.evaluateJavascript(jsCode, null);
});
}
} catch (Exception e) {
Toast.makeText(this, "Error reading file", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
private void saveToUri(Uri uri) {
try {
OutputStream outputStream = getContentResolver().openOutputStream(uri);
if (outputStream != null) {
outputStream.write(dataToSave.getBytes());
outputStream.close();
Toast.makeText(this, "Backup saved", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Error", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Toast.makeText(this, "Error saving file", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
private void requestNotificationPermissions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.POST_NOTIFICATIONS)
@@ -201,6 +351,10 @@ public class SettingsActivity extends AppCompatActivity {
}
}
// export or import data
public class AndroidInterface {
private SettingsActivity sActivity;