mirror of
https://github.com/gsantner/dandelion
synced 2025-12-15 08:41:10 +01:00
Change package ID of gsantner/opoc
This commit is contained in:
parent
b3129e0e91
commit
15a34a1895
20 changed files with 360 additions and 77 deletions
149
app/src/main/java/net/gsantner/opoc/ui/LanguagePreference.java
Normal file
149
app/src/main/java/net/gsantner/opoc/ui/LanguagePreference.java
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* ------------------------------------------------------------------------------
|
||||
* Gregor Santner <gsantner.github.io> wrote this. You can do whatever you want
|
||||
* with it. If we meet some day, and you think it is worth it, you can buy me a
|
||||
* coke in return. Provided as is without any kind of warranty. Do not blame or
|
||||
* sue me if something goes wrong. No attribution required. - Gregor Santner
|
||||
*
|
||||
* License: Creative Commons Zero (CC0 1.0)
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* A ListPreference that displays a list of available languages
|
||||
* Requires:
|
||||
* The BuildConfig field "APPLICATION_LANGUAGES" which is a array of all available languages
|
||||
* opoc/ContextUtils
|
||||
* BuildConfig field can be defined by using the method below
|
||||
|
||||
buildConfigField("String[]", "APPLICATION_LANGUAGES", '{' + getUsedAndroidLanguages().collect {"\"${it}\""}.join(",") + '}')
|
||||
|
||||
@SuppressWarnings(["UnnecessaryQualifiedReference", "SpellCheckingInspection"])
|
||||
static String[] getUsedAndroidLanguages() {
|
||||
Set<String> langs = new HashSet<>()
|
||||
new File('.').eachFileRecurse(groovy.io.FileType.DIRECTORIES) {
|
||||
final foldername = it.name
|
||||
if (foldername.startsWith('values-') && !it.canonicalPath.contains("build" + File.separator + "intermediates")) {
|
||||
new File(it.toString()).eachFileRecurse(groovy.io.FileType.FILES) {
|
||||
if (it.name.toLowerCase().endsWith(".xml") && it.getCanonicalFile().getText('UTF-8').contains("<string")) {
|
||||
langs.add(foldername.replace("values-", ""))
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return langs.toArray(new String[langs.size()])
|
||||
}
|
||||
|
||||
* Summary: Change language of this app. Restart app for changes to take effect
|
||||
|
||||
* Define element in Preferences-XML:
|
||||
<!--suppress AndroidDomInspection -->
|
||||
<net.gsantner.opoc.ui.LanguagePreference
|
||||
android:icon="@drawable/ic_language_black_24dp"
|
||||
android:defaultValue=""
|
||||
android:key="@string/pref_key__language"
|
||||
android:summary="@string/pref_desc__language"
|
||||
android:title="@string/pref_title__language"/>
|
||||
*/
|
||||
package net.gsantner.opoc.ui;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.preference.ListPreference;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import net.gsantner.opoc.util.ContextUtils;
|
||||
|
||||
/**
|
||||
* A {@link android.preference.ListPreference} that displays a list of languages to select from
|
||||
*/
|
||||
@SuppressWarnings({"unused", "SpellCheckingInspection"})
|
||||
public class LanguagePreference extends ListPreference {
|
||||
public LanguagePreference(Context context) {
|
||||
super(context);
|
||||
init(context, null);
|
||||
}
|
||||
|
||||
public LanguagePreference(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public LanguagePreference(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public LanguagePreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean callChangeListener(Object newValue) {
|
||||
if (newValue instanceof String) {
|
||||
// Does not apply to existing UI, use recreate()
|
||||
new ContextUtils(getContext()).setAppLanguage((String) newValue);
|
||||
}
|
||||
return super.callChangeListener(newValue);
|
||||
}
|
||||
|
||||
private void init(Context context, AttributeSet attrs) {
|
||||
// Fetch readable details
|
||||
ContextUtils ContextUtils = new ContextUtils(context);
|
||||
List<String> languages = new ArrayList<>();
|
||||
Object bcof = ContextUtils.getBuildConfigValue("APPLICATION_LANGUAGES");
|
||||
if (bcof instanceof String[]) {
|
||||
for (String langId : (String[]) bcof) {
|
||||
Locale locale = ContextUtils.getLocaleByAndroidCode(langId);
|
||||
languages.add(summarizeLocale(locale) + ";" + langId);
|
||||
}
|
||||
}
|
||||
|
||||
// Sort languages naturally
|
||||
Collections.sort(languages);
|
||||
|
||||
// Show in UI
|
||||
String[] entries = new String[languages.size() + 2];
|
||||
String[] entryval = new String[languages.size() + 2];
|
||||
for (int i = 0; i < languages.size(); i++) {
|
||||
entries[i + 2] = languages.get(i).split(";")[0];
|
||||
entryval[i + 2] = languages.get(i).split(";")[1];
|
||||
}
|
||||
entries[0] = "System";
|
||||
entryval[0] = "";
|
||||
entries[1] = "English";
|
||||
entryval[1] = "en";
|
||||
|
||||
setEntries(entries);
|
||||
setEntryValues(entryval);
|
||||
}
|
||||
|
||||
// Concat english and localized language name
|
||||
// Append country if country specific (e.g. Portuguese Brazil)
|
||||
private String summarizeLocale(Locale locale) {
|
||||
String country = locale.getDisplayCountry(locale);
|
||||
String language = locale.getDisplayLanguage(locale);
|
||||
return locale.getDisplayLanguage(Locale.ENGLISH)
|
||||
+ " (" + language.substring(0, 1).toUpperCase() + language.substring(1)
|
||||
+ ((!country.isEmpty() && !country.toLowerCase().equals(language.toLowerCase())) ? (", " + country) : "")
|
||||
+ ")";
|
||||
}
|
||||
|
||||
// Add current language to summary
|
||||
@Override
|
||||
public CharSequence getSummary() {
|
||||
Locale locale = new ContextUtils(getContext()).getLocaleByAndroidCode(getValue());
|
||||
return super.getSummary() + "\n\n" + summarizeLocale(locale);
|
||||
}
|
||||
}
|
||||
124
app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java
Normal file
124
app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* ------------------------------------------------------------------------------
|
||||
* Gregor Santner <gsantner.github.io> wrote this. You can do whatever you want
|
||||
* with it. If we meet some day, and you think it is worth it, you can buy me a
|
||||
* coke in return. Provided as is without any kind of warranty. Do not blame or
|
||||
* sue me if something goes wrong. No attribution required. - Gregor Santner
|
||||
*
|
||||
* License: Creative Commons Zero (CC0 1.0)
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.AppCompatTextView;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableString;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.TypedValue;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
|
||||
|
||||
@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "SpellCheckingInspection"})
|
||||
public class ActivityUtils extends net.gsantner.opoc.util.ContextUtils {
|
||||
//########################
|
||||
//## Members, Constructors
|
||||
//########################
|
||||
protected Activity _activity;
|
||||
|
||||
public ActivityUtils(final Activity activity) {
|
||||
super(activity);
|
||||
_activity = activity;
|
||||
}
|
||||
|
||||
//########################
|
||||
//## Methods
|
||||
//########################
|
||||
|
||||
/**
|
||||
* Animate to specified Activity
|
||||
*
|
||||
* @param to The class of the activity
|
||||
* @param finishFromActivity true: Finish the current activity
|
||||
* @param requestCode Request code for stating the activity, not waiting for result if null
|
||||
*/
|
||||
public void animateToActivity(Class to, Boolean finishFromActivity, Integer requestCode) {
|
||||
animateToActivity(new Intent(_activity, to), finishFromActivity, requestCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Animate to Activity specified in intent
|
||||
* Requires animation resources
|
||||
*
|
||||
* @param intent Intent to open start an activity
|
||||
* @param finishFromActivity true: Finish the current activity
|
||||
* @param requestCode Request code for stating the activity, not waiting for result if null
|
||||
*/
|
||||
public void animateToActivity(Intent intent, Boolean finishFromActivity, Integer requestCode) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
|
||||
if (requestCode != null) {
|
||||
_activity.startActivityForResult(intent, requestCode);
|
||||
} else {
|
||||
_activity.startActivity(intent);
|
||||
|
||||
}
|
||||
_activity.overridePendingTransition(getResId(ResType.DIMEN, "fadein"), getResId(ResType.DIMEN, "fadeout"));
|
||||
if (finishFromActivity != null && finishFromActivity) {
|
||||
_activity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void showSnackBar(@StringRes int stringId, boolean showLong) {
|
||||
Snackbar.make(_activity.findViewById(android.R.id.content), stringId,
|
||||
showLong ? Snackbar.LENGTH_LONG : Snackbar.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
public void hideSoftKeyboard() {
|
||||
InputMethodManager inputMethodManager = (InputMethodManager) _activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
|
||||
if (_activity.getCurrentFocus() != null && _activity.getCurrentFocus().getWindowToken() != null) {
|
||||
inputMethodManager.hideSoftInputFromWindow(_activity.getCurrentFocus().getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void showDialogWithHtmlTextView(@StringRes int resTitleId, String html) {
|
||||
showDialogWithHtmlTextView(resTitleId, html, true, null);
|
||||
}
|
||||
|
||||
public void showDialogWithHtmlTextView(@StringRes int resTitleId, String text, boolean isHtml, DialogInterface.OnDismissListener dismissedListener) {
|
||||
AppCompatTextView textView = new AppCompatTextView(_context);
|
||||
int padding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16,
|
||||
_context.getResources().getDisplayMetrics());
|
||||
textView.setMovementMethod(new LinkMovementMethod());
|
||||
textView.setPadding(padding, 0, padding, 0);
|
||||
|
||||
textView.setText(isHtml ? new SpannableString(Html.fromHtml(text)) : text);
|
||||
AlertDialog.Builder dialog = new AlertDialog.Builder(_context)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.setOnDismissListener(dismissedListener)
|
||||
.setTitle(resTitleId)
|
||||
.setView(textView);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
// Toggle with no param, else set visibility according to first bool
|
||||
public void toggleStatusbarVisibility(boolean... optionalForceVisible) {
|
||||
WindowManager.LayoutParams attrs = _activity.getWindow().getAttributes();
|
||||
int flag = WindowManager.LayoutParams.FLAG_FULLSCREEN;
|
||||
if (optionalForceVisible.length == 0) {
|
||||
attrs.flags ^= flag;
|
||||
} else if (optionalForceVisible.length == 1 && optionalForceVisible[0]) {
|
||||
attrs.flags &= ~flag;
|
||||
} else {
|
||||
attrs.flags |= flag;
|
||||
}
|
||||
_activity.getWindow().setAttributes(attrs);
|
||||
}
|
||||
}
|
||||
176
app/src/main/java/net/gsantner/opoc/util/AdBlock.java
Normal file
176
app/src/main/java/net/gsantner/opoc/util/AdBlock.java
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* ---------------------------------------------------------------------------- *
|
||||
* Gregor Santner <gsantner.github.io> wrote this file. You can do whatever
|
||||
* you want with this stuff. If we meet some day, and you think this stuff is
|
||||
* worth it, you can buy me a coke in return. Provided as is without any kind
|
||||
* of warranty. No attribution required. - Gregor Santner
|
||||
*
|
||||
* License of this file: Creative Commons Zero (CC0 1.0)
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* Place adblock hosts file in raw: src/main/res/raw/adblock_domains__xyz.txt
|
||||
* Always blocks both, www and non www
|
||||
|
||||
* Load hosts (call e.g. via Application-Object)
|
||||
AdBlock.getInstance().loadHostsFromRawAssetsAsync(context);
|
||||
|
||||
* Override inside a WebViewClient:
|
||||
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
|
||||
return AdBlock.getInstance().isAdHost(url)
|
||||
? AdBlock.createEmptyResponse()
|
||||
: super.shouldInterceptRequest(view, url);
|
||||
}
|
||||
*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebResourceResponse;
|
||||
|
||||
import com.github.dfa.diaspora_android.R;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Simple Host-Based AdBlocker
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "SpellCheckingInspection", "unused"})
|
||||
public class AdBlock {
|
||||
private static final AdBlock instance = new AdBlock();
|
||||
|
||||
public static AdBlock getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
//########################
|
||||
//##
|
||||
//## Members
|
||||
//##
|
||||
//########################
|
||||
private final Set<String> _adblockHostsFromRaw = new HashSet<>();
|
||||
private final Set<String> _adblockHosts = new HashSet<>();
|
||||
private boolean _isLoaded;
|
||||
|
||||
//########################
|
||||
//##
|
||||
//## Methods
|
||||
//##
|
||||
//########################
|
||||
private AdBlock() {
|
||||
}
|
||||
|
||||
public boolean isAdHost(String urlS) {
|
||||
if (urlS != null && !urlS.isEmpty() && urlS.startsWith("http")) {
|
||||
try {
|
||||
URI url = new URI(urlS);
|
||||
String host = url.getHost().trim();
|
||||
if (host.startsWith("www.") && host.length() >= 4) {
|
||||
host = host.substring(4);
|
||||
}
|
||||
return _adblockHosts.contains(host) || _adblockHosts.contains("www." + host);
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public AdBlock reset() {
|
||||
_adblockHosts.clear();
|
||||
_adblockHosts.addAll(_adblockHostsFromRaw);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isLoaded() {
|
||||
return _isLoaded;
|
||||
}
|
||||
|
||||
public static WebResourceResponse createEmptyResponse() {
|
||||
return new WebResourceResponse("text/plain", "utf-8", new ByteArrayInputStream("".getBytes()));
|
||||
}
|
||||
|
||||
public void addBlockedHosts(String... hosts) {
|
||||
for (String host : hosts) {
|
||||
if (host != null) {
|
||||
host = host.trim();
|
||||
if (host.startsWith("www.") && host.length() >= 4) {
|
||||
host = host.substring(4);
|
||||
}
|
||||
if (!host.startsWith("#") && !host.startsWith("\"")) {
|
||||
_adblockHosts.add(host);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void loadHostsFromRawAssetsAsync(final Context context) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
loadHostsFromRawAssets(context);
|
||||
_isLoaded = true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void loadHostsFromRawAssets(Context context) throws IOException {
|
||||
BufferedReader br = null;
|
||||
String host;
|
||||
|
||||
_adblockHosts.clear();
|
||||
for (int rawId : getAdblockIdsInRaw()) {
|
||||
try {
|
||||
br = new BufferedReader(new InputStreamReader(context.getResources().openRawResource(rawId)));
|
||||
while ((host = br.readLine()) != null) {
|
||||
addBlockedHosts(host);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(AdBlock.class.getName(), "Error: Cannot read adblock res " + rawId);
|
||||
} finally {
|
||||
if (br != null) {
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_adblockHostsFromRaw.clear();
|
||||
_adblockHostsFromRaw.addAll(_adblockHosts);
|
||||
}
|
||||
|
||||
private List<Integer> getAdblockIdsInRaw() {
|
||||
ArrayList<Integer> adblockResIds = new ArrayList<>();
|
||||
Field[] fields = R.raw.class.getFields();
|
||||
for (Field field : fields) {
|
||||
try {
|
||||
int resId = field.getInt(field);
|
||||
String resFilename = field.getName();
|
||||
if (resFilename.startsWith("adblock_domains__")) {
|
||||
adblockResIds.add(resId);
|
||||
}
|
||||
} catch (IllegalAccessException | IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
return adblockResIds;
|
||||
}
|
||||
}
|
||||
408
app/src/main/java/net/gsantner/opoc/util/AppSettingsBase.java
Normal file
408
app/src/main/java/net/gsantner/opoc/util/AppSettingsBase.java
Normal file
|
|
@ -0,0 +1,408 @@
|
|||
/*
|
||||
* ------------------------------------------------------------------------------
|
||||
* Gregor Santner <gsantner.github.io> wrote this. You can do whatever you want
|
||||
* with it. If we meet some day, and you think it is worth it, you can buy me a
|
||||
* coke in return. Provided as is without any kind of warranty. Do not blame or
|
||||
* sue me if something goes wrong. No attribution required. - Gregor Santner
|
||||
*
|
||||
* License: Creative Commons Zero (CC0 1.0)
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a wrapper for settings based on SharedPreferences
|
||||
* with keys in resources. Extend from this class and add
|
||||
* getters/setters for the app's settings.
|
||||
* Example:
|
||||
public boolean isAppFirstStart(boolean doSet) {
|
||||
boolean value = getBool(prefApp, R.string.pref_key__app_first_start, true);
|
||||
if (doSet) {
|
||||
setBool(prefApp, R.string.pref_key__app_first_start, false);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public boolean isAppCurrentVersionFirstStart(boolean doSet) {
|
||||
int value = getInt(prefApp, R.string.pref_key__app_first_start_current_version, -1);
|
||||
if (doSet) {
|
||||
setInt(prefApp, R.string.pref_key__app_first_start_current_version, BuildConfig.VERSION_CODE);
|
||||
}
|
||||
return value != BuildConfig.VERSION_CODE && !BuildConfig.IS_TEST_BUILD;
|
||||
}
|
||||
|
||||
* Maybe add a singleton for this:
|
||||
* Whereas App.get() is returning ApplicationContext
|
||||
private AppSettings(Context _context) {
|
||||
super(_context);
|
||||
}
|
||||
|
||||
public static AppSettings get() {
|
||||
return new AppSettings(App.get());
|
||||
}
|
||||
*/
|
||||
|
||||
package net.gsantner.opoc.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper for settings based on SharedPreferences with keys in resources
|
||||
* Default SharedPreference (_prefApp) will be taken if no SP is specified, else the first one
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "unused", "SpellCheckingInspection", "SameParameterValue"})
|
||||
public class AppSettingsBase {
|
||||
protected static final String ARRAY_SEPARATOR = "%%%";
|
||||
protected static final String ARRAY_SEPARATOR_SUBSTITUTE = "§§§";
|
||||
public static final String SHARED_PREF_APP = "app";
|
||||
|
||||
//########################
|
||||
//## Members, Constructors
|
||||
//########################
|
||||
protected final SharedPreferences _prefApp;
|
||||
protected final String _prefAppName;
|
||||
protected final Context _context;
|
||||
|
||||
public AppSettingsBase(final Context context) {
|
||||
this(context, SHARED_PREF_APP);
|
||||
}
|
||||
|
||||
public AppSettingsBase(final Context context, final String prefAppName) {
|
||||
_context = context.getApplicationContext();
|
||||
_prefAppName = TextUtils.isEmpty(prefAppName) ?
|
||||
_context.getPackageName() + "_preferences" : prefAppName;
|
||||
_prefApp = _context.getSharedPreferences(_prefAppName, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
//#####################
|
||||
//## Methods
|
||||
//#####################
|
||||
public Context getContext() {
|
||||
return _context;
|
||||
}
|
||||
|
||||
public boolean isKeyEqual(String key, int stringKeyResourceId) {
|
||||
return key.equals(rstr(stringKeyResourceId));
|
||||
}
|
||||
|
||||
public void resetSettings() {
|
||||
resetSettings(_prefApp);
|
||||
}
|
||||
|
||||
@SuppressLint("ApplySharedPref")
|
||||
public void resetSettings(final SharedPreferences pref) {
|
||||
pref.edit().clear().commit();
|
||||
}
|
||||
|
||||
public boolean isPrefSet(@StringRes int stringKeyResourceId) {
|
||||
return isPrefSet(_prefApp, stringKeyResourceId);
|
||||
}
|
||||
|
||||
public boolean isPrefSet(final SharedPreferences pref, @StringRes int stringKeyResourceId) {
|
||||
return pref.contains(rstr(stringKeyResourceId));
|
||||
}
|
||||
|
||||
public void registerPreferenceChangedListener(SharedPreferences.OnSharedPreferenceChangeListener value) {
|
||||
registerPreferenceChangedListener(_prefApp, value);
|
||||
}
|
||||
|
||||
public void registerPreferenceChangedListener(final SharedPreferences pref, SharedPreferences.OnSharedPreferenceChangeListener value) {
|
||||
pref.registerOnSharedPreferenceChangeListener(value);
|
||||
}
|
||||
|
||||
public void unregisterPreferenceChangedListener(SharedPreferences.OnSharedPreferenceChangeListener value) {
|
||||
unregisterPreferenceChangedListener(_prefApp, value);
|
||||
}
|
||||
|
||||
public void unregisterPreferenceChangedListener(final SharedPreferences pref, SharedPreferences.OnSharedPreferenceChangeListener value) {
|
||||
pref.unregisterOnSharedPreferenceChangeListener(value);
|
||||
}
|
||||
|
||||
public SharedPreferences getDefaultPreferences() {
|
||||
return _prefApp;
|
||||
}
|
||||
|
||||
public SharedPreferences.Editor getDefaultPreferencesEditor() {
|
||||
return _prefApp.edit();
|
||||
}
|
||||
|
||||
public String getDefaultPreferencesName() {
|
||||
return _prefAppName;
|
||||
}
|
||||
|
||||
|
||||
private SharedPreferences gp(final SharedPreferences... pref) {
|
||||
return (pref != null && pref.length > 0 ? pref[0] : _prefApp);
|
||||
}
|
||||
|
||||
//#################################
|
||||
//## Getter for resources
|
||||
//#################################
|
||||
public String rstr(@StringRes int stringKeyResourceId) {
|
||||
return _context.getString(stringKeyResourceId);
|
||||
}
|
||||
|
||||
public int rcolor(@ColorRes int resColorId) {
|
||||
return ContextCompat.getColor(_context, resColorId);
|
||||
}
|
||||
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for String
|
||||
//#################################
|
||||
public void setString(@StringRes int keyResourceId, String value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putString(rstr(keyResourceId), value).apply();
|
||||
}
|
||||
|
||||
public void setString(String key, String value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putString(key, value).apply();
|
||||
}
|
||||
|
||||
public void setString(@StringRes int keyResourceId, @StringRes int defaultValueResourceId, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putString(rstr(keyResourceId), rstr(defaultValueResourceId)).apply();
|
||||
}
|
||||
|
||||
public String getString(@StringRes int keyResourceId, String defaultValue, final SharedPreferences... pref) {
|
||||
return gp(pref).getString(rstr(keyResourceId), defaultValue);
|
||||
}
|
||||
|
||||
public String getString(@StringRes int keyResourceId, @StringRes int defaultValueResourceId, final SharedPreferences... pref) {
|
||||
return gp(pref).getString(rstr(keyResourceId), rstr(defaultValueResourceId));
|
||||
}
|
||||
|
||||
public String getString(String key, String defaultValue, final SharedPreferences... pref) {
|
||||
return gp(pref).getString(key, defaultValue);
|
||||
}
|
||||
|
||||
public String getString(@StringRes int keyResourceId, String defaultValue, @StringRes int keyResourceIdDefaultValue, final SharedPreferences... pref) {
|
||||
return gp(pref).getString(rstr(keyResourceId), rstr(keyResourceIdDefaultValue));
|
||||
}
|
||||
|
||||
public void setStringArray(@StringRes int keyResourceId, Object[] values, final SharedPreferences... pref) {
|
||||
setStringArray(rstr(keyResourceId), values, gp(pref));
|
||||
}
|
||||
|
||||
public void setStringArray(String key, Object[] values, final SharedPreferences... pref) {
|
||||
setStringArray(key, values, gp(pref));
|
||||
}
|
||||
|
||||
private void setStringArray(String key, Object[] values, final SharedPreferences pref) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Object value : values) {
|
||||
sb.append(ARRAY_SEPARATOR);
|
||||
sb.append(value.toString().replace(ARRAY_SEPARATOR, ARRAY_SEPARATOR_SUBSTITUTE));
|
||||
}
|
||||
setString(key, sb.toString().replaceFirst(ARRAY_SEPARATOR, ""), pref);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public String[] getStringArray(@StringRes int keyResourceId, final SharedPreferences... pref) {
|
||||
return getStringArray(rstr(keyResourceId), gp(pref));
|
||||
}
|
||||
|
||||
private String[] getStringArray(String key, final SharedPreferences... pref) {
|
||||
String value = gp(pref)
|
||||
.getString(key, ARRAY_SEPARATOR)
|
||||
.replace(ARRAY_SEPARATOR_SUBSTITUTE, ARRAY_SEPARATOR);
|
||||
if (value.equals(ARRAY_SEPARATOR)) {
|
||||
return new String[0];
|
||||
}
|
||||
return value.split(ARRAY_SEPARATOR);
|
||||
}
|
||||
|
||||
public void setStringList(@StringRes int keyResourceId, List<String> values, final SharedPreferences... pref) {
|
||||
setStringArray(rstr(keyResourceId), values.toArray(new String[values.size()]), pref);
|
||||
}
|
||||
|
||||
public void setStringList(String key, List<String> values, final SharedPreferences... pref) {
|
||||
setStringArray(key, values.toArray(new String[values.size()]), pref);
|
||||
}
|
||||
|
||||
public ArrayList<String> getStringList(@StringRes int keyResourceId, final SharedPreferences... pref) {
|
||||
return new ArrayList<>(Arrays.asList(getStringArray(rstr(keyResourceId), gp(pref))));
|
||||
}
|
||||
|
||||
public ArrayList<String> getStringList(String key, final SharedPreferences... pref) {
|
||||
return new ArrayList<>(Arrays.asList(getStringArray(key, gp(pref))));
|
||||
}
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for integer
|
||||
//#################################
|
||||
public void setInt(@StringRes int keyResourceId, int value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putInt(rstr(keyResourceId), value).apply();
|
||||
}
|
||||
|
||||
public void setInt(String key, int value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putInt(key, value).apply();
|
||||
}
|
||||
|
||||
public int getInt(@StringRes int keyResourceId, int defaultValue, final SharedPreferences... pref) {
|
||||
return gp(pref).getInt(rstr(keyResourceId), defaultValue);
|
||||
}
|
||||
|
||||
public int getInt(String key, int defaultValue, final SharedPreferences... pref) {
|
||||
return gp(pref).getInt(key, defaultValue);
|
||||
}
|
||||
|
||||
public int getIntOfStringPref(@StringRes int keyResId, int defaultValue, final SharedPreferences... pref) {
|
||||
return getIntOfStringPref(rstr(keyResId), defaultValue, gp(pref));
|
||||
}
|
||||
|
||||
public int getIntOfStringPref(String key, int defaultValue, final SharedPreferences... pref) {
|
||||
String strNum = getString(key, Integer.toString(defaultValue), gp(pref));
|
||||
return Integer.valueOf(strNum);
|
||||
}
|
||||
|
||||
|
||||
public void setIntArray(@StringRes int keyResourceId, Object[] values, final SharedPreferences... pref) {
|
||||
setIntArray(rstr(keyResourceId), values, gp(pref));
|
||||
}
|
||||
|
||||
public void setIntArray(String key, Object[] values, final SharedPreferences... pref) {
|
||||
setIntArray(key, values, gp(pref));
|
||||
}
|
||||
|
||||
private void setIntArray(String key, Object[] values, final SharedPreferences pref) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Object value : values) {
|
||||
sb.append(ARRAY_SEPARATOR);
|
||||
sb.append(value.toString());
|
||||
}
|
||||
setString(key, sb.toString().replaceFirst(ARRAY_SEPARATOR, ""), pref);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Integer[] getIntArray(@StringRes int keyResourceId, final SharedPreferences... pref) {
|
||||
return getIntArray(rstr(keyResourceId), gp(pref));
|
||||
}
|
||||
|
||||
private Integer[] getIntArray(String key, final SharedPreferences... pref) {
|
||||
String value = gp(pref).getString(key, ARRAY_SEPARATOR);
|
||||
if (value.equals(ARRAY_SEPARATOR)) {
|
||||
return new Integer[0];
|
||||
}
|
||||
String[] split = value.split(ARRAY_SEPARATOR);
|
||||
Integer[] ret = new Integer[split.length];
|
||||
for (int i = 0; i < ret.length; i++) {
|
||||
ret[i] = Integer.parseInt(split[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void setIntList(@StringRes int keyResourceId, List<Integer> values, final SharedPreferences... pref) {
|
||||
setIntArray(rstr(keyResourceId), values.toArray(new Integer[values.size()]), pref);
|
||||
}
|
||||
|
||||
public void setIntList(String key, List<Integer> values, final SharedPreferences... pref) {
|
||||
setIntArray(key, values.toArray(new Integer[values.size()]), pref);
|
||||
}
|
||||
|
||||
public ArrayList<Integer> getIntList(@StringRes int keyResourceId, final SharedPreferences... pref) {
|
||||
return new ArrayList<>(Arrays.asList(getIntArray(rstr(keyResourceId), gp(pref))));
|
||||
}
|
||||
|
||||
public ArrayList<Integer> getIntList(String key, final SharedPreferences... pref) {
|
||||
return new ArrayList<>(Arrays.asList(getIntArray(key, gp(pref))));
|
||||
}
|
||||
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for Long
|
||||
//#################################
|
||||
public void setLong(@StringRes int keyResourceId, long value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putLong(rstr(keyResourceId), value).apply();
|
||||
}
|
||||
|
||||
public void setLong(String key, long value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putLong(key, value).apply();
|
||||
}
|
||||
|
||||
public long getLong(@StringRes int keyResourceId, long defaultValue, final SharedPreferences... pref) {
|
||||
return gp(pref).getLong(rstr(keyResourceId), defaultValue);
|
||||
}
|
||||
|
||||
public long getLong(String key, long defaultValue, final SharedPreferences... pref) {
|
||||
return gp(pref).getLong(key, defaultValue);
|
||||
}
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for Float
|
||||
//#################################
|
||||
public void setFloat(@StringRes int keyResourceId, float value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putFloat(rstr(keyResourceId), value).apply();
|
||||
}
|
||||
|
||||
public void setFloat(String key, float value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putFloat(key, value).apply();
|
||||
}
|
||||
|
||||
public float getFloat(@StringRes int keyResourceId, float defaultValue, final SharedPreferences... pref) {
|
||||
return gp(pref).getFloat(rstr(keyResourceId), defaultValue);
|
||||
}
|
||||
|
||||
public float getFloat(String key, float defaultValue, final SharedPreferences... pref) {
|
||||
return gp(pref).getFloat(key, defaultValue);
|
||||
}
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for Double
|
||||
//#################################
|
||||
public void setDouble(@StringRes int keyResourceId, double value, final SharedPreferences... pref) {
|
||||
setLong(rstr(keyResourceId), Double.doubleToRawLongBits(value));
|
||||
}
|
||||
|
||||
public void setDouble(String key, double value, final SharedPreferences... pref) {
|
||||
setLong(key, Double.doubleToRawLongBits(value));
|
||||
}
|
||||
|
||||
public double getDouble(@StringRes int keyResourceId, double defaultValue, final SharedPreferences... pref) {
|
||||
return getDouble(rstr(keyResourceId), defaultValue, gp(pref));
|
||||
}
|
||||
|
||||
public double getDouble(String key, double defaultValue, final SharedPreferences... pref) {
|
||||
return Double.longBitsToDouble(getLong(key, Double.doubleToRawLongBits(defaultValue), gp(pref)));
|
||||
}
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for boolean
|
||||
//#################################
|
||||
public void setBool(@StringRes int keyResourceId, boolean value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putBoolean(rstr(keyResourceId), value).apply();
|
||||
}
|
||||
|
||||
public void setBool(String key, boolean value, final SharedPreferences... pref) {
|
||||
gp(pref).edit().putBoolean(key, value).apply();
|
||||
}
|
||||
|
||||
public boolean getBool(@StringRes int keyResourceId, boolean defaultValue, final SharedPreferences... pref) {
|
||||
return gp(pref).getBoolean(rstr(keyResourceId), defaultValue);
|
||||
}
|
||||
|
||||
public boolean getBool(String key, boolean defaultValue, final SharedPreferences... pref) {
|
||||
return gp(pref).getBoolean(key, defaultValue);
|
||||
}
|
||||
|
||||
//#################################
|
||||
//## Getter & Setter for Color
|
||||
//#################################
|
||||
public int getColor(String key, @ColorRes int defaultColor, final SharedPreferences... pref) {
|
||||
return gp(pref).getInt(key, rcolor(defaultColor));
|
||||
}
|
||||
|
||||
public int getColor(@StringRes int keyResourceId, @ColorRes int defaultColor, final SharedPreferences... pref) {
|
||||
return gp(pref).getInt(rstr(keyResourceId), rcolor(defaultColor));
|
||||
}
|
||||
}
|
||||
437
app/src/main/java/net/gsantner/opoc/util/ContextUtils.java
Normal file
437
app/src/main/java/net/gsantner/opoc/util/ContextUtils.java
Normal file
|
|
@ -0,0 +1,437 @@
|
|||
/*
|
||||
* ------------------------------------------------------------------------------
|
||||
* Gregor Santner <gsantner.github.io> wrote this. You can do whatever you want
|
||||
* with it. If we meet some day, and you think it is worth it, you can buy me a
|
||||
* coke in return. Provided as is without any kind of warranty. Do not blame or
|
||||
* sue me if something goes wrong. No attribution required. - Gregor Santner
|
||||
*
|
||||
* License: Creative Commons Zero (CC0 1.0)
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
package net.gsantner.opoc.util;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.AlarmManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.VectorDrawable;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.ColorRes;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.RawRes;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.graphics.drawable.VectorDrawableCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.graphics.drawable.DrawableCompat;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.AppCompatButton;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableString;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.Locale;
|
||||
|
||||
import static android.graphics.Bitmap.CompressFormat;
|
||||
|
||||
@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "SpellCheckingInspection", "deprecation"})
|
||||
public class ContextUtils {
|
||||
//########################
|
||||
//## Members, Constructors
|
||||
//########################
|
||||
protected Context _context;
|
||||
|
||||
public ContextUtils(Context context) {
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public Context context() {
|
||||
return _context;
|
||||
}
|
||||
|
||||
//########################
|
||||
//## Resources
|
||||
//########################
|
||||
static class ResType {
|
||||
public static final String DRAWABLE = "drawable";
|
||||
public static final String STRING = "string";
|
||||
public static final String PLURAL = "plural";
|
||||
public static final String COLOR = "color";
|
||||
public static final String STYLE = "style";
|
||||
public static final String ARRAY = "array";
|
||||
public static final String DIMEN = "dimen";
|
||||
public static final String MENU = "menu";
|
||||
public static final String RAW = "raw";
|
||||
}
|
||||
|
||||
public String str(@StringRes int strResId) {
|
||||
return _context.getString(strResId);
|
||||
}
|
||||
|
||||
public Drawable drawable(@DrawableRes int resId) {
|
||||
return ContextCompat.getDrawable(_context, resId);
|
||||
}
|
||||
|
||||
public int color(@ColorRes int resId) {
|
||||
return ContextCompat.getColor(_context, resId);
|
||||
}
|
||||
|
||||
public int getResId(final String type, final String name) {
|
||||
return _context.getResources().getIdentifier(name, type, _context.getPackageName());
|
||||
}
|
||||
|
||||
public boolean areResIdsAvailable(final String type, final String... names) {
|
||||
for (String name : names) {
|
||||
if (getResId(type, name) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//########################
|
||||
//## Methods
|
||||
//########################
|
||||
|
||||
public String colorToHexString(int intColor) {
|
||||
return String.format("#%06X", 0xFFFFFF & intColor);
|
||||
}
|
||||
|
||||
public String getAppVersionName() {
|
||||
try {
|
||||
PackageManager manager = _context.getPackageManager();
|
||||
PackageInfo info = manager.getPackageInfo(_context.getPackageName(), 0);
|
||||
return info.versionName;
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
public void openWebpageInExternalBrowser(final String url) {
|
||||
Uri uri = Uri.parse(url);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
_context.startActivity(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get field from PackageId.BuildConfig
|
||||
* May be helpful in libraries, where a access to
|
||||
* BuildConfig would only get values of the library
|
||||
* rather than the app ones
|
||||
*/
|
||||
public Object getBuildConfigValue(String fieldName) {
|
||||
try {
|
||||
Class<?> c = Class.forName(_context.getPackageName() + ".BuildConfig");
|
||||
return c.getField(fieldName).get(null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getBuildConfigBoolean(String fieldName, boolean defaultValue) {
|
||||
Object field = getBuildConfigValue(fieldName);
|
||||
if (field != null && field instanceof Boolean) {
|
||||
return (Boolean) field;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public boolean isGooglePlayBuild() {
|
||||
return getBuildConfigBoolean("IS_GPLAY_BUILD", true);
|
||||
}
|
||||
|
||||
public boolean isFossBuild() {
|
||||
return getBuildConfigBoolean("IS_FOSS_BUILD", false);
|
||||
}
|
||||
|
||||
// Requires donate__bitcoin_* resources (see below) to be available as string resource
|
||||
public void showDonateBitcoinRequest(@StringRes final int strResBitcoinId, @StringRes final int strResBitcoinAmount, @StringRes final int strResBitcoinMessage, @StringRes final int strResAlternativeDonateUrl) {
|
||||
if (!isGooglePlayBuild()) {
|
||||
String btcUri = String.format("bitcoin:%s?amount=%s&label=%s&message=%s",
|
||||
str(strResBitcoinId), str(strResBitcoinAmount),
|
||||
str(strResBitcoinMessage), str(strResBitcoinMessage));
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(btcUri));
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
try {
|
||||
_context.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
openWebpageInExternalBrowser(str(strResAlternativeDonateUrl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String readTextfileFromRawRes(@RawRes int rawResId, String linePrefix, String linePostfix) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BufferedReader br = null;
|
||||
String line;
|
||||
|
||||
linePrefix = linePrefix == null ? "" : linePrefix;
|
||||
linePostfix = linePostfix == null ? "" : linePostfix;
|
||||
|
||||
try {
|
||||
br = new BufferedReader(new InputStreamReader(_context.getResources().openRawResource(rawResId)));
|
||||
while ((line = br.readLine()) != null) {
|
||||
sb.append(linePrefix);
|
||||
sb.append(line);
|
||||
sb.append(linePostfix);
|
||||
sb.append("\n");
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
} finally {
|
||||
if (br != null) {
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void showDialogWithRawFileInWebView(String fileInRaw, @StringRes int resTitleId) {
|
||||
WebView wv = new WebView(_context);
|
||||
wv.loadUrl("file:///android_res/raw/" + fileInRaw);
|
||||
AlertDialog.Builder dialog = new AlertDialog.Builder(_context)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.setTitle(resTitleId)
|
||||
.setView(wv);
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
@SuppressLint("RestrictedApi")
|
||||
@SuppressWarnings("RestrictedApi")
|
||||
public void setTintColorOfButton(AppCompatButton button, @ColorRes int resColor) {
|
||||
button.setSupportBackgroundTintList(ColorStateList.valueOf(
|
||||
color(resColor)
|
||||
));
|
||||
}
|
||||
|
||||
public boolean isConnectedToInternet() {
|
||||
ConnectivityManager connectivityManager = (ConnectivityManager)
|
||||
_context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo activeNetInfo = connectivityManager.getActiveNetworkInfo();
|
||||
return activeNetInfo != null && activeNetInfo.isConnectedOrConnecting();
|
||||
}
|
||||
|
||||
public boolean isConnectedToInternet(@Nullable @StringRes Integer warnMessageStringRes) {
|
||||
final boolean result = isConnectedToInternet();
|
||||
if (!result && warnMessageStringRes != null)
|
||||
Toast.makeText(_context, _context.getString(warnMessageStringRes), Toast.LENGTH_SHORT).show();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void restartApp(Class classToStartupWith) {
|
||||
Intent restartIntent = new Intent(_context, classToStartupWith);
|
||||
PendingIntent restartIntentP = PendingIntent.getActivity(_context, 555,
|
||||
restartIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
AlarmManager mgr = (AlarmManager) _context.getSystemService(Context.ALARM_SERVICE);
|
||||
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, restartIntentP);
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
public String loadMarkdownForTextViewFromRaw(@RawRes int rawMdFile, String prepend) {
|
||||
try {
|
||||
return new SimpleMarkdownParser()
|
||||
.parse(_context.getResources().openRawResource(rawMdFile),
|
||||
prepend, SimpleMarkdownParser.FILTER_ANDROID_TEXTVIEW)
|
||||
.replaceColor("#000001", color(getResId(ResType.COLOR, "accent")))
|
||||
.removeMultiNewlines().replaceBulletCharacter("*").getHtml();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public void setHtmlToTextView(TextView textView, String html) {
|
||||
textView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
textView.setText(new SpannableString(htmlToSpanned(html)));
|
||||
}
|
||||
|
||||
public double getEstimatedScreenSizeInches() {
|
||||
DisplayMetrics dm = _context.getResources().getDisplayMetrics();
|
||||
|
||||
double density = dm.density * 160;
|
||||
double x = Math.pow(dm.widthPixels / density, 2);
|
||||
double y = Math.pow(dm.heightPixels / density, 2);
|
||||
double screenInches = Math.sqrt(x + y) * 1.16; // 1.16 = est. Nav/Statusbar
|
||||
screenInches = screenInches < 4.0 ? 4.0 : screenInches;
|
||||
screenInches = screenInches > 12.0 ? 12.0 : screenInches;
|
||||
return screenInches;
|
||||
}
|
||||
|
||||
public boolean isInPortraitMode() {
|
||||
return _context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
|
||||
}
|
||||
|
||||
public Locale getLocaleByAndroidCode(String code) {
|
||||
if (!TextUtils.isEmpty(code)) {
|
||||
return code.contains("-r")
|
||||
? new Locale(code.substring(0, 2), code.substring(4, 6)) // de-rAt
|
||||
: new Locale(code); // de
|
||||
}
|
||||
return Resources.getSystem().getConfiguration().locale;
|
||||
}
|
||||
|
||||
// en/de/de-rAt ; Empty string -> default locale
|
||||
public void setAppLanguage(String androidLocaleString) {
|
||||
Locale locale = getLocaleByAndroidCode(androidLocaleString);
|
||||
Configuration config = _context.getResources().getConfiguration();
|
||||
config.locale = (locale != null && !androidLocaleString.isEmpty())
|
||||
? locale : Resources.getSystem().getConfiguration().locale;
|
||||
_context.getResources().updateConfiguration(config, null);
|
||||
}
|
||||
|
||||
// Find out if color above the given color should be light or dark. true if light
|
||||
public boolean shouldColorOnTopBeLight(int colorOnBottomInt) {
|
||||
return 186 > (((0.299 * Color.red(colorOnBottomInt))
|
||||
+ ((0.587 * Color.green(colorOnBottomInt))
|
||||
+ (0.114 * Color.blue(colorOnBottomInt)))));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public Spanned htmlToSpanned(String html) {
|
||||
Spanned result;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
result = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
|
||||
} else {
|
||||
result = Html.fromHtml(html);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public float px2dp(final float px) {
|
||||
return px / _context.getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
public float dp2px(final float dp) {
|
||||
return dp * _context.getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
public void setViewVisible(View view, boolean visible) {
|
||||
view.setVisibility(visible ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
public static void setDrawableWithColorToImageView(ImageView imageView, @DrawableRes int drawableResId, @ColorRes int colorResId) {
|
||||
imageView.setImageResource(drawableResId);
|
||||
imageView.setColorFilter(ContextCompat.getColor(imageView.getContext(), colorResId));
|
||||
}
|
||||
|
||||
public Bitmap drawableToBitmap(Drawable drawable) {
|
||||
Bitmap bitmap = null;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && (drawable instanceof VectorDrawable || drawable instanceof VectorDrawableCompat)) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
drawable = (DrawableCompat.wrap(drawable)).mutate();
|
||||
}
|
||||
|
||||
bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
|
||||
drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
|
||||
drawable.draw(canvas);
|
||||
} else if (drawable instanceof BitmapDrawable) {
|
||||
bitmap = ((BitmapDrawable) drawable).getBitmap();
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public Bitmap loadImageFromFilesystem(String imagePath, int maxDimen) {
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeFile(imagePath, options);
|
||||
options.inSampleSize = calculateInSampleSize(options, maxDimen);
|
||||
options.inJustDecodeBounds = false;
|
||||
return BitmapFactory.decodeFile(imagePath, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the scaling factor so the bitmap is maximal as big as the maxDimen
|
||||
*
|
||||
* @param options Bitmap-options that contain the current dimensions of the bitmap
|
||||
* @param maxDimen Max size of the Bitmap (width or height)
|
||||
* @return the scaling factor that needs to be applied to the bitmap
|
||||
*/
|
||||
public int calculateInSampleSize(BitmapFactory.Options options, int maxDimen) {
|
||||
// Raw height and width of image
|
||||
int height = options.outHeight;
|
||||
int width = options.outWidth;
|
||||
int inSampleSize = 1;
|
||||
|
||||
if (Math.max(height, width) > maxDimen) {
|
||||
inSampleSize = Math.round(1f * Math.max(height, width) / maxDimen);
|
||||
}
|
||||
return inSampleSize;
|
||||
}
|
||||
|
||||
public Bitmap scaleBitmap(Bitmap bitmap, int maxDimen) {
|
||||
int picSize = Math.min(bitmap.getHeight(), bitmap.getWidth());
|
||||
float scale = 1.f * maxDimen / picSize;
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postScale(scale, scale);
|
||||
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
}
|
||||
|
||||
public File writeImageToFileJpeg(String path, String filename, Bitmap image) {
|
||||
return writeImageToFile(path, filename, image, Bitmap.CompressFormat.JPEG, 95);
|
||||
}
|
||||
|
||||
public File writeImageToFile(String path, String filename, Bitmap image, CompressFormat format, int quality) {
|
||||
File imageFile = new File(path);
|
||||
if (imageFile.exists() || imageFile.mkdirs()) {
|
||||
imageFile = new File(path, filename);
|
||||
|
||||
FileOutputStream stream = null;
|
||||
try {
|
||||
stream = new FileOutputStream(imageFile); // overwrites this image every time
|
||||
image.compress(format, quality, stream);
|
||||
return imageFile;
|
||||
} catch (FileNotFoundException ignored) {
|
||||
} finally {
|
||||
try {
|
||||
if (stream != null) {
|
||||
stream.close();
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,230 @@
|
|||
/*
|
||||
* ------------------------------------------------------------------------------
|
||||
* Gregor Santner <gsantner.github.io> wrote this. You can do whatever you want
|
||||
* with it. If we meet some day, and you think it is worth it, you can buy me a
|
||||
* coke in return. Provided as is without any kind of warranty. Do not blame or
|
||||
* sue me if something goes wrong. No attribution required. - Gregor Santner
|
||||
*
|
||||
* License: Creative Commons Zero (CC0 1.0)
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get updates:
|
||||
* https://github.com/gsantner/onePieceOfCode/blob/master/java/SimpleMarkdownParser.java
|
||||
* Apply to TextView:
|
||||
* See https://github.com/gsantner/onePieceOfCode/blob/master/android/ContextUtils.java
|
||||
* Parses most common markdown tags. Only inline tags are supported, multiline/block syntax
|
||||
* is not supported (citation, multiline code, ..). This is intended to stay as easy as possible.
|
||||
*
|
||||
* You can e.g. apply a accent color by replacing #000001 with your accentColor string.
|
||||
*
|
||||
* FILTER_ANDROID_TEXTVIEW output is intended to be used at simple Android TextViews,
|
||||
* were a limited set of _html tags is supported. This allow to still display e.g. a simple
|
||||
* CHANGELOG.md file without including a WebView for showing HTML, or other additional UI-libraries.
|
||||
*
|
||||
* FILTER_WEB is intended to be used at engines understanding most common HTML tags.
|
||||
*/
|
||||
|
||||
package net.gsantner.opoc.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
|
||||
/**
|
||||
* Simple Markdown Parser
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "CaughtExceptionImmediatelyRethrown", "SameParameterValue", "unused", "SpellCheckingInspection", "RepeatedSpace", "SingleCharAlternation"})
|
||||
public class SimpleMarkdownParser {
|
||||
//########################
|
||||
//## Statics
|
||||
//########################
|
||||
public interface SmpFilter {
|
||||
String filter(String text);
|
||||
}
|
||||
|
||||
public final static SmpFilter FILTER_ANDROID_TEXTVIEW = new SmpFilter() {
|
||||
@Override
|
||||
public String filter(String text) {
|
||||
// TextView supports a limited set of html tags, most notably
|
||||
// a href, b, big, font size&color, i, li, small, u
|
||||
|
||||
// Don't start new line if 2 empty lines and heading
|
||||
while (text.contains("\n\n#")) {
|
||||
text = text.replace("\n\n#", "\n#");
|
||||
}
|
||||
|
||||
return text
|
||||
.replaceAll("(?s)<!--.*?-->", "") // HTML comments
|
||||
.replace("\n\n", "\n<br/>\n") // Start new line if 2 empty lines
|
||||
.replace("~°", " ") // double space/half tab
|
||||
.replaceAll("(?m)^### (.*)$", "<br/><big><b><font color='#000000'>$1</font></b></big><br/>") // h3
|
||||
.replaceAll("(?m)^## (.*)$", "<br/><big><big><b><font color='#000000'>$1</font></b></big></big><br/><br/>") // h2 (DEP: h3)
|
||||
.replaceAll("(?m)^# (.*)$", "<br/><big><big><big><b><font color='#000000'>$1</font></b></big></big></big><br/><br/>") // h1 (DEP: h2,h3)
|
||||
.replaceAll("!\\[(.*?)\\]\\((.*?)\\)", "<a href=\\'$2\\'>$1</a>") // img
|
||||
.replaceAll("\\[(.*?)\\]\\((.*?)\\)", "<a href=\\'$2\\'>$1</a>") // a href (DEP: img)
|
||||
.replaceAll("<(http|https):\\/\\/(.*)>", "<a href='$1://$2'>$1://$2</a>") // a href (DEP: img)
|
||||
.replaceAll("(?m)^([-*] )(.*)$", "<font color='#000001'>•</font> $2<br/>") // unordered list + end line
|
||||
.replaceAll("(?m)^ (-|\\*) ([^<]*)$", " <font color='#000001'>•</font> $2<br/>") // unordered list2 + end line
|
||||
.replaceAll("`([^<]*)`", "<font face='monospace'>$1</font>") // code
|
||||
.replace("\\*", "●") // temporary replace escaped star symbol
|
||||
.replaceAll("(?m)\\*\\*(.*)\\*\\*", "<b>$1</b>") // bold (DEP: temp star)
|
||||
.replaceAll("(?m)\\*(.*)\\*", "<i>$1</i>") // italic (DEP: temp star code)
|
||||
.replace("●", "*") // restore escaped star symbol (DEP: b,i)
|
||||
.replaceAll("(?m) $", "<br/>") // new line (DEP: ul)
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
public final static SmpFilter FILTER_WEB = new SmpFilter() {
|
||||
@Override
|
||||
public String filter(String text) {
|
||||
// Don't start new line if 2 empty lines and heading
|
||||
while (text.contains("\n\n#")) {
|
||||
text = text.replace("\n\n#", "\n#");
|
||||
}
|
||||
|
||||
text = text
|
||||
.replaceAll("(?s)<!--.*?-->", "") // HTML comments
|
||||
.replace("\n\n", "\n<br/>\n") // Start new line if 2 empty lines
|
||||
.replaceAll("~°", " ") // double space/half tab
|
||||
.replaceAll("(?m)^### (.*)$", "<h3>$1</h3>") // h3
|
||||
.replaceAll("(?m)^## (.*)$", "<h2>$1</h2>") /// h2 (DEP: h3)
|
||||
.replaceAll("(?m)^# (.*)$", "<h1>$1</h1>") // h1 (DEP: h2,h3)
|
||||
.replaceAll("!\\[(.*?)\\]\\((.*?)\\)", "<img src=\\'$2\\' alt='$1' />") // img
|
||||
.replaceAll("<(http|https):\\/\\/(.*)>", "<a href='$1://$2'>$1://$2</a>") // a href (DEP: img)
|
||||
.replaceAll("\\[(.*?)\\]\\((.*?)\\)", "<a href=\\'$2\\'>$1</a>") // a href (DEP: img)
|
||||
.replaceAll("(?m)^([-*] )(.*)$", "<font color='#000001'>•</font> $2 ") // unordered list + end line
|
||||
.replaceAll("(?m)^ (-|\\*) ([^<]*)$", " <font color='#000001'>•</font> $2 ") // unordered list2 + end line
|
||||
.replaceAll("`([^<]*)`", "<code>$1</code>") // code
|
||||
.replace("\\*", "●") // temporary replace escaped star symbol
|
||||
.replaceAll("(?m)\\*\\*(.*)\\*\\*", "<b>$1</b>") // bold (DEP: temp star)
|
||||
.replaceAll("(?m)\\*(.*)\\*", "<i>$1</i>") // italic (DEP: temp star code)
|
||||
.replace("●", "*") // restore escaped star symbol (DEP: b,i)
|
||||
.replaceAll("(?m) $", "<br/>") // new line (DEP: ul)
|
||||
;
|
||||
return text;
|
||||
}
|
||||
};
|
||||
|
||||
public final static SmpFilter FILTER_CHANGELOG = new SmpFilter() {
|
||||
@Override
|
||||
public String filter(String text) {
|
||||
text = text
|
||||
.replace("New:", "<font color='#276230'>New:</font>")
|
||||
.replace("Added:", "<font color='#276230'>Added:</font>")
|
||||
.replace("Fixed:", "<font color='#005688'>Fixed:</font>")
|
||||
.replace("Removed:", "<font color='#C13524'>Removed:</font>")
|
||||
.replace("Updated:", "<font color='#555555'>Updated:</font>")
|
||||
.replace("Improved:", "<font color='#555555'>Improved:</font>")
|
||||
.replace("Modified:", "<font color='#555555'>Modified:</font>")
|
||||
;
|
||||
return text;
|
||||
}
|
||||
};
|
||||
|
||||
//########################
|
||||
//## Singleton
|
||||
//########################
|
||||
private static SimpleMarkdownParser __instance;
|
||||
|
||||
public static SimpleMarkdownParser get() {
|
||||
if (__instance == null) {
|
||||
__instance = new SimpleMarkdownParser();
|
||||
}
|
||||
return __instance;
|
||||
}
|
||||
|
||||
//########################
|
||||
//## Members, Constructors
|
||||
//########################
|
||||
private SmpFilter _defaultSmpFilter;
|
||||
private String _html;
|
||||
|
||||
public SimpleMarkdownParser() {
|
||||
setDefaultSmpFilter(FILTER_WEB);
|
||||
}
|
||||
|
||||
//########################
|
||||
//## Methods
|
||||
//########################
|
||||
public SimpleMarkdownParser setDefaultSmpFilter(SmpFilter defaultSmpFilter) {
|
||||
_defaultSmpFilter = defaultSmpFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleMarkdownParser parse(String filepath, SmpFilter... smpFilters) throws IOException {
|
||||
return parse(new FileInputStream(filepath), "", smpFilters);
|
||||
}
|
||||
|
||||
public SimpleMarkdownParser parse(InputStream inputStream, String lineMdPrefix, SmpFilter... smpFilters) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
BufferedReader br = null;
|
||||
String line;
|
||||
|
||||
try {
|
||||
br = new BufferedReader(new InputStreamReader(inputStream));
|
||||
while ((line = br.readLine()) != null) {
|
||||
sb.append(lineMdPrefix);
|
||||
sb.append(line);
|
||||
sb.append("\n");
|
||||
}
|
||||
} catch (IOException rethrow) {
|
||||
_html = "";
|
||||
throw rethrow;
|
||||
} finally {
|
||||
if (br != null) {
|
||||
try {
|
||||
br.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
_html = parse(sb.toString(), "", smpFilters).getHtml();
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleMarkdownParser parse(String markdown, String lineMdPrefix, SmpFilter... smpFilters) throws IOException {
|
||||
_html = markdown;
|
||||
if (smpFilters.length == 0) {
|
||||
smpFilters = new SmpFilter[]{_defaultSmpFilter};
|
||||
}
|
||||
for (SmpFilter smpFilter : smpFilters) {
|
||||
_html = smpFilter.filter(_html).trim();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getHtml() {
|
||||
return _html;
|
||||
}
|
||||
|
||||
public SimpleMarkdownParser setHtml(String html) {
|
||||
_html = html;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleMarkdownParser removeMultiNewlines() {
|
||||
_html = _html.replace("\n", "").replaceAll("(<br/>){3,}", "<br/><br/>");
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleMarkdownParser replaceBulletCharacter(String replacment) {
|
||||
_html = _html.replace("•", replacment);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SimpleMarkdownParser replaceColor(String hexColor, int newIntColor) {
|
||||
_html = _html.replace(hexColor, String.format("#%06X", 0xFFFFFF & newIntColor));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return _html != null ? _html : "";
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue