Unverified Commit 6fbd399a authored by gsantner's avatar gsantner 🦀
Browse files

Update gsantner/opoc libs/utils

parent fa7e37cc
...@@ -125,6 +125,20 @@ public class SimpleMarkdownParser { ...@@ -125,6 +125,20 @@ public class SimpleMarkdownParser {
return text; return text;
} }
}; };
public final static SmpFilter FILTER_H_TO_SUP = new SmpFilter() {
@Override
public String filter(String text) {
text = text
.replace("<h1>", "<sup><sup><sup>")
.replace("</h1>", "</sup></sup></sup>")
.replace("<h2>", "<sup><sup>")
.replace("</h2>", "</sup></sup>")
.replace("<h3>", "<sup>")
.replace("</h3>", "</sup>")
;
return text;
}
};
public final static SmpFilter FILTER_NONE = new SmpFilter() { public final static SmpFilter FILTER_NONE = new SmpFilter() {
@Override @Override
public String filter(String text) { public String filter(String text) {
......
...@@ -11,12 +11,14 @@ ...@@ -11,12 +11,14 @@
package net.gsantner.opoc.ui; package net.gsantner.opoc.ui;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build; import android.os.Build;
import android.support.annotation.ColorInt; import android.support.annotation.ColorInt;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.StringRes; import android.support.annotation.StringRes;
...@@ -24,10 +26,14 @@ import android.support.design.widget.Snackbar; ...@@ -24,10 +26,14 @@ import android.support.design.widget.Snackbar;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.widget.AppCompatEditText; import android.support.v7.widget.AppCompatEditText;
import android.text.Editable; import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Pair;
import android.view.Gravity; import android.view.Gravity;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.Window; import android.view.Window;
...@@ -58,16 +64,23 @@ public class SearchOrCustomTextDialog { ...@@ -58,16 +64,23 @@ public class SearchOrCustomTextDialog {
public static class DialogOptions { public static class DialogOptions {
public Callback.a1<String> callback; public Callback.a1<String> callback;
public List<? extends CharSequence> data = new ArrayList<>(); public Callback.a2<String, Integer> withPositionCallback;
public List<? extends CharSequence> highlightData = new ArrayList<>(); public List<? extends CharSequence> data;
public List<Integer> iconsForData = new ArrayList<>(); public List<? extends CharSequence> highlightData;
public List<Integer> iconsForData;
public String messageText = ""; public String messageText = "";
public String defaultText = "";
public boolean isSearchEnabled = true; public boolean isSearchEnabled = true;
public boolean isDarkDialog = false; public boolean isDarkDialog = false;
public int dialogWidthDp = WindowManager.LayoutParams.MATCH_PARENT; public int dialogWidthDp = WindowManager.LayoutParams.MATCH_PARENT;
public int dialogHeightDp = WindowManager.LayoutParams.WRAP_CONTENT; public int dialogHeightDp = WindowManager.LayoutParams.WRAP_CONTENT;
public int gravity = Gravity.NO_GRAVITY; public int gravity = Gravity.NO_GRAVITY;
public int searchInputType = 0; public int searchInputType = 0;
public boolean searchIsRegex = false;
public Callback.a1<Spannable> highlighter;
public String extraFilter = null;
public Callback.a0 neutralButtonCallback = null;
@ColorInt @ColorInt
public int textColor = 0xFF000000; public int textColor = 0xFF000000;
...@@ -76,77 +89,122 @@ public class SearchOrCustomTextDialog { ...@@ -76,77 +89,122 @@ public class SearchOrCustomTextDialog {
@StringRes @StringRes
public int cancelButtonText = android.R.string.cancel; public int cancelButtonText = android.R.string.cancel;
@StringRes @StringRes
public int neutralButtonText = 0;
@StringRes
public int okButtonText = android.R.string.ok; public int okButtonText = android.R.string.ok;
@StringRes @StringRes
public int titleText = android.R.string.untitled; public int titleText = 0;
@StringRes @StringRes
public int searchHintText = android.R.string.search_go; public int searchHintText = android.R.string.search_go;
} }
public static void showMultiChoiceDialogWithSearchFilterUI(final Activity activity, final DialogOptions dopt) { private static class WithPositionAdapter extends ArrayAdapter<Pair<String, Integer>> {
final List<CharSequence> allItems = new ArrayList<>(dopt.data);
final List<CharSequence> filteredItems = new ArrayList<>(allItems); final LayoutInflater mInflater;
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity, dopt.isDarkDialog final @LayoutRes
? android.support.v7.appcompat.R.style.Theme_AppCompat_Dialog int mLayout;
: android.support.v7.appcompat.R.style.Theme_AppCompat_Light_Dialog final DialogOptions dopt;
); final List<Pair<String, Integer>> filteredItems;
final Pattern extraPattern;
WithPositionAdapter(Context context, @LayoutRes int layout, List<Pair<String, Integer>> filteredItems, DialogOptions dopt) {
super(context, layout, filteredItems);
mInflater = LayoutInflater.from(context);
mLayout = layout;
this.dopt = dopt;
this.filteredItems = filteredItems;
extraPattern = dopt.extraFilter == null ? null : Pattern.compile(dopt.extraFilter);
}
final ArrayAdapter<CharSequence> listAdapter = new ArrayAdapter<CharSequence>(activity, android.R.layout.simple_list_item_1, filteredItems) { @NonNull
@NonNull @Override
@Override public View getView(int pos, @Nullable View convertView, @NonNull ViewGroup parent) {
public View getView(int pos, @Nullable View convertView, @NonNull ViewGroup parent) { final Pair<String, Integer> item = getItem(pos);
TextView textView = (TextView) super.getView(pos, convertView, parent); final String text = item.first;
String text = textView.getText().toString(); final int posInOriginalList = item.second;
int posInOriginalList = dopt.data.indexOf(text); final TextView textView;
if (posInOriginalList >= 0 && dopt.iconsForData != null && posInOriginalList < dopt.iconsForData.size() && dopt.iconsForData.get(posInOriginalList) != 0) { if (convertView == null) {
textView.setCompoundDrawablesWithIntrinsicBounds(dopt.iconsForData.get(posInOriginalList), 0, 0, 0); textView = (TextView) mInflater.inflate(mLayout, parent, false);
textView.setCompoundDrawablePadding(32); } else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { textView = (TextView) convertView;
textView.setCompoundDrawableTintList(ColorStateList.valueOf(dopt.isDarkDialog ? Color.WHITE : Color.BLACK)); }
}
} else { if (posInOriginalList >= 0 && dopt.iconsForData != null && posInOriginalList < dopt.iconsForData.size() && dopt.iconsForData.get(posInOriginalList) != 0) {
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); textView.setCompoundDrawablesWithIntrinsicBounds(dopt.iconsForData.get(posInOriginalList), 0, 0, 0);
textView.setCompoundDrawablePadding(32);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
textView.setCompoundDrawableTintList(ColorStateList.valueOf(dopt.isDarkDialog ? Color.WHITE : Color.BLACK));
} }
} else {
textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
}
boolean hl = dopt.highlightData.contains(text); if (dopt.highlightData != null) {
final boolean hl = dopt.highlightData.contains(text);
textView.setTextColor(hl ? dopt.highlightColor : dopt.textColor); textView.setTextColor(hl ? dopt.highlightColor : dopt.textColor);
textView.setTypeface(null, hl ? Typeface.BOLD : Typeface.NORMAL); textView.setTypeface(null, hl ? Typeface.BOLD : Typeface.NORMAL);
}
return textView; if (dopt.highlighter != null) {
Spannable s = new SpannableString(text);
dopt.highlighter.callback(s);
textView.setText(s);
} else {
textView.setText(text);
} }
@Override return textView;
public Filter getFilter() { }
return new Filter() {
@SuppressWarnings("unchecked")
@Override
protected void publishResults(final CharSequence constraint, final FilterResults results) {
filteredItems.clear();
filteredItems.addAll((List<String>) results.values);
notifyDataSetChanged();
}
@Override @Override
protected FilterResults performFiltering(final CharSequence constraint) { public Filter getFilter() {
final FilterResults res = new FilterResults(); return new Filter() {
final ArrayList<CharSequence> resList = new ArrayList<>(); @SuppressWarnings("unchecked")
final String fil = constraint.toString(); @Override
protected void publishResults(final CharSequence constraint, final FilterResults results) {
filteredItems.clear();
filteredItems.addAll((List<Pair<String, Integer>>) results.values);
notifyDataSetChanged();
}
for (final CharSequence str : allItems) { @Override
if ("".equals(fil) || str.toString().toLowerCase(Locale.getDefault()).contains(fil.toLowerCase(Locale.getDefault()))) { protected FilterResults performFiltering(final CharSequence constraint) {
resList.add(str); final ArrayList<Pair<CharSequence, Integer>> resList = new ArrayList<>();
if (dopt.data != null) {
final String fil = constraint.toString();
final boolean emptySearch = fil.isEmpty();
for (int i = 0; i < dopt.data.size(); i++) {
final CharSequence str = dopt.data.get(i);
final boolean matchExtra = (extraPattern == null) || extraPattern.matcher(str).find();
final boolean matchNormal = str.toString().toLowerCase(Locale.getDefault()).contains(fil.toLowerCase(Locale.getDefault()));
final boolean matchRegex = dopt.searchIsRegex && (str.toString().matches(fil));
if (matchExtra && (matchNormal || matchRegex || emptySearch)) {
resList.add(new Pair<>(str, i));
} }
} }
res.values = resList;
res.count = resList.size();
return res;
} }
};
} final FilterResults res = new FilterResults();
}; res.values = resList;
res.count = resList.size();
return res;
}
};
}
}
public static void showMultiChoiceDialogWithSearchFilterUI(final Activity activity, final DialogOptions dopt) {
final List<Pair<String, Integer>> filteredItems = new ArrayList<>();
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity, dopt.isDarkDialog
? android.support.v7.appcompat.R.style.Theme_AppCompat_Dialog
: android.support.v7.appcompat.R.style.Theme_AppCompat_Light_Dialog
);
final WithPositionAdapter listAdapter = new WithPositionAdapter(activity, android.R.layout.simple_list_item_1, filteredItems, dopt);
final AppCompatEditText searchEditText = new AppCompatEditText(activity); final AppCompatEditText searchEditText = new AppCompatEditText(activity);
searchEditText.setText(dopt.defaultText);
searchEditText.setSingleLine(true); searchEditText.setSingleLine(true);
searchEditText.setMaxLines(1); searchEditText.setMaxLines(1);
searchEditText.setTextColor(dopt.textColor); searchEditText.setTextColor(dopt.textColor);
...@@ -174,24 +232,35 @@ public class SearchOrCustomTextDialog { ...@@ -174,24 +232,35 @@ public class SearchOrCustomTextDialog {
listView.setAdapter(listAdapter); listView.setAdapter(listAdapter);
listView.setVisibility(dopt.data != null && !dopt.data.isEmpty() ? View.VISIBLE : View.GONE); listView.setVisibility(dopt.data != null && !dopt.data.isEmpty() ? View.VISIBLE : View.GONE);
linearLayout.setOrientation(LinearLayout.VERTICAL); linearLayout.setOrientation(LinearLayout.VERTICAL);
if (dopt.isSearchEnabled) { if (dopt.isSearchEnabled) {
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);
int px = (int) (new ContextUtils(listView.getContext()).convertDpToPx(8)); int px = (int) (new ContextUtils(listView.getContext()).convertDpToPx(8));
lp.setMargins(px, px / 2, px, px / 2); lp.setMargins(px, px / 2, px, px / 2);
linearLayout.addView(searchEditText, lp); linearLayout.addView(searchEditText, lp);
} }
final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0); final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0);
layoutParams.weight = 1; layoutParams.weight = 1;
linearLayout.addView(listView, layoutParams); linearLayout.addView(listView, layoutParams);
if (!TextUtils.isEmpty(dopt.messageText)) { if (!TextUtils.isEmpty(dopt.messageText)) {
dialogBuilder.setMessage(dopt.messageText); dialogBuilder.setMessage(dopt.messageText);
} }
dialogBuilder.setView(linearLayout) dialogBuilder.setView(linearLayout)
.setOnCancelListener(null) .setOnCancelListener(null)
.setNegativeButton(dopt.cancelButtonText, (dialogInterface, i) -> dialogInterface.dismiss()); .setNegativeButton(dopt.cancelButtonText, (dialogInterface, i) -> dialogInterface.dismiss());
if (dopt.neutralButtonCallback != null && dopt.neutralButtonText != 0) {
dialogBuilder.setNeutralButton(dopt.neutralButtonText, (dialogInterface, i) -> {
dopt.neutralButtonCallback.callback();
});
}
if (dopt.titleText != 0) { if (dopt.titleText != 0) {
dialogBuilder.setTitle(dopt.titleText); dialogBuilder.setTitle(dopt.titleText);
} }
if (dopt.isSearchEnabled) { if (dopt.isSearchEnabled) {
dialogBuilder.setPositiveButton(dopt.okButtonText, (dialogInterface, i) -> { dialogBuilder.setPositiveButton(dopt.okButtonText, (dialogInterface, i) -> {
dialogInterface.dismiss(); dialogInterface.dismiss();
...@@ -205,7 +274,11 @@ public class SearchOrCustomTextDialog { ...@@ -205,7 +274,11 @@ public class SearchOrCustomTextDialog {
listView.setOnItemClickListener((parent, view, position, id) -> { listView.setOnItemClickListener((parent, view, position, id) -> {
dialog.dismiss(); dialog.dismiss();
if (dopt.callback != null) { if (dopt.callback != null) {
dopt.callback.callback(filteredItems.get(position).toString()); dopt.callback.callback(filteredItems.get(position).first);
}
if (dopt.withPositionCallback != null) {
final Pair<String, Integer> item = filteredItems.get(position);
dopt.withPositionCallback.callback(item.first, item.second);
} }
}); });
...@@ -220,7 +293,6 @@ public class SearchOrCustomTextDialog { ...@@ -220,7 +293,6 @@ public class SearchOrCustomTextDialog {
return false; return false;
}); });
Window w; Window w;
if ((w = dialog.getWindow()) != null && dopt.isSearchEnabled) { if ((w = dialog.getWindow()) != null && dopt.isSearchEnabled) {
w.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); w.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
...@@ -241,6 +313,9 @@ public class SearchOrCustomTextDialog { ...@@ -241,6 +313,9 @@ public class SearchOrCustomTextDialog {
if (dopt.isSearchEnabled) { if (dopt.isSearchEnabled) {
searchEditText.requestFocus(); searchEditText.requestFocus();
} }
if (dopt.defaultText != null) {
listAdapter.getFilter().filter(searchEditText.getText());
}
} }
......
...@@ -37,6 +37,10 @@ public class Callback { ...@@ -37,6 +37,10 @@ public class Callback {
void callback(A arg1, B arg2, C arg3, D arg4, E arg5); void callback(A arg1, B arg2, C arg3, D arg4, E arg5);
} }
public interface b0 {
boolean callback();
}
public interface b1<A> { public interface b1<A> {
boolean callback(A arg1); boolean callback(A arg1);
} }
...@@ -56,4 +60,28 @@ public class Callback { ...@@ -56,4 +60,28 @@ public class Callback {
public interface b5<A, B, C, D, E> { public interface b5<A, B, C, D, E> {
boolean callback(A arg1, B arg2, C arg3, D arg4, E arg5); boolean callback(A arg1, B arg2, C arg3, D arg4, E arg5);
} }
public interface s0 {
String callback();
}
public interface s1<A> {
String callback(A arg1);
}
public interface s2<A, B> {
String callback(A arg1, B arg2);
}
public interface s3<A, B, C> {
String callback(A arg1, B arg2, C arg3);
}
public interface s4<A, B, C, D> {
String callback(A arg1, B arg2, C arg3, D arg4);
}
public interface s5<A, B, C, D, E> {
String callback(A arg1, B arg2, C arg3, D arg4, E arg5);
}
} }
...@@ -893,7 +893,7 @@ public class ContextUtils { ...@@ -893,7 +893,7 @@ public class ContextUtils {
public CharSequence filter(CharSequence src, int start, int end, Spanned dest, int dstart, int dend) { public CharSequence filter(CharSequence src, int start, int end, Spanned dest, int dstart, int dend) {
if (src.length() < 1) return null; if (src.length() < 1) return null;
char last = src.charAt(src.length() - 1); char last = src.charAt(src.length() - 1);
String illegal = "|\\?*<\":>+[]/'"; String illegal = "|\\?*<\":>[]/'";
if (illegal.indexOf(last) > -1) return src.subSequence(0, src.length() - 1); if (illegal.indexOf(last) > -1) return src.subSequence(0, src.length() - 1);
return null; return null;
} }
...@@ -935,7 +935,11 @@ public class ContextUtils { ...@@ -935,7 +935,11 @@ public class ContextUtils {
ContentResolver cr = _context.getContentResolver(); ContentResolver cr = _context.getContentResolver();
mimeType = cr.getType(uri); mimeType = cr.getType(uri);
} else { } else {
String ext = MimeTypeMap.getFileExtensionFromUrl(uri.toString()); String filename = uri.toString();
if (filename.endsWith(".jenc")) {
filename = filename.replace(".jenc", "");
}
String ext = MimeTypeMap.getFileExtensionFromUrl(filename);
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.toLowerCase()); mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext.toLowerCase());
// Try to guess if the recommended methods fail // Try to guess if the recommended methods fail
......
...@@ -409,9 +409,10 @@ public class FileUtils { ...@@ -409,9 +409,10 @@ public class FileUtils {
if (guess == null || guess.isEmpty()) { if (guess == null || guess.isEmpty()) {
guess = "*/*"; guess = "*/*";
int dot = file.getName().lastIndexOf(".") + 1; String filename = file.getName().replace(".jenc", "");
if (dot > 0 && dot < file.getName().length()) { int dot = filename.lastIndexOf(".") + 1;
switch (file.getName().substring(dot)) { if (dot > 0 && dot < filename.length()) {
switch (filename.substring(dot)) {
case "md": case "md":
case "markdown": case "markdown":
case "mkd": case "mkd":
...@@ -488,4 +489,16 @@ public class FileUtils { ...@@ -488,4 +489,16 @@ public class FileUtils {
ret[2] = (int) (diff / 1000) % 60; // sec ret[2] = (int) (diff / 1000) % 60; // sec
return ret; return ret;
} }
public static String getHumanReadableByteCountSI(final long bytes) {
if (bytes < 1000) {
return String.format(Locale.getDefault(), "%d%s", bytes, "B");
} else if (bytes < 1000000) {
return String.format(Locale.getDefault(), "%.2f%s", (bytes / 1000f), "KB");
} else if (bytes < 1000000000) {
return String.format(Locale.getDefault(), "%.2f%s", (bytes / 1000000f), "GB");
} else {
return String.format(Locale.getDefault(), "%.2f%s", (bytes / 1000000000f), "TB");
}
}
} }
...@@ -24,6 +24,7 @@ import java.net.URL; ...@@ -24,6 +24,7 @@ import java.net.URL;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -150,6 +151,7 @@ public class NetworkUtils { ...@@ -150,6 +151,7 @@ public class NetworkUtils {
return performCall(url, method, data, null); return performCall(url, method, data, null);
} }
@SuppressWarnings("CharsetObjectCanBeUsed")
private static String performCall(final URL url, final String method, final String data, final HttpURLConnection existingConnection) { private static String performCall(final URL url, final String method, final String data, final HttpURLConnection existingConnection) {
try { try {
final HttpURLConnection connection = existingConnection != null final HttpURLConnection connection = existingConnection != null
...@@ -160,7 +162,7 @@ public class NetworkUtils { ...@@ -160,7 +162,7 @@ public class NetworkUtils {
if (data != null && !data.isEmpty()) { if (data != null && !data.isEmpty()) {
connection.setDoOutput(true); connection.setDoOutput(true);
final OutputStream output = connection.getOutputStream(); final OutputStream output = connection.getOutputStream();
output.write(data.getBytes(Charset.forName(UTF8))); output.write(data.getBytes(Charset.forName("UTF-8")));
output.flush(); output.flush();
output.close(); output.close();
} }
......
...@@ -78,7 +78,7 @@ import static android.app.Activity.RESULT_OK; ...@@ -78,7 +78,7 @@ import static android.app.Activity.RESULT_OK;
* Also allows to parse/fetch information out of shared information. * Also allows to parse/fetch information out of shared information.
* (M)Permissions are not checked, wrap ShareUtils methods if neccessary * (M)Permissions are not checked, wrap ShareUtils methods if neccessary
*/ */
@SuppressWarnings({"UnusedReturnValue", "WeakerAccess", "SameParameterValue", "unused", "deprecation", "ConstantConditions", "ObsoleteSdkInt", "SpellCheckingInspection", "JavadocReference"}) @SuppressWarnings({"UnusedReturnValue", "WeakerAccess", "SameParameterValue", "unused", "deprecation", "ConstantConditions", "ObsoleteSdkInt", "SpellCheckingInspection", "JavadocReference", "ConstantLocale"})
public class ShareUtil {