0
0
mirror of https://github.com/TrianguloY/UrlChecker.git synced 2024-09-19 11:52:14 +02:00

Refactor Utils class for Better Readability (#338)

Refactored the Utils class to enhance code readability by separating
functionalities into two distinct classes:

- Created HttpUtils class for HTTP-related operations.
- Introduced LocaleUtils class for locale-related operations.
- Cleaned up code for improved readability and maintainability.

---------

Co-authored-by: Nikulkumar Popatbhai Kukadiya <nk865270@dal.ca>
Co-authored-by: TrianguloY <correo--correo@hotmail.com>
This commit is contained in:
Nikul Kukadiya 2024-05-25 09:12:48 -03:00 committed by GitHub
parent b9f4fa7c39
commit f6aec67e7b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 222 additions and 205 deletions

View File

@ -14,6 +14,7 @@ import com.trianguloy.urlchecker.R;
import com.trianguloy.urlchecker.utilities.AndroidSettings;
import com.trianguloy.urlchecker.utilities.methods.AndroidUtils;
import com.trianguloy.urlchecker.utilities.methods.Inflater;
import com.trianguloy.urlchecker.utilities.methods.LocaleUtils;
import com.trianguloy.urlchecker.utilities.methods.PackageUtils;
import java.util.List;
@ -37,7 +38,7 @@ public class AboutActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidSettings.setTheme(this, false);
AndroidSettings.setLocale(this);
LocaleUtils.setLocale(this);
setContentView(R.layout.activity_about);
setTitle(R.string.a_about);
AndroidUtils.configureUp(this);

View File

@ -32,6 +32,7 @@ import com.trianguloy.urlchecker.utilities.methods.AndroidUtils;
import com.trianguloy.urlchecker.utilities.methods.Animations;
import com.trianguloy.urlchecker.utilities.methods.JavaUtils;
import com.trianguloy.urlchecker.utilities.methods.JavaUtils.Function;
import com.trianguloy.urlchecker.utilities.methods.LocaleUtils;
import com.trianguloy.urlchecker.utilities.methods.PackageUtils;
import com.trianguloy.urlchecker.utilities.wrappers.ProgressDialog;
import com.trianguloy.urlchecker.utilities.wrappers.ZipReader;
@ -69,13 +70,14 @@ public class BackupActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidSettings.setTheme(this, false);
AndroidSettings.setLocale(this);
LocaleUtils.setLocale(this);
setContentView(R.layout.activity_backup);
setTitle(R.string.btn_backupRestore);
AndroidUtils.configureUp(this);
Animations.enableAnimationsRecursively(this);
// find view UI elements
prefs = GenericPref.getPrefs(this);
chk_data = findViewById(R.id.chk_data);
chk_data_prefs = findViewById(R.id.chk_data_prefs);
@ -272,7 +274,7 @@ public class BackupActivity extends Activity {
try (var zip = new ZipReader(uri, this)) {
// check version
if (!chk_ignoreNewer.isChecked() && VersionManager.isNewerThanCurrent(zip.getFileString(FILE_VERSION))) {
if (!chk_ignoreNewer.isChecked() && VersionManager.isVersionNewer(zip.getFileString(FILE_VERSION))) {
runOnUiThread(() -> Toast.makeText(this, R.string.bck_newer, Toast.LENGTH_LONG).show());
return;
}
@ -308,6 +310,7 @@ public class BackupActivity extends Activity {
});
}
/** Restore preferences from [fileName] in the [zip] that matches the [predicate]. */
private void restorePreferencesMatching(String fileName, Function<String, Boolean> predicate, ZipReader zip) throws IOException, JSONException {
var preferences = zip.getFileString(fileName);
if (preferences == null) return;
@ -324,13 +327,19 @@ public class BackupActivity extends Activity {
// add
for (var key : JavaUtils.toList(jsonPrefs.keys())) {
var ent = jsonPrefs.getJSONObject(key);
switch (ent.getString(PREF_TYPE)) {
case "String" -> editor.putString(key, ent.getString(PREF_VALUE));
case "Integer" -> editor.putInt(key, ent.getInt(PREF_VALUE));
case "Long" -> editor.putLong(key, ent.getLong(PREF_VALUE));
case "Boolean" -> editor.putBoolean(key, ent.getBoolean(PREF_VALUE));
default -> AndroidUtils.assertError("Unknown type: " + ent.getString(PREF_TYPE));
try {
var ent = jsonPrefs.getJSONObject(key);
var type = ent.getString(PREF_TYPE);
switch (type) {
case "String" -> editor.putString(key, ent.getString(PREF_VALUE));
case "Integer" -> editor.putInt(key, ent.getInt(PREF_VALUE));
case "Long" -> editor.putLong(key, ent.getLong(PREF_VALUE));
case "Boolean" -> editor.putBoolean(key, ent.getBoolean(PREF_VALUE));
default -> AndroidUtils.assertError("Unknown type: " + type);
}
} catch (JSONException e) {
AndroidUtils.assertError("Error when restoring key: " + key);
e.printStackTrace();
}
}

View File

@ -14,6 +14,7 @@ import com.trianguloy.urlchecker.fragments.ResultCodeInjector;
import com.trianguloy.urlchecker.modules.companions.VersionManager;
import com.trianguloy.urlchecker.utilities.AndroidSettings;
import com.trianguloy.urlchecker.utilities.methods.AndroidUtils;
import com.trianguloy.urlchecker.utilities.methods.LocaleUtils;
import com.trianguloy.urlchecker.utilities.methods.PackageUtils;
/**
@ -27,7 +28,7 @@ public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidSettings.setTheme(this, false);
AndroidSettings.setLocale(this);
LocaleUtils.setLocale(this);
setContentView(R.layout.activity_main);
// mark as seen if required

View File

@ -21,6 +21,7 @@ import com.trianguloy.urlchecker.utilities.methods.AndroidUtils;
import com.trianguloy.urlchecker.utilities.methods.Animations;
import com.trianguloy.urlchecker.utilities.methods.Inflater;
import com.trianguloy.urlchecker.utilities.methods.JavaUtils;
import com.trianguloy.urlchecker.utilities.methods.LocaleUtils;
import java.util.ArrayList;
import java.util.Collections;
@ -43,7 +44,7 @@ public class ModulesActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidSettings.setTheme(this, false);
AndroidSettings.setLocale(this);
LocaleUtils.setLocale(this);
setContentView(R.layout.activity_modules);
setTitle(R.string.a_modules);
AndroidUtils.configureUp(this);
@ -194,7 +195,8 @@ public class ModulesActivity extends Activity {
* Updates the enable status of all the movable buttons
*/
private void updateMovableButtons() {
for (int i = 0; i < list.getChildCount(); i++) {
var listSize = list.getChildCount();
for (int i = 0; i < listSize; i++) {
View child = list.getChildAt(i);
// enable up unless already at the top
View up = child.findViewById(R.id.move_up);
@ -202,8 +204,8 @@ public class ModulesActivity extends Activity {
up.setAlpha(i > 0 ? 1 : 0.5f);
// enable down unless already at the bottom
View down = child.findViewById(R.id.move_down);
down.setEnabled(i < list.getChildCount() - 1);
down.setAlpha(i < list.getChildCount() - 1 ? 1 : 0.5f);
down.setEnabled(i < listSize - 1);
down.setAlpha(i < listSize - 1 ? 1 : 0.5f);
}
}

View File

@ -10,10 +10,12 @@ import android.widget.ArrayAdapter;
import android.widget.Spinner;
import com.trianguloy.urlchecker.R;
//import com.trianguloy.urlchecker.fragments.BrowserButtonsFragment;
import com.trianguloy.urlchecker.fragments.BrowserButtonsFragment;
import com.trianguloy.urlchecker.fragments.ResultCodeInjector;
import com.trianguloy.urlchecker.utilities.AndroidSettings;
import com.trianguloy.urlchecker.utilities.methods.AndroidUtils;
import com.trianguloy.urlchecker.utilities.methods.LocaleUtils;
import com.trianguloy.urlchecker.utilities.methods.Animations;
import com.trianguloy.urlchecker.utilities.methods.PackageUtils;
@ -28,7 +30,7 @@ public class SettingsActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidSettings.setTheme(this, false);
AndroidSettings.setLocale(this);
LocaleUtils.setLocale(this);
setContentView(R.layout.activity_settings);
setTitle(R.string.a_settings);
AndroidUtils.configureUp(this);
@ -86,11 +88,11 @@ public class SettingsActivity extends Activity {
*/
private void configureLocale() {
// init
var pref = AndroidSettings.LOCALE_PREF(this);
var pref = LocaleUtils.LOCALE_PREF(this);
var spinner = this.<Spinner>findViewById(R.id.locale);
// populate available
var locales = AndroidSettings.getLocales(this);
var locales = LocaleUtils.getLocales(this);
var adapter = new ArrayAdapter<>(
this,
android.R.layout.simple_spinner_item,

View File

@ -9,10 +9,12 @@ import android.widget.Button;
import android.widget.TextView;
import com.trianguloy.urlchecker.R;
//import com.trianguloy.urlchecker.fragments.BrowserButtonsFragment;
import com.trianguloy.urlchecker.fragments.BrowserButtonsFragment;
import com.trianguloy.urlchecker.fragments.ResultCodeInjector;
import com.trianguloy.urlchecker.utilities.AndroidSettings;
import com.trianguloy.urlchecker.utilities.generics.GenericPref;
import com.trianguloy.urlchecker.utilities.methods.LocaleUtils;
import com.trianguloy.urlchecker.utilities.methods.PackageUtils;
import com.trianguloy.urlchecker.utilities.wrappers.DoubleEvent;
import com.trianguloy.urlchecker.utilities.wrappers.FixedViewFlipper;
@ -37,7 +39,7 @@ public class TutorialActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidSettings.setTheme(this, false);
AndroidSettings.setLocale(this);
LocaleUtils.setLocale(this);
setContentView(R.layout.activity_tutorial);
setTitle(R.string.tutorial);

View File

@ -26,6 +26,7 @@ import com.trianguloy.urlchecker.utilities.AndroidSettings;
import com.trianguloy.urlchecker.utilities.methods.AndroidUtils;
import com.trianguloy.urlchecker.utilities.methods.Animations;
import com.trianguloy.urlchecker.utilities.methods.Inflater;
import com.trianguloy.urlchecker.utilities.methods.LocaleUtils;
import java.util.ArrayList;
import java.util.Collections;
@ -187,7 +188,7 @@ public class MainDialog extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidSettings.setTheme(this, true);
AndroidSettings.setLocale(this);
LocaleUtils.setLocale(this);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.dialog_main);
setFinishOnTouchOutside(true);

View File

@ -14,6 +14,7 @@ import com.trianguloy.urlchecker.R;
import com.trianguloy.urlchecker.dialogs.JsonEditor;
import com.trianguloy.urlchecker.utilities.generics.GenericPref;
import com.trianguloy.urlchecker.utilities.methods.AndroidUtils;
import com.trianguloy.urlchecker.utilities.methods.HttpUtils;
import com.trianguloy.urlchecker.utilities.methods.JavaUtils;
import com.trianguloy.urlchecker.utilities.methods.StreamUtils;
import com.trianguloy.urlchecker.utilities.wrappers.AssetFile;
@ -284,7 +285,7 @@ public class ClearUrlCatalog {
// read content
String rawRules;
try {
rawRules = StreamUtils.readFromUrl(catalogURL.get());
rawRules = HttpUtils.readFromUrl(catalogURL.get());
} catch (IOException e) {
e.printStackTrace();
return R.string.mClear_urlError;
@ -296,7 +297,7 @@ public class ClearUrlCatalog {
// read hash
String hash;
try {
hash = StreamUtils.readFromUrl(hashURL.get()).trim();
hash = HttpUtils.readFromUrl(hashURL.get()).trim();
} catch (IOException e) {
e.printStackTrace();
return R.string.mClear_hashError;

View File

@ -7,6 +7,7 @@ import android.util.Pair;
import com.trianguloy.urlchecker.R;
import com.trianguloy.urlchecker.utilities.generics.JsonCatalog;
import com.trianguloy.urlchecker.utilities.methods.HttpUtils;
import com.trianguloy.urlchecker.utilities.methods.JavaUtils;
import com.trianguloy.urlchecker.utilities.methods.StreamUtils;
import com.trianguloy.urlchecker.utilities.wrappers.InternalFile;
@ -97,7 +98,7 @@ public class Hosts {
progress.setMessage(cntx.getString(R.string.mHosts_buildDownload, label, file));
Log.d("HOSTS", "Downloading " + file);
StreamUtils.streamFromUrl(file, line -> {
HttpUtils.streamFromUrl(file, line -> {
var parts = line.replaceAll("#.*", "").trim().split(" +");
if (parts.length != 2) return;
// valid, add

View File

@ -33,7 +33,7 @@ public class VersionManager {
}
/** Returns true iff [version] is newer than the current one */
public static boolean isNewerThanCurrent(String version) {
public static boolean isVersionNewer(String version) {
// shortcut to check own version
if (BuildConfig.VERSION_NAME.equals(version)) return false;
@ -42,18 +42,20 @@ public class VersionManager {
if (versionSplit.isEmpty()) return true;
// compare: "1" < "2", "1" < "1.1"
var currentSplit = split(BuildConfig.VERSION_NAME);
var i = 0;
while (true) {
// end of version, version is older (or equal)
if (versionSplit.size() <= i) return false;
// end of current, version is newer
if (currentSplit.size() <= i) return true;
for (var i = 0; i < Math.min(versionSplit.size(), currentSplit.size()); i++) {
var versionPart = versionSplit.get(i);
var currentPart = currentSplit.get(i);
// version is older
if (versionSplit.get(i) < currentSplit.get(i)) return false;
if (versionPart < currentPart) return false;
// version is newer
if (versionSplit.get(i) > currentSplit.get(i)) return true;
i++;
if (versionPart > currentPart) return true;
}
// If all parts are equal up to the minimum length, the version with more parts is newer
// (and if both are equal, then it is not newer)
return versionSplit.size() > currentSplit.size();
}
/* ------------------- instance ------------------- */

View File

@ -3,6 +3,7 @@ package com.trianguloy.urlchecker.modules.companions;
import android.content.Context;
import com.trianguloy.urlchecker.R;
import com.trianguloy.urlchecker.utilities.methods.HttpUtils;
import com.trianguloy.urlchecker.utilities.methods.StreamUtils;
import org.json.JSONException;
@ -34,7 +35,7 @@ public class VirusTotalUtility {
String responseJSON;
try {
responseJSON = StreamUtils.performPOST(urlGetReport, getPOSTparameters(urlToScan, key));
responseJSON = HttpUtils.performPOST(urlGetReport, getPOSTparameters(urlToScan, key));
} catch (IOException e) {
e.printStackTrace();
result.error = cntx.getString(R.string.mVT_connectError);

View File

@ -17,7 +17,7 @@ import com.trianguloy.urlchecker.modules.AModuleDialog;
import com.trianguloy.urlchecker.url.UrlData;
import com.trianguloy.urlchecker.utilities.generics.GenericPref;
import com.trianguloy.urlchecker.utilities.methods.AndroidUtils;
import com.trianguloy.urlchecker.utilities.methods.StreamUtils;
import com.trianguloy.urlchecker.utilities.methods.HttpUtils;
import java.io.IOException;
import java.net.HttpURLConnection;
@ -183,7 +183,7 @@ class StatusDialog extends AModuleDialog {
// perform GET to the url
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setInstanceFollowRedirects(false); // Make the logic below easier to detect redirections
conn.setConnectTimeout(StreamUtils.CONNECT_TIMEOUT);
conn.setConnectTimeout(HttpUtils.CONNECT_TIMEOUT);
var responseCode = conn.getResponseCode();
Log.d("RESPONSE_CODE", url + ": " + responseCode);

View File

@ -14,6 +14,7 @@ import com.trianguloy.urlchecker.modules.AModuleDialog;
import com.trianguloy.urlchecker.modules.DescriptionConfig;
import com.trianguloy.urlchecker.url.UrlData;
import com.trianguloy.urlchecker.utilities.methods.AndroidUtils;
import com.trianguloy.urlchecker.utilities.methods.HttpUtils;
import com.trianguloy.urlchecker.utilities.methods.StreamUtils;
import org.json.JSONException;
@ -108,7 +109,7 @@ class UnshortenDialog extends AModuleDialog {
try {
// get response
var response = new JSONObject(StreamUtils.readFromUrl("https://unshorten.me/json/" + getUrl()));
var response = new JSONObject(HttpUtils.readFromUrl("https://unshorten.me/json/" + getUrl()));
var resolved_url = response.getString("resolved_url");
var usage_count = Integer.parseInt(response.optString("usage_count", "0"));
var ref = new Object() { // reference object to allow using these inside lambdas

View File

@ -18,108 +18,6 @@ import java.util.Locale;
public interface AndroidSettings {
/* ------------------- locale ------------------- */
/**
* The locale pref
*/
static GenericPref.Str LOCALE_PREF(Context cntx) {
return new GenericPref.Str("locale", "", cntx);
}
/**
* Sets the locale to an activity
*/
static void setLocale(Activity cntx) {
cntx.getResources().updateConfiguration(
getConfig(parseLocale(LOCALE_PREF(cntx).get())),
cntx.getResources().getDisplayMetrics()
);
}
/**
* Container for a locale with a given name
*/
class AvailableLocale {
public final String tag;
public final Locale locale;
public final String name;
public AvailableLocale(String tag, Locale locale, String name) {
this.tag = tag;
this.locale = locale;
this.name = name;
}
public AvailableLocale(String name) {
this.tag = "";
this.locale = null;
this.name = name;
}
@Override
public String toString() {
return name + (tag.isEmpty() ? "" : " (" + tag + ")");
}
}
/**
* Returns the list of available/installed locales (plus a 'default' at the top)
*/
static List<AvailableLocale> getLocales(Context cntx) {
// check each locale
var available = new ArrayList<AvailableLocale>();
for (var tag : BuildConfig.LOCALES) {
var locale = parseLocale(tag);
// check if available on this device (with split apks the device may not have the translation downloaded)
var localeName = getStringForLocale(R.string.locale, locale, cntx);
if (available.isEmpty() || !available.get(0).name.equals(localeName)) {
// either english (first one) or a translation exists
// note that translations may not exists because PlayStore only installs locales configured by the user
available.add(new AvailableLocale(tag, locale, localeName));
} else {
if (BuildConfig.DEBUG) Log.d("LOCALE", "Locale " + tag + " is not present");
}
}
Collections.sort(available, (a, b) -> a.toString().compareTo(b.toString()));
available.add(0, new AvailableLocale(cntx.getString(R.string.deviceDefault)));
return available;
}
/**
* returns a specific string in a specific locale
*/
static String getStringForLocale(int id, Locale locale, Context cntx) {
return cntx.createConfigurationContext(getConfig(locale)).getString(id);
}
/**
* returns a configuration object for the given locale
*/
static Configuration getConfig(Locale locale) {
Configuration config = new Configuration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
config.setLocale(locale);
} else {
config.locale = locale;
}
return config;
}
/**
* returns a locale for the given tag (language[-country[-variant]])
*/
static Locale parseLocale(String locale) {
if (locale.isEmpty()) return null;
try {
var parts = locale.split("-");
return new Locale(parts[0], parts.length > 1 ? parts[1] : "", parts.length > 2 ? parts[2] : "");
} catch (Exception e) {
return null;
}
}
/* ------------------- day/light theme ------------------- */
/**

View File

@ -99,11 +99,10 @@ public interface AndroidUtils {
static String formatMillis(long millis, Context cntx) {
if (millis < 0) return "---";
return DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT,
Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
? cntx.getResources().getConfiguration().getLocales().get(0)
: cntx.getResources().getConfiguration().locale
).format(new Date(millis));
var locale = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
? cntx.getResources().getConfiguration().getLocales().get(0)
: cntx.getResources().getConfiguration().locale;
return DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, locale).format(new Date(millis));
}
/**

View File

@ -0,0 +1,45 @@
package com.trianguloy.urlchecker.utilities.methods;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
/** HttpUtils class contains the method related to url. */
public class HttpUtils {
public static final int CONNECT_TIMEOUT = 5000;
/** GETs an URL and returns the content as a string. */
public static String readFromUrl(String url) throws IOException {
var connection = new URL(url).openConnection();
connection.setConnectTimeout(CONNECT_TIMEOUT);
return StreamUtils.inputStream2String(connection.getInputStream());
}
/** GETs an URL and streams its lines. */
public static void streamFromUrl(String url, JavaUtils.Consumer<String> consumer) throws IOException {
var connection = new URL(url).openConnection();
connection.setConnectTimeout(CONNECT_TIMEOUT);
StreamUtils.consumeLines(connection.getInputStream(), consumer);
}
/** POSTs something (a body) to an URL and returns its content as a string. */
public static String performPOST(String url, String body) throws IOException {
// Send POST data request
var conn = (HttpsURLConnection) new URL(url).openConnection();
conn.setDoOutput(true);
conn.setConnectTimeout(CONNECT_TIMEOUT);
try (var wr = new OutputStreamWriter(conn.getOutputStream())) {
wr.write(body);
wr.flush();
}
// Get the server response
return StreamUtils.inputStream2String(
conn.getResponseCode() >= 200 && conn.getResponseCode() < 300
? conn.getInputStream()
: conn.getErrorStream()
);
}
}

View File

@ -0,0 +1,107 @@
package com.trianguloy.urlchecker.utilities.methods;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.util.Log;
import com.trianguloy.urlchecker.BuildConfig;
import com.trianguloy.urlchecker.R;
import com.trianguloy.urlchecker.utilities.generics.GenericPref;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
/** Utilities related to translations */
public interface LocaleUtils {
/** Returns a locale for the given tag (language[-country[-variant]]) */
static Locale parseLocale(String locale) {
if (locale.isEmpty()) return null;
try {
var parts = locale.split("-");
return new Locale(parts[0], parts.length > 1 ? parts[1] : "", parts.length > 2 ? parts[2] : "");
} catch (Exception e) {
return null;
}
}
/** Returns a configuration object for the given locale */
static Configuration getConfig(Locale locale) {
var config = new Configuration();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
config.setLocale(locale);
} else {
config.locale = locale;
}
return config;
}
/** The locale pref */
static GenericPref.Str LOCALE_PREF(Context cntx) {
return new GenericPref.Str("locale", "", cntx);
}
/** Sets the locale to an activity */
static void setLocale(Activity cntx) {
cntx.getResources().updateConfiguration(
getConfig(parseLocale(LOCALE_PREF(cntx).get())),
cntx.getResources().getDisplayMetrics()
);
}
/** Container for a locale with a given name */
class AvailableLocale {
public final String tag;
public final Locale locale;
public final String name;
public AvailableLocale(String tag, Locale locale, String name) {
this.tag = tag;
this.locale = locale;
this.name = name;
}
public AvailableLocale(String name) {
this.tag = "";
this.locale = null;
this.name = name;
}
@Override
public String toString() {
return name + (tag.isEmpty() ? "" : " (" + tag + ")");
}
}
/** Returns the list of available/installed locales (plus a 'default' at the top) */
static List<AvailableLocale> getLocales(Context cntx) {
// check each locale
var available = new ArrayList<AvailableLocale>();
for (var tag : BuildConfig.LOCALES) {
var locale = parseLocale(tag);
// check if available on this device (with split apks the device may not have the translation downloaded)
var localeName = getStringForLocale(R.string.locale, locale, cntx);
if (available.isEmpty() || !available.get(0).name.equals(localeName)) {
// either english (first one) or a translation exists
// note that translations may not exists because PlayStore only installs locales configured by the user
available.add(new AvailableLocale(tag, locale, localeName));
} else {
if (BuildConfig.DEBUG) Log.d("LOCALE", "Locale " + tag + " is not present");
}
}
Collections.sort(available, (a, b) -> a.toString().compareTo(b.toString()));
available.add(0, new AvailableLocale(cntx.getString(R.string.deviceDefault)));
return available;
}
/** returns a specific string in a specific locale */
static String getStringForLocale(int id, Locale locale, Context cntx) {
return cntx.createConfigurationContext(getConfig(locale)).getString(id);
}
}

View File

@ -7,69 +7,17 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.net.ssl.HttpsURLConnection;
/**
* Generic utilities related to streams (urls, strings, bytes...)
*/
public interface StreamUtils {
Charset UTF_8 = Charset.forName("UTF-8"); // StandardCharsets.UTF_8 requires api 19
int CONNECT_TIMEOUT = 5000;
/**
* GETs an url and returns the content as string
*/
static String readFromUrl(String url) throws IOException {
URLConnection connection = new URL(url).openConnection();
connection.setConnectTimeout(CONNECT_TIMEOUT);
return inputStream2String(connection.getInputStream());
}
/**
* GETs an url and streams their lines
*/
static void streamFromUrl(String url, JavaUtils.Consumer<String> consumer) throws IOException {
URLConnection connection = new URL(url).openConnection();
connection.setConnectTimeout(CONNECT_TIMEOUT);
consumeLines(connection.getInputStream(), consumer);
}
/**
* POSTs something (a body) to an url, returns its content as a string
*/
static String performPOST(String url, String body) throws IOException {
// Defined URL where to send data
URL urlObject = new URL(url);
// Send POST data request
HttpsURLConnection conn = (HttpsURLConnection) urlObject.openConnection();
conn.setDoOutput(true);
conn.setConnectTimeout(CONNECT_TIMEOUT);
OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
wr.write(body);
wr.flush();
// Get the server response
return inputStream2String(
conn.getResponseCode() >= 200 && conn.getResponseCode() < 300
? conn.getInputStream()
: conn.getErrorStream()
);
}
/**
* Reads an input stream and returns its content as string.
* The stream is closed afterwards
*/
/** Reads an input stream and returns its content as a string. The stream is closed afterwards. */
static String inputStream2String(InputStream is) throws IOException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, UTF_8))) {
StringBuilder sb = new StringBuilder();
@ -82,14 +30,14 @@ public interface StreamUtils {
}
}
/** Reads an inputStream and transfers its content to a file. The stream is NOT closed */
/** Reads an input stream and transfers its content to a file. The stream is NOT closed. */
static void inputStream2File(InputStream in, File file) throws IOException {
try (var out = new FileOutputStream(file)) {
inputStream2OutputStream(in, out);
}
}
/** Reads an inputStream and transfers its content to an output stream. The streams are NOT closed */
/** Reads an input stream and transfers its content to an output stream. The streams are NOT closed. */
static void inputStream2OutputStream(InputStream in, OutputStream out) throws IOException {
var buffer = new byte[10240];
int read;
@ -98,9 +46,7 @@ public interface StreamUtils {
}
}
/**
* Reads an input stream and streams its lines
*/
/** Reads an input stream and streams its lines. */
static void consumeLines(InputStream is, JavaUtils.Consumer<String> function) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, UTF_8))) {
String line;
@ -112,9 +58,7 @@ public interface StreamUtils {
}
}
/**
* Returns the sha-256 of a string
*/
/** Returns the SHA-256 hash of a string. */
static String sha256(String string) {
try {
// get byte array