From c5e3a420056e994c8b5b0d13d2b5582f8d1c00c9 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sat, 7 Sep 2019 21:54:08 +0200 Subject: [PATCH 01/49] Update opoc --- .../net/gsantner/opoc/util/ContextUtils.java | 12 +++++++++ .../net/gsantner/opoc/util/FileUtils.java | 12 ++++++++- .../net/gsantner/opoc/util/ShareUtil.java | 25 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java index 9f3b6221..f4b730b4 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java @@ -12,6 +12,7 @@ package net.gsantner.opoc.util; import android.annotation.SuppressLint; import android.app.Activity; +import android.app.ActivityManager; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.ActivityNotFoundException; @@ -47,6 +48,7 @@ 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.app.ActivityManagerCompat; import android.support.v4.content.ContextCompat; import android.support.v4.graphics.drawable.DrawableCompat; import android.support.v4.util.Pair; @@ -945,6 +947,16 @@ public class ContextUtils { } } + public boolean isDeviceGoodHardware() { + try { + ActivityManager activityManager = (ActivityManager) _context.getSystemService(Context.ACTIVITY_SERVICE); + return !ActivityManagerCompat.isLowRamDevice(activityManager) && + Runtime.getRuntime().availableProcessors() >= 4 && + activityManager.getMemoryClass() >= 128; + } catch (Exception ignored) { + return true; + } + } } diff --git a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java index a358ebff..14c57344 100644 --- a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java @@ -16,6 +16,7 @@ import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -42,13 +43,22 @@ public class FileUtils { public static String readTextFileFast(final File file) { try { - return new String(readCloseBinaryStream(new FileInputStream(file))); + return new String(readCloseStreamWithSize(new FileInputStream(file), (int) file.length())); } catch (FileNotFoundException e) { System.err.println("readTextFileFast: File " + file + " not found."); } return ""; } + public static byte[] readCloseStreamWithSize(final InputStream stream, int size) { + byte[] data = new byte[size]; + try (DataInputStream dis = new DataInputStream(stream)) { + dis.readFully(data); + } catch (IOException ignored) { + } + return data; + } + public static String readTextFile(final File file) { try { return readCloseTextStream(new FileInputStream(file)); diff --git a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java index 756000d3..cc6ae7bb 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java +++ b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java @@ -65,6 +65,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Locale; @@ -230,6 +231,30 @@ public class ShareUtil { } } + /** + * Share the given files as stream with given mime-type + * + * @param files The files to share + * @param mimeType The files mime type. Usally * / * is the best option + */ + public boolean shareStreamMultiple(Collection files, String mimeType) { + ArrayList uris = new ArrayList<>(); + for (File file : files) { + File uri = new File(file.toString()); + uris.add(FileProvider.getUriForFile(_context, getFileProviderAuthority(), file)); + } + + try { + Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE); + intent.setType(mimeType); + intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); + showChooser(intent, null); + return true; + } catch (Exception e) { // FileUriExposed(API24) / IllegalArgument + return false; + } + } + /** * Start calendar application to add new event, with given details prefilled */ From 0708fcb02b190068d759853d68c90236b6c76afb Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sun, 22 Sep 2019 13:35:33 +0200 Subject: [PATCH 02/49] Update list of languages for crowdin --- crowdin.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/crowdin.yml b/crowdin.yml index b74b9cb5..2fb1e633 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,10 +1,9 @@ -# vim: +# vim: sw=2 ts=2 noexpandtab: files: - source: /app/src/main/res/values/strings.xml translation: /app/src/main/res/values-%android_code%/%original_file_name% languages_mapping: android_code: - kn: kn # Kannada (Asian) gl: gl # Galician sc: sc # Sardinian kab: kab # Kabyle @@ -44,4 +43,10 @@ files: bs: bs # Bosnian sr: sr # Serbian, Cyrillic sr-CS: sr-rRS # Serbian, Latin + bn: bn # Bengali + pa-IN: pa # Punjabi, India + jv: jw # Javanese + mr: mr # Marathi + te: te # Telugu + ur-PK: ur # Urdu, Pakistan translate_attributes: 0 From 8d019b6c3b38b09f6fcbd18f05cfd9c9de81aca0 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sun, 22 Sep 2019 13:55:33 +0000 Subject: [PATCH 03/49] New Crowdin translations (#253) --- app/src/main/res/values-bn/strings.xml | 25 +++++++++++++++++++++++++ app/src/main/res/values-jw/strings.xml | 25 +++++++++++++++++++++++++ app/src/main/res/values-mr/strings.xml | 25 +++++++++++++++++++++++++ app/src/main/res/values-pa/strings.xml | 25 +++++++++++++++++++++++++ app/src/main/res/values-te/strings.xml | 25 +++++++++++++++++++++++++ app/src/main/res/values-ur/strings.xml | 25 +++++++++++++++++++++++++ 6 files changed, 150 insertions(+) create mode 100644 app/src/main/res/values-bn/strings.xml create mode 100644 app/src/main/res/values-jw/strings.xml create mode 100644 app/src/main/res/values-mr/strings.xml create mode 100644 app/src/main/res/values-pa/strings.xml create mode 100644 app/src/main/res/values-te/strings.xml create mode 100644 app/src/main/res/values-ur/strings.xml diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml new file mode 100644 index 00000000..dbdd3fbf --- /dev/null +++ b/app/src/main/res/values-bn/strings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-jw/strings.xml b/app/src/main/res/values-jw/strings.xml new file mode 100644 index 00000000..dbdd3fbf --- /dev/null +++ b/app/src/main/res/values-jw/strings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-mr/strings.xml b/app/src/main/res/values-mr/strings.xml new file mode 100644 index 00000000..dbdd3fbf --- /dev/null +++ b/app/src/main/res/values-mr/strings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml new file mode 100644 index 00000000..dbdd3fbf --- /dev/null +++ b/app/src/main/res/values-pa/strings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-te/strings.xml b/app/src/main/res/values-te/strings.xml new file mode 100644 index 00000000..dbdd3fbf --- /dev/null +++ b/app/src/main/res/values-te/strings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml new file mode 100644 index 00000000..dbdd3fbf --- /dev/null +++ b/app/src/main/res/values-ur/strings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + From d1be7f5215ee153914ccf70fe830bbf17a13f1af Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Fri, 4 Oct 2019 01:38:43 +0200 Subject: [PATCH 04/49] Bump gradle from 3.5.0 to 3.5.1 (#254) --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 2f8f520e..2d3db78c 100644 --- a/build.gradle +++ b/build.gradle @@ -13,7 +13,7 @@ import java.text.SimpleDateFormat buildscript { ext { - version_gradle_tools = "3.5.0" + version_gradle_tools = "3.5.1" version_plugin_kotlin = "1.3.50" enable_plugin_kotlin = false From 1948c28cff50e27ff2cd6ccc5c43333e95591579 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Mon, 4 Nov 2019 14:18:40 +0100 Subject: [PATCH 05/49] Crowdin: Update language mapping --- crowdin.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crowdin.yml b/crowdin.yml index 2fb1e633..8525cd8a 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -49,4 +49,7 @@ files: mr: mr # Marathi te: te # Telugu ur-PK: ur # Urdu, Pakistan + id: in # Indonesian + sk: sk # Slovak + kn: kn # Kannada (Asian) translate_attributes: 0 From 7361d4bc3f5a24f8a1616a644b58c0a495366144 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Wed, 20 Nov 2019 00:34:10 +0100 Subject: [PATCH 06/49] Update opoc Update shared helper utilities of my projects to latest state --- .../opoc/activity/GsFragmentBase.java | 14 ++ .../SharedPreferencesPropertyBackend.java | 2 +- .../opoc/ui/SearchOrCustomTextDialog.java | 35 +++- .../java/net/gsantner/opoc/util/Callback.java | 5 + .../net/gsantner/opoc/util/ContextUtils.java | 160 ++++++++++++------ .../net/gsantner/opoc/util/FileUtils.java | 37 +++- .../net/gsantner/opoc/util/NetworkUtils.java | 2 +- .../net/gsantner/opoc/util/ShareUtil.java | 139 +++++++++------ build.gradle | 4 +- 9 files changed, 286 insertions(+), 112 deletions(-) diff --git a/app/src/main/java/net/gsantner/opoc/activity/GsFragmentBase.java b/app/src/main/java/net/gsantner/opoc/activity/GsFragmentBase.java index 507d25ff..7dcf0317 100644 --- a/app/src/main/java/net/gsantner/opoc/activity/GsFragmentBase.java +++ b/app/src/main/java/net/gsantner/opoc/activity/GsFragmentBase.java @@ -16,6 +16,7 @@ import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; +import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.LayoutInflater; import android.view.Menu; @@ -143,4 +144,17 @@ public abstract class GsFragmentBase extends Fragment { public Menu getFragmentMenu() { return _fragmentMenu; } + + /** + * Get the toolbar from activity + * Requires id to be set to @+id/toolbar + */ + @SuppressWarnings("ConstantConditions") + protected Toolbar getToolbar() { + try { + return (Toolbar) getActivity().findViewById(new ContextUtils(getActivity()).getResId(ContextUtils.ResType.ID, "toolbar")); + } catch (Exception e) { + return null; + } + } } diff --git a/app/src/main/java/net/gsantner/opoc/preference/SharedPreferencesPropertyBackend.java b/app/src/main/java/net/gsantner/opoc/preference/SharedPreferencesPropertyBackend.java index 343f2a4c..6950e522 100644 --- a/app/src/main/java/net/gsantner/opoc/preference/SharedPreferencesPropertyBackend.java +++ b/app/src/main/java/net/gsantner/opoc/preference/SharedPreferencesPropertyBackend.java @@ -547,7 +547,7 @@ public class SharedPreferencesPropertyBackend implements PropertyBackend callback; public List data = new ArrayList<>(); public List highlightData = new ArrayList<>(); + public List iconsForData = new ArrayList<>(); public String messageText = ""; public boolean isSearchEnabled = true; public boolean isDarkDialog = false; + public int dialogWidthDp = WindowManager.LayoutParams.MATCH_PARENT; + public int dialogHeightDp = WindowManager.LayoutParams.WRAP_CONTENT; + public int gravity = Gravity.NO_GRAVITY; + public int searchInputType = 0; @ColorInt public int textColor = 0xFF000000; @@ -89,6 +98,17 @@ public class SearchOrCustomTextDialog { TextView textView = (TextView) super.getView(pos, convertView, parent); String text = textView.getText().toString(); + int posInOriginalList = dopt.data.indexOf(text); + if (posInOriginalList >= 0 && dopt.iconsForData != null && posInOriginalList < dopt.iconsForData.size() && dopt.iconsForData.get(posInOriginalList) != 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); textView.setTextColor(hl ? dopt.highlightColor : dopt.textColor); textView.setTypeface(null, hl ? Typeface.BOLD : Typeface.NORMAL); @@ -132,6 +152,7 @@ public class SearchOrCustomTextDialog { searchEditText.setTextColor(dopt.textColor); searchEditText.setHintTextColor((dopt.textColor & 0x00FFFFFF) | 0x99000000); searchEditText.setHint(dopt.searchHintText); + searchEditText.setInputType(dopt.searchInputType == 0 ? searchEditText.getInputType() : dopt.searchInputType); searchEditText.addTextChangedListener(new TextWatcher() { @Override @@ -166,9 +187,11 @@ public class SearchOrCustomTextDialog { dialogBuilder.setMessage(dopt.messageText); } dialogBuilder.setView(linearLayout) - .setTitle(dopt.titleText) .setOnCancelListener(null) .setNegativeButton(dopt.cancelButtonText, (dialogInterface, i) -> dialogInterface.dismiss()); + if (dopt.titleText != 0) { + dialogBuilder.setTitle(dopt.titleText); + } if (dopt.isSearchEnabled) { dialogBuilder.setPositiveButton(dopt.okButtonText, (dialogInterface, i) -> { dialogInterface.dismiss(); @@ -204,7 +227,15 @@ public class SearchOrCustomTextDialog { } dialog.show(); if ((w = dialog.getWindow()) != null) { - w.setLayout(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT); + int ds_w = dopt.dialogWidthDp < 100 ? dopt.dialogWidthDp : ((int) (dopt.dialogWidthDp * activity.getResources().getDisplayMetrics().density)); + int ds_h = dopt.dialogHeightDp < 100 ? dopt.dialogHeightDp : ((int) (dopt.dialogHeightDp * activity.getResources().getDisplayMetrics().density)); + w.setLayout(ds_w, ds_h); + } + + if ((w = dialog.getWindow()) != null && dopt.gravity != Gravity.NO_GRAVITY) { + WindowManager.LayoutParams wlp = w.getAttributes(); + wlp.gravity = dopt.gravity; + w.setAttributes(wlp); } if (dopt.isSearchEnabled) { diff --git a/app/src/main/java/net/gsantner/opoc/util/Callback.java b/app/src/main/java/net/gsantner/opoc/util/Callback.java index c07f883c..7a3186e8 100644 --- a/app/src/main/java/net/gsantner/opoc/util/Callback.java +++ b/app/src/main/java/net/gsantner/opoc/util/Callback.java @@ -12,6 +12,11 @@ package net.gsantner.opoc.util; @SuppressWarnings("unused") public class Callback { + + public interface a0 { + void callback(); + } + public interface a1 { void callback(A arg1); } diff --git a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java index f4b730b4..141f1b47 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java @@ -41,6 +41,8 @@ import android.net.Uri; import android.os.Build; import android.os.Environment; import android.os.SystemClock; +import android.os.VibrationEffect; +import android.os.Vibrator; import android.support.annotation.ColorInt; import android.support.annotation.ColorRes; import android.support.annotation.DrawableRes; @@ -51,7 +53,9 @@ import android.support.graphics.drawable.VectorDrawableCompat; import android.support.v4.app.ActivityManagerCompat; import android.support.v4.content.ContextCompat; import android.support.v4.graphics.drawable.DrawableCompat; +import android.support.v4.text.TextUtilsCompat; import android.support.v4.util.Pair; +import android.support.v4.view.ViewCompat; import android.text.Html; import android.text.InputFilter; import android.text.SpannableString; @@ -82,10 +86,11 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import static android.content.Context.VIBRATOR_SERVICE; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.graphics.Bitmap.CompressFormat; -@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "ObsoleteSdkInt", "deprecation", "SpellCheckingInspection"}) +@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "ObsoleteSdkInt", "deprecation", "SpellCheckingInspection", "TryFinallyCanBeTryWithResources", "UnusedAssignment"}) public class ContextUtils { // // Members, Constructors @@ -117,21 +122,29 @@ public class ContextUtils { * * @return A valid id if the id could be found, else 0 */ - public int getResId(ResType resType, final String name) { - return _context.getResources().getIdentifier(name, resType.name().toLowerCase(), _context.getPackageName()); + public int getResId(final ResType resType, final String name) { + try { + return _context.getResources().getIdentifier(name, resType.name().toLowerCase(), _context.getPackageName()); + } catch (Exception e) { + return 0; + } } /** * Get String by given string ressource id (nuermic) */ - public String rstr(@StringRes int strResId) { - return _context.getString(strResId); + public String rstr(@StringRes final int strResId) { + try { + return _context.getString(strResId); + } catch (Exception e) { + return null; + } } /** * Get String by given string ressource identifier (textual) */ - public String rstr(String strResKey) { + public String rstr(final String strResKey) { try { return rstr(getResId(ResType.STRING, strResKey)); } catch (Resources.NotFoundException e) { @@ -142,14 +155,22 @@ public class ContextUtils { /** * Get drawable from given ressource identifier */ - public Drawable rdrawable(@DrawableRes int resId) { - return ContextCompat.getDrawable(_context, resId); + public Drawable rdrawable(@DrawableRes final int resId) { + try { + return ContextCompat.getDrawable(_context, resId); + } catch (Exception e) { + return null; + } } /** * Get color by given color ressource id */ - public int rcolor(@ColorRes int resId) { + public int rcolor(@ColorRes final int resId) { + if (resId == 0) { + Log.e(getClass().getName(), "ContextUtils::rcolor: resId is 0!"); + return Color.BLACK; + } return ContextCompat.getColor(_context, resId); } @@ -175,12 +196,12 @@ public class ContextUtils { * @param intColor The color coded in int * @param withAlpha Optional; Set first bool parameter to true to also include alpha value */ - public String colorToHexString(int intColor, boolean... withAlpha) { + public static String colorToHexString(final int intColor, final boolean... withAlpha) { boolean a = withAlpha != null && withAlpha.length >= 1 && withAlpha[0]; return String.format(a ? "#%08X" : "#%06X", (a ? 0xFFFFFFFF : 0xFFFFFF) & intColor); } - public String getAndroidVersion() { + public static String getAndroidVersion() { return Build.VERSION.RELEASE + " (" + Build.VERSION.SDK_INT + ")"; } @@ -205,7 +226,7 @@ public class ContextUtils { src = _context.getPackageManager().getInstallerPackageName(getPackageIdManifest()); } catch (Exception ignored) { } - if (TextUtils.isEmpty(src)) { + if (src == null || src.trim().isEmpty()) { return "Sideloaded"; } else if (src.toLowerCase().contains(".amazon.")) { return "Amazon Appstore"; @@ -213,7 +234,7 @@ public class ContextUtils { switch (src) { case "com.android.vending": case "com.google.android.feedback": { - return "Google Play Store"; + return "Google Play"; } case "org.fdroid.fdroid.privileged": case "org.fdroid.fdroid": { @@ -237,12 +258,12 @@ public class ContextUtils { * If the parameter is an string a browser will get triggered */ public void openWebpageInExternalBrowser(final String url) { - Uri uri = Uri.parse(url); - Intent intent = new Intent(Intent.ACTION_VIEW, uri); - intent.addFlags(FLAG_ACTIVITY_NEW_TASK); try { + Uri uri = Uri.parse(url); + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + intent.addFlags(FLAG_ACTIVITY_NEW_TASK); _context.startActivity(intent); - } catch (ActivityNotFoundException e) { + } catch (Exception e) { e.printStackTrace(); } } @@ -252,7 +273,7 @@ public class ContextUtils { */ public String getPackageIdManifest() { String pkg = rstr("manifest_package_id"); - return pkg != null ? pkg : _context.getPackageName(); + return !TextUtils.isEmpty(pkg) ? pkg : _context.getPackageName(); } /** @@ -270,7 +291,7 @@ public class ContextUtils { * of the package set in manifest (root element). * Falls back to applicationId of the app which may differ from manifest. */ - public Object getBuildConfigValue(String fieldName) { + public Object getBuildConfigValue(final String fieldName) { String pkg = getPackageIdManifest() + ".BuildConfig"; try { Class c = Class.forName(pkg); @@ -284,9 +305,9 @@ public class ContextUtils { /** * Get a BuildConfig bool value */ - public Boolean bcbool(String fieldName, Boolean defaultValue) { + public Boolean bcbool(final String fieldName, final Boolean defaultValue) { Object field = getBuildConfigValue(fieldName); - if (field != null && field instanceof Boolean) { + if (field instanceof Boolean) { return (Boolean) field; } return defaultValue; @@ -295,9 +316,9 @@ public class ContextUtils { /** * Get a BuildConfig string value */ - public String bcstr(String fieldName, String defaultValue) { + public String bcstr(final String fieldName, final String defaultValue) { Object field = getBuildConfigValue(fieldName); - if (field != null && field instanceof String) { + if (field instanceof String) { return (String) field; } return defaultValue; @@ -306,9 +327,9 @@ public class ContextUtils { /** * Get a BuildConfig string value */ - public Integer bcint(String fieldName, int defaultValue) { + public Integer bcint(final String fieldName, final int defaultValue) { Object field = getBuildConfigValue(fieldName); - if (field != null && field instanceof Integer) { + if (field instanceof Integer) { return (Integer) field; } return defaultValue; @@ -396,8 +417,8 @@ public class ContextUtils { * Check if app with given {@code packageName} is installed */ public boolean isAppInstalled(String packageName) { - PackageManager pm = _context.getApplicationContext().getPackageManager(); try { + PackageManager pm = _context.getApplicationContext().getPackageManager(); pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES); return true; } catch (PackageManager.NameNotFoundException e) { @@ -409,17 +430,17 @@ public class ContextUtils { * Restart the current app. Supply the class to start on startup */ public void restartApp(Class classToStart) { - Intent inte = new Intent(_context, classToStart); - PendingIntent inteP = PendingIntent.getActivity(_context, 555, inte, PendingIntent.FLAG_CANCEL_CURRENT); + Intent intent = new Intent(_context, classToStart); + PendingIntent pendi = PendingIntent.getActivity(_context, 555, intent, PendingIntent.FLAG_CANCEL_CURRENT); AlarmManager mgr = (AlarmManager) _context.getSystemService(Context.ALARM_SERVICE); if (_context instanceof Activity) { ((Activity) _context).finish(); } if (mgr != null) { - mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, inteP); + mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendi); } else { - inte.addFlags(FLAG_ACTIVITY_NEW_TASK); - _context.startActivity(inte); + intent.addFlags(FLAG_ACTIVITY_NEW_TASK); + _context.startActivity(intent); } Runtime.getRuntime().exit(0); } @@ -488,19 +509,25 @@ public class ContextUtils { * {@code androidLC} may be in any of the forms: en, de, de-rAt * If given an empty string, the default (system) locale gets loaded */ - public void setAppLanguage(String androidLC) { + public void setAppLanguage(final String androidLC) { Locale locale = getLocaleByAndroidCode(androidLC); + locale = (locale != null && !androidLC.isEmpty()) ? locale : Resources.getSystem().getConfiguration().locale; + setLocale(locale); + } + + public ContextUtils setLocale(final Locale locale) { Configuration config = _context.getResources().getConfiguration(); - config.locale = (locale != null && !androidLC.isEmpty()) - ? locale : Resources.getSystem().getConfiguration().locale; + config.locale = (locale != null ? locale : Resources.getSystem().getConfiguration().locale); _context.getResources().updateConfiguration(config, null); + Locale.setDefault(locale); + return this; } /** * Try to guess if the color on top of the given {@code colorOnBottomInt} * should be light or dark. Returns true if top color should be light */ - public boolean shouldColorOnTopBeLight(@ColorInt int colorOnBottomInt) { + public boolean shouldColorOnTopBeLight(@ColorInt final int colorOnBottomInt) { return 186 > (((0.299 * Color.red(colorOnBottomInt)) + ((0.587 * Color.green(colorOnBottomInt)) + (0.114 * Color.blue(colorOnBottomInt))))); @@ -509,7 +536,7 @@ public class ContextUtils { /** * Convert a html string to an android {@link Spanned} object */ - public Spanned htmlToSpanned(String html) { + public Spanned htmlToSpanned(final 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); @@ -568,7 +595,7 @@ public class ContextUtils { return dirs; } - public String getStorageName(File externalFileDir, boolean storageNameWithoutType) { + public String getStorageName(final File externalFileDir, final boolean storageNameWithoutType) { boolean isInt = externalFileDir.getAbsolutePath().startsWith(Environment.getExternalStorageDirectory().getAbsolutePath()); String[] split = externalFileDir.getAbsolutePath().split("/"); @@ -579,7 +606,7 @@ public class ContextUtils { } } - public List> getStorages(boolean internalStorageFolder, boolean sdcardFolders) { + public List> getStorages(final boolean internalStorageFolder, final boolean sdcardFolders) { List> storages = new ArrayList<>(); for (Pair pair : getAppDataPublicDirs(internalStorageFolder, sdcardFolders, true)) { if (pair.first != null && pair.first.getAbsolutePath().lastIndexOf("/Android/data") > 0) { @@ -592,7 +619,7 @@ public class ContextUtils { return storages; } - public File getStorageRootFolder(File file) { + public File getStorageRootFolder(final File file) { String filepath; try { filepath = file.getCanonicalPath(); @@ -613,7 +640,7 @@ public class ContextUtils { * * @param files Files and folders to scan */ - public void mediaScannerScanFile(File... files) { + public void mediaScannerScanFile(final File... files) { if (android.os.Build.VERSION.SDK_INT > 19) { String[] paths = new String[files.length]; for (int i = 0; i < files.length; i++) { @@ -662,8 +689,12 @@ public class ContextUtils { /** * Get a {@link Bitmap} out of a {@link DrawableRes} */ - public Bitmap drawableToBitmap(@DrawableRes int drawableId) { - return drawableToBitmap(ContextCompat.getDrawable(_context, drawableId)); + public Bitmap drawableToBitmap(@DrawableRes final int drawableId) { + try { + return drawableToBitmap(ContextCompat.getDrawable(_context, drawableId)); + } catch (Exception e) { + return null; + } } /** @@ -671,7 +702,7 @@ public class ContextUtils { * Specifying a {@code maxDimen} is also possible and a value below 2000 * is recommended, otherwise a {@link OutOfMemoryError} may occur */ - public Bitmap loadImageFromFilesystem(File imagePath, int maxDimen) { + public Bitmap loadImageFromFilesystem(final File imagePath, final int maxDimen) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = true; BitmapFactory.decodeFile(imagePath.getAbsolutePath(), options); @@ -687,7 +718,7 @@ public class ContextUtils { * @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) { + public int calculateInSampleSize(final BitmapFactory.Options options, final int maxDimen) { // Raw height and width of image int height = options.outHeight; int width = options.outWidth; @@ -703,7 +734,7 @@ public class ContextUtils { * Scale the bitmap so both dimensions are lower or equal to {@code maxDimen} * This keeps the aspect ratio */ - public Bitmap scaleBitmap(Bitmap bitmap, int maxDimen) { + public Bitmap scaleBitmap(final Bitmap bitmap, final int maxDimen) { int picSize = Math.min(bitmap.getHeight(), bitmap.getWidth()); float scale = 1.f * maxDimen / picSize; Matrix matrix = new Matrix(); @@ -714,7 +745,7 @@ public class ContextUtils { /** * Write the given {@link Bitmap} to {@code imageFile}, in {@link CompressFormat#JPEG} format */ - public boolean writeImageToFileJpeg(File imageFile, Bitmap image) { + public boolean writeImageToFileJpeg(final File imageFile, final Bitmap image) { return writeImageToFile(imageFile, image, Bitmap.CompressFormat.JPEG, 95); } @@ -727,7 +758,7 @@ public class ContextUtils { * @param quality Quality level, defaults to 95 * @return True if writing was successful */ - public boolean writeImageToFile(File targetFile, Bitmap image, CompressFormat format, Integer quality) { + public boolean writeImageToFile(final File targetFile, final Bitmap image, CompressFormat format, Integer quality) { File folder = new File(targetFile.getParent()); if (quality == null || quality < 0 || quality > 100) { quality = 95; @@ -765,7 +796,7 @@ public class ContextUtils { * Draw text in the center of the given {@link DrawableRes} * This may be useful for e.g. badge counts */ - public Bitmap drawTextOnDrawable(@DrawableRes int drawableRes, String text, int textSize) { + public Bitmap drawTextOnDrawable(@DrawableRes final int drawableRes, final String text, final int textSize) { Resources resources = _context.getResources(); float scale = resources.getDisplayMetrics().density; Bitmap bitmap = drawableToBitmap(drawableRes); @@ -790,7 +821,7 @@ public class ContextUtils { * Try to tint all {@link Menu}s {@link MenuItem}s with given color */ @SuppressWarnings("ConstantConditions") - public void tintMenuItems(Menu menu, boolean recurse, @ColorInt int iconColor) { + public void tintMenuItems(final Menu menu, final boolean recurse, @ColorInt final int iconColor) { for (int i = 0; i < menu.size(); i++) { MenuItem item = menu.getItem(i); try { @@ -807,14 +838,14 @@ public class ContextUtils { /** * Loads {@link Drawable} by given {@link DrawableRes} and applies a color */ - public Drawable tintDrawable(@DrawableRes int drawableRes, @ColorInt int color) { + public Drawable tintDrawable(@DrawableRes final int drawableRes, @ColorInt final int color) { return tintDrawable(rdrawable(drawableRes), color); } /** * Tint a {@link Drawable} with given {@code color} */ - public Drawable tintDrawable(@Nullable Drawable drawable, @ColorInt int color) { + public Drawable tintDrawable(@Nullable Drawable drawable, @ColorInt final int color) { if (drawable != null) { drawable = DrawableCompat.wrap(drawable); DrawableCompat.setTint(drawable.mutate(), color); @@ -826,7 +857,10 @@ public class ContextUtils { * Try to make icons in Toolbar/ActionBars SubMenus visible * This may not work on some devices and it maybe won't work on future android updates */ - public void setSubMenuIconsVisiblity(Menu menu, boolean visible) { + public void setSubMenuIconsVisiblity(final Menu menu, final boolean visible) { + if (TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL) { + return; + } if (menu.getClass().getSimpleName().equals("MenuBuilder")) { try { @SuppressLint("PrivateApi") Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE); @@ -886,7 +920,7 @@ public class ContextUtils { } - public String getMimeType(File file) { + public String getMimeType(final File file) { return getMimeType(Uri.fromFile(file)); } @@ -895,7 +929,7 @@ public class ContextUtils { * Android/Java's own MimeType map is very very small and detection barely works at all * Hence use custom map for some file extensions */ - public String getMimeType(Uri uri) { + public String getMimeType(final Uri uri) { String mimeType = null; if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) { ContentResolver cr = _context.getContentResolver(); @@ -936,7 +970,7 @@ public class ContextUtils { return mimeType; } - public Integer parseColor(String colorstr) { + public Integer parseColor(final String colorstr) { if (colorstr == null || colorstr.trim().isEmpty()) { return null; } @@ -957,6 +991,22 @@ public class ContextUtils { return true; } } + + // Vibrate device one time by given amount of time, defaulting to 50ms + // Requires in AndroidManifest to work + @SuppressWarnings("UnnecessaryReturnStatement") + @SuppressLint("MissingPermission") + public void vibrate(final int... ms) { + int ms_v = ms != null && ms.length > 0 ? ms[0] : 50; + Vibrator vibrator = ((Vibrator) _context.getSystemService(VIBRATOR_SERVICE)); + if (vibrator == null) { + return; + } else if (Build.VERSION.SDK_INT >= 26) { + vibrator.vibrate(VibrationEffect.createOneShot(ms_v, VibrationEffect.DEFAULT_AMPLITUDE)); + } else { + vibrator.vibrate(ms_v); + } + } } diff --git a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java index 14c57344..c8a2b6d3 100644 --- a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java @@ -29,6 +29,7 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.net.URLConnection; import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.List; import java.util.Locale; @@ -240,6 +241,30 @@ public class FileUtils { } } + public static boolean copyFile(final File src, final FileOutputStream os) { + InputStream is = null; + try { + try { + is = new FileInputStream(src); + byte[] buf = new byte[BUFFER_SIZE]; + int len; + while ((len = is.read(buf)) > 0) { + os.write(buf, 0, len); + } + return true; + } finally { + if (is != null) { + is.close(); + } + if (os != null) { + os.close(); + } + } + } catch (IOException ex) { + return false; + } + } + // Returns -1 if the file did not contain any of the needles, otherwise, // the index of which needle was found in the contents of the file. // @@ -452,7 +477,15 @@ public class FileUtils { } String[] units = abbreviation ? new String[]{"B", "kB", "MB", "GB", "TB"} : new String[]{"Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"}; int unit = (int) (Math.log10(size) / Math.log10(1024)); - return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, unit)) - + " " + units[unit]; + return new DecimalFormat("#,##0.#", DecimalFormatSymbols.getInstance(Locale.ENGLISH)).format(size / Math.pow(1024, unit)) + " " + units[unit]; + } + + public static int[] getTimeDiffHMS(long now, long past) { + int[] ret = new int[3]; + long diff = Math.abs(now - past); + ret[0] = (int) (diff / (1000 * 60 * 60)); // hours + ret[1] = (int) (diff / (1000 * 60)) % 60; // min + ret[2] = (int) (diff / 1000) % 60; // sec + return ret; } } diff --git a/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java b/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java index 50d11664..a8c564c6 100644 --- a/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java @@ -77,7 +77,7 @@ public class NetworkUtils { int written = 0; final float invLength = 1f / connection.getContentLength(); - byte data[] = new byte[BUFFER_SIZE]; + byte[] data = new byte[BUFFER_SIZE]; while ((count = input.read(data)) != -1) { output.write(data, 0, count); if (invLength != -1f && progressCallback != null) { diff --git a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java index cc6ae7bb..4ebea3b7 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java +++ b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java @@ -96,12 +96,12 @@ public class ShareUtil { protected String _fileProviderAuthority; protected String _chooserTitle; - public ShareUtil(Context context) { + public ShareUtil(final Context context) { _context = context; _chooserTitle = "➥"; } - public void setContext(Context c) { + public void setContext(final Context c) { _context = c; } @@ -116,13 +116,13 @@ public class ShareUtil { return _fileProviderAuthority; } - public ShareUtil setFileProviderAuthority(String fileProviderAuthority) { + public ShareUtil setFileProviderAuthority(final String fileProviderAuthority) { _fileProviderAuthority = fileProviderAuthority; return this; } - public ShareUtil setChooserTitle(String title) { + public ShareUtil setChooserTitle(final String title) { _chooserTitle = title; return this; } @@ -133,7 +133,7 @@ public class ShareUtil { * @param file the file * @return Uri for this file */ - public Uri getUriByFileProviderAuthority(File file) { + public Uri getUriByFileProviderAuthority(final File file) { return FileProvider.getUriForFile(_context, getFileProviderAuthority(), file); } @@ -143,7 +143,7 @@ public class ShareUtil { * @param intent Thing to be shared * @param chooserText The title text for the chooser, or null for default */ - public void showChooser(Intent intent, String chooserText) { + public void showChooser(final Intent intent, final String chooserText) { _context.startActivity(Intent.createChooser(intent, chooserText != null ? chooserText : _chooserTitle)); } @@ -157,7 +157,7 @@ public class ShareUtil { * @param iconRes Icon resource for the item * @param title Title of the item */ - public void createLauncherDesktopShortcut(Intent intent, @DrawableRes int iconRes, String title) { + public void createLauncherDesktopShortcut(final Intent intent, @DrawableRes final int iconRes, final String title) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); if (intent.getAction() == null) { @@ -182,7 +182,7 @@ public class ShareUtil { * @param iconRes Icon resource for the item * @param title Title of the item */ - public void createLauncherDesktopShortcutLegacy(Intent intent, @DrawableRes int iconRes, String title) { + public void createLauncherDesktopShortcutLegacy(final Intent intent, @DrawableRes final int iconRes, final String title) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); if (intent.getAction() == null) { @@ -203,7 +203,7 @@ public class ShareUtil { * @param text The text to share * @param mimeType MimeType or null (uses text/plain) */ - public void shareText(String text, @Nullable String mimeType) { + public void shareText(final String text, @Nullable final String mimeType) { Intent intent = new Intent(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_TEXT, text); intent.setType(mimeType != null ? mimeType : MIME_TEXT_PLAIN); @@ -216,7 +216,7 @@ public class ShareUtil { * @param file The file to share * @param mimeType The files mime type */ - public boolean shareStream(File file, String mimeType) { + public boolean shareStream(final File file, final String mimeType) { Intent intent = new Intent(Intent.ACTION_SEND); intent.putExtra(EXTRA_FILEPATH, file.getAbsolutePath()); intent.setType(mimeType); @@ -237,7 +237,7 @@ public class ShareUtil { * @param files The files to share * @param mimeType The files mime type. Usally * / * is the best option */ - public boolean shareStreamMultiple(Collection files, String mimeType) { + public boolean shareStreamMultiple(final Collection files, final String mimeType) { ArrayList uris = new ArrayList<>(); for (File file : files) { File uri = new File(file.toString()); @@ -258,14 +258,13 @@ public class ShareUtil { /** * Start calendar application to add new event, with given details prefilled */ - public boolean createCalendarAppointment(@Nullable String title, @Nullable String description, @Nullable String location, @Nullable Long... startAndEndTime) { + public boolean createCalendarAppointment(@Nullable final String title, @Nullable final String description, @Nullable final String location, @Nullable final Long... startAndEndTime) { Intent intent = new Intent(Intent.ACTION_INSERT).setData(CalendarContract.Events.CONTENT_URI); if (title != null) { intent.putExtra(CalendarContract.Events.TITLE, title); } if (description != null) { - description = description.length() > 800 ? description.substring(0, 800) : description; - intent.putExtra(CalendarContract.Events.DESCRIPTION, description); + intent.putExtra(CalendarContract.Events.DESCRIPTION, (description.length() > 800 ? description.substring(0, 800) : description)); } if (location != null) { intent.putExtra(CalendarContract.Events.EVENT_LOCATION, location); @@ -292,7 +291,7 @@ public class ShareUtil { * * @param file The file to share */ - public boolean viewFileInOtherApp(File file, @Nullable String type) { + public boolean viewFileInOtherApp(final File file, @Nullable final String type) { // On some specific devices the first won't work Uri fileUri = null; try { @@ -324,7 +323,7 @@ public class ShareUtil { * @param format A {@link Bitmap.CompressFormat}, supporting JPEG,PNG,WEBP * @return if success, true */ - public boolean shareImage(Bitmap bitmap, Bitmap.CompressFormat format) { + public boolean shareImage(final Bitmap bitmap, final Bitmap.CompressFormat format) { return shareImage(bitmap, format, 95, "SharedImage"); } @@ -337,7 +336,7 @@ public class ShareUtil { * @param quality Quality of the exported image [0-100] * @return if success, true */ - public boolean shareImage(Bitmap bitmap, Bitmap.CompressFormat format, int quality, String imageName) { + public boolean shareImage(final Bitmap bitmap, final Bitmap.CompressFormat format, final int quality, final String imageName) { try { String ext = format.name().toLowerCase(); File file = File.createTempFile(imageName, "." + ext.replace("jpeg", "jpg"), _context.getExternalCacheDir()); @@ -359,19 +358,23 @@ public class ShareUtil { * @return {{@link PrintJob}} or null */ @RequiresApi(api = Build.VERSION_CODES.KITKAT) - @SuppressWarnings("deprecation") - public PrintJob print(WebView webview, String jobName) { + public PrintJob print(final WebView webview, final String jobName, final boolean... landscape) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - PrintDocumentAdapter printAdapter; - PrintManager printManager = (PrintManager) _context.getSystemService(Context.PRINT_SERVICE); + final PrintDocumentAdapter printAdapter; + final PrintManager printManager = (PrintManager) _context.getSystemService(Context.PRINT_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { printAdapter = webview.createPrintDocumentAdapter(jobName); } else { printAdapter = webview.createPrintDocumentAdapter(); } + final PrintAttributes.Builder attrib = new PrintAttributes.Builder(); + if (landscape != null && landscape.length > 0 && landscape[0]) { + attrib.setMediaSize(new PrintAttributes.MediaSize("ISO_A4", "android", 11690, 8270)); + attrib.setMinMargins(new PrintAttributes.Margins(0, 0, 0, 0)); + } if (printManager != null) { try { - return printManager.print(jobName, printAdapter, new PrintAttributes.Builder().build()); + return printManager.print(jobName, printAdapter, attrib.build()); } catch (Exception ignored) { } } @@ -386,8 +389,7 @@ public class ShareUtil { * See {@link #print(WebView, String) print method} */ @RequiresApi(api = Build.VERSION_CODES.KITKAT) - @SuppressWarnings("deprecation") - public PrintJob createPdf(WebView webview, String jobName) { + public PrintJob createPdf(final WebView webview, final String jobName) { return print(webview, jobName); } @@ -399,7 +401,7 @@ public class ShareUtil { * @return A {@link Bitmap} or null */ @Nullable - public static Bitmap getBitmapFromWebView(WebView webView) { + public static Bitmap getBitmapFromWebView(final WebView webView) { try { //Measure WebView's content int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); @@ -432,7 +434,7 @@ public class ShareUtil { * Replace (primary) clipboard contents with given {@code text} * @param text Text to be set */ - public boolean setClipboard(CharSequence text) { + public boolean setClipboard(final CharSequence text) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { android.text.ClipboardManager cm = ((android.text.ClipboardManager) _context.getSystemService(Context.CLIPBOARD_SERVICE)); if (cm != null) { @@ -485,7 +487,7 @@ public class ShareUtil { * @param callback Callback after paste try * @param serverOrNothing Supply one or no hastebin server. If empty, the default gets taken */ - public void pasteOnHastebin(final String text, final Callback.a2 callback, String... serverOrNothing) { + public void pasteOnHastebin(final String text, final Callback.a2 callback, final String... serverOrNothing) { final Handler handler = new Handler(); final String server = (serverOrNothing != null && serverOrNothing.length > 0 && serverOrNothing[0] != null) ? serverOrNothing[0] : "https://hastebin.com"; @@ -507,7 +509,7 @@ public class ShareUtil { * @param body Body (content) text to be prefilled in the mail * @param to recipients to be prefilled in the mail */ - public void draftEmail(String subject, String body, String... to) { + public void draftEmail(final String subject, final String body, final String... to) { Intent intent = new Intent(Intent.ACTION_SENDTO); intent.setData(Uri.parse("mailto:")); if (subject != null) { @@ -528,7 +530,7 @@ public class ShareUtil { * @param receivingIntent The intent from {@link Activity#getIntent()} * @return A file or null if extraction did not succeed */ - public File extractFileFromIntent(Intent receivingIntent) { + public File extractFileFromIntent(final Intent receivingIntent) { String action = receivingIntent.getAction(); String type = receivingIntent.getType(); File tmpf; @@ -572,6 +574,14 @@ public class ShareUtil { } } + // media/ prefix for External storage + if (fileStr.startsWith((tmps = "media/"))) { + File f = new File(Uri.decode(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + fileStr.substring(tmps.length()))); + if (f.exists()) { + return f; + } + } + // Next/OwnCloud Fileprovider for (String fp : new String[]{"org.nextcloud.files", "org.nextcloud.beta.files", "org.owncloud.files"}) { if (fileProvider.equals(fp) && fileStr.startsWith(tmps = "external_files/")) { @@ -587,6 +597,16 @@ public class ShareUtil { return new File(Uri.decode(Environment.getExternalStorageDirectory().getAbsolutePath() + fileStr.substring(tmps.length()))); } + if (fileStr.startsWith(tmps = "external_files/")) { + for (String prefix : new String[]{Environment.getExternalStorageDirectory().getAbsolutePath(), "/storage", ""}) { + File f = new File(Uri.decode(prefix + "/" + fileStr.substring(tmps.length()))); + if (f.exists()) { + return f; + } + } + + } + // URI Encoded paths with full path after content://package/ if (fileStr.startsWith("/") || fileStr.startsWith("%2F")) { tmpf = new File(Uri.decode(fileStr)); @@ -624,6 +644,11 @@ public class ShareUtil { } } + public String extractFileFromIntentStr(final Intent receivingIntent) { + File f = extractFileFromIntent(receivingIntent); + return f != null ? f.getAbsolutePath() : null; + } + /** * Request a picture from camera-like apps * Result ({@link String}) will be available from {@link Activity#onActivityResult(int, int, Intent)}. @@ -634,7 +659,8 @@ public class ShareUtil { * * @param target Path to file to write to, if folder the filename gets app_name + millis + random filename. If null DCIM folder is used. */ - public String requestCameraPicture(File target) { + @SuppressWarnings("RegExpRedundantEscape") + public String requestCameraPicture(final File target) { if (!(_context instanceof Activity)) { throw new RuntimeException("Error: ShareUtil.requestCameraPicture needs an Activity Context."); } @@ -647,7 +673,7 @@ public class ShareUtil { if (target != null && !target.isDirectory()) { photoFile = target; } else { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss", Locale.getDefault()); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss", Locale.ENGLISH); File storageDir = target != null ? target : new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "Camera"); String imageFileName = ((new ContextUtils(_context).rstr("app_name")).replaceAll("[^a-zA-Z0-9\\.\\-]", "_") + "_").replace("__", "_") + sdf.format(new Date()); photoFile = new File(storageDir, imageFileName + ".jpg"); @@ -686,7 +712,7 @@ public class ShareUtil { * Also may forward results via local broadcast */ @SuppressLint("ApplySharedPref") - public Object extractResultFromActivityResult(int requestCode, int resultCode, Intent data, Activity... activityOrNull) { + public Object extractResultFromActivityResult(final int requestCode, final int resultCode, final Intent data, final Activity... activityOrNull) { Activity activity = greedyGetActivity(activityOrNull); switch (requestCode) { case REQUEST_CAMERA_PICTURE: { @@ -717,6 +743,10 @@ public class ShareUtil { cursor.close(); } + // Try to grab via file extraction method + data.setAction(Intent.ACTION_VIEW); + picturePath = picturePath != null ? picturePath : extractFileFromIntentStr(data); + // Retrieve image from file descriptor / Cloud, e.g.: Google Drive, Picasa if (picturePath == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { try { @@ -762,7 +792,7 @@ public class ShareUtil { * Send a local broadcast (to receive within app), with given action and string-extra+value. * This is a convenience method for quickly sending just one thing. */ - public void sendLocalBroadcastWithStringExtra(String action, String extra, CharSequence value) { + public void sendLocalBroadcastWithStringExtra(final String action, final String extra, final CharSequence value) { Intent intent = new Intent(action); intent.putExtra(extra, value); LocalBroadcastManager.getInstance(_context).sendBroadcast(intent); @@ -776,7 +806,7 @@ public class ShareUtil { * @param filterActions All {@link IntentFilter} actions to filter for * @return The created instance. Has to be unregistered on {@link Activity} lifecycle events. */ - public BroadcastReceiver receiveResultFromLocalBroadcast(Callback.a2 callback, boolean autoUnregister, String... filterActions) { + public BroadcastReceiver receiveResultFromLocalBroadcast(final Callback.a2 callback, final boolean autoUnregister, final String... filterActions) { IntentFilter intentFilter = new IntentFilter(); for (String filterAction : filterActions) { intentFilter.addAction(filterAction); @@ -804,7 +834,7 @@ public class ShareUtil { * * @param file File that should be edited */ - public void requestPictureEdit(File file) { + public void requestPictureEdit(final File file) { Uri uri = getUriByFileProviderAuthority(file); int flags = Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION; @@ -826,9 +856,10 @@ public class ShareUtil { * * @param file Target file * @param mode 1 for picture, 2 for video, anything else for other - * @return + * @return Media URI */ - public Uri getMediaUri(File file, int mode) { + @SuppressWarnings("TryFinallyCanBeTryWithResources") + public Uri getMediaUri(final File file, final int mode) { Uri uri = MediaStore.Files.getContentUri("external"); uri = (mode != 0) ? (mode == 1 ? MediaStore.Images.Media.EXTERNAL_CONTENT_URI : MediaStore.Video.Media.EXTERNAL_CONTENT_URI) : uri; @@ -854,7 +885,7 @@ public class ShareUtil { * which implement the Chrome Custom Tab interface. This method changes * the customtab intent to use an available compatible browser, if available. */ - public void enableChromeCustomTabsForOtherBrowsers(Intent customTabIntent) { + public void enableChromeCustomTabsForOtherBrowsers(final Intent customTabIntent) { String[] checkpkgs = new String[]{ "com.android.chrome", "com.chrome.beta", "com.chrome.dev", "com.google.android.apps.chrome", "org.chromium.chrome", "org.mozilla.fennec_fdroid", "org.mozilla.firefox", "org.mozilla.firefox_beta", "org.mozilla.fennec_aurora", @@ -905,7 +936,7 @@ public class ShareUtil { * Request storage access. The user needs to press "Select storage" at the correct storage. * @param activity The activity which will receive the result from startActivityForResult */ - public void requestStorageAccessFramework(Activity... activity) { + public void requestStorageAccessFramework(final Activity... activity) { Activity a = greedyGetActivity(activity); if (a != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE); @@ -961,8 +992,12 @@ public class ShareUtil { * @param file The file object (file/folder) * @return Wether or not the file is under storage access folder */ - public boolean isUnderStorageAccessFolder(File file) { + public boolean isUnderStorageAccessFolder(final File file) { if (file != null) { + // When file writeable as is, it's the fastest way to learn SAF isn't required + if (file.canWrite()) { + return false; + } ContextUtils cu = new ContextUtils(_context); for (Pair storage : cu.getStorages(false, true)) { if (file.getAbsolutePath().startsWith(storage.first.getAbsolutePath())) { @@ -978,7 +1013,7 @@ public class ShareUtil { /** * Greedy extract Activity from parameter or convert context if it's a activity */ - private Activity greedyGetActivity(Activity... activity) { + private Activity greedyGetActivity(final Activity... activity) { if (activity != null && activity.length != 0 && activity[0] != null) { return activity[0]; } @@ -996,10 +1031,11 @@ public class ShareUtil { * @param isDir Wether or not the given file parameter is a directory * @return Wether or not the file can be written */ - public boolean canWriteFile(File file, boolean isDir) { + public boolean canWriteFile(final File file, final boolean isDir) { if (file == null) { return false; - } else if (file.getAbsolutePath().startsWith(Environment.getExternalStorageDirectory().getAbsolutePath())) { + } else if (file.getAbsolutePath().startsWith(Environment.getExternalStorageDirectory().getAbsolutePath()) + || file.getAbsolutePath().startsWith(_context.getFilesDir().getAbsolutePath())) { boolean s1 = isDir && file.getParentFile().canWrite(); return !isDir && file.getParentFile() != null ? file.getParentFile().canWrite() : file.canWrite(); } else { @@ -1017,7 +1053,8 @@ public class ShareUtil { * @param isDir Wether or not file is a directory. For non-existing (to be created) files this info is not known hence required. * @return A {@link DocumentFile} object or null if file cannot be converted */ - public DocumentFile getDocumentFile(File file, boolean isDir) { + @SuppressWarnings("RegExpRedundantEscape") + public DocumentFile getDocumentFile(final File file, final boolean isDir) { // On older versions use fromFile if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { return DocumentFile.fromFile(file); @@ -1066,7 +1103,7 @@ public class ShareUtil { return dof; } - public void showMountSdDialog(@StringRes int title, @StringRes int description, @DrawableRes int mountDescriptionGraphic, Activity... activityOrNull) { + public void showMountSdDialog(@StringRes final int title, @StringRes final int description, @DrawableRes final int mountDescriptionGraphic, final Activity... activityOrNull) { Activity activity = greedyGetActivity(activityOrNull); if (activity == null) { return; @@ -1087,11 +1124,12 @@ public class ShareUtil { dialogi.show(); } - public void writeFile(File file, boolean isDirectory, Callback.a2 writeFileCallback) { + @SuppressWarnings({"ResultOfMethodCallIgnored", "StatementWithEmptyBody"}) + public void writeFile(final File file, final boolean isDirectory, final Callback.a2 writeFileCallback) { try { FileOutputStream fileOutputStream = null; ParcelFileDescriptor pfd = null; - if (file.canWrite()) { + if (file.canWrite() || (!file.exists() && file.getParentFile().canWrite())) { if (isDirectory) { file.mkdirs(); } else { @@ -1112,7 +1150,10 @@ public class ShareUtil { writeFileCallback.callback(fileOutputStream != null || (isDirectory && file.exists()), fileOutputStream); } if (fileOutputStream != null) { - fileOutputStream.close(); + try { + fileOutputStream.close(); + } catch (Exception ignored) { + } } if (pfd != null) { pfd.close(); @@ -1132,7 +1173,7 @@ public class ShareUtil { * @param directCall Direct call number if possible */ @SuppressWarnings("SimplifiableConditionalExpression") - public void callTelephoneNumber(String telNo, boolean... directCall) { + public void callTelephoneNumber(final String telNo, final boolean... directCall) { Activity activity = greedyGetActivity(); if (activity == null) { throw new RuntimeException("Error: ShareUtil::callTelephoneNumber needs to be contstructed with activity context"); diff --git a/build.gradle b/build.gradle index 2d3db78c..7f72a6af 100644 --- a/build.gradle +++ b/build.gradle @@ -13,8 +13,8 @@ import java.text.SimpleDateFormat buildscript { ext { - version_gradle_tools = "3.5.1" - version_plugin_kotlin = "1.3.50" + version_gradle_tools = "3.5.2" + version_plugin_kotlin = "1.3.60" enable_plugin_kotlin = false version_compileSdk = 28 From 8326c2196c4074284a970cce5220ea7112b21edf Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Fri, 6 Dec 2019 22:02:24 +0100 Subject: [PATCH 07/49] Update tools --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 7f72a6af..cb5254e4 100644 --- a/build.gradle +++ b/build.gradle @@ -13,8 +13,8 @@ import java.text.SimpleDateFormat buildscript { ext { - version_gradle_tools = "3.5.2" - version_plugin_kotlin = "1.3.60" + version_gradle_tools = "3.5.3" + version_plugin_kotlin = "1.3.61" enable_plugin_kotlin = false version_compileSdk = 28 From 1f3cde93266ccb9c1551f3a6def5a9fa3fa5a385 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Mon, 23 Dec 2019 21:11:39 +0100 Subject: [PATCH 08/49] Add albanian / Tamil --- crowdin.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crowdin.yml b/crowdin.yml index 8525cd8a..d5fff4b3 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -52,4 +52,6 @@ files: id: in # Indonesian sk: sk # Slovak kn: kn # Kannada (Asian) + ta: ta # Tamil (Asian) + sq: sq # Albanian translate_attributes: 0 From 073a688db92f536cc872b6271c7a6fe664ee5fbc Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Mon, 23 Dec 2019 20:18:54 +0000 Subject: [PATCH 09/49] New Crowdin translations (#259) --- app/src/main/res/values-in/strings.xml | 25 +++++++++++++++++++++++++ app/src/main/res/values-sk/strings.xml | 25 +++++++++++++++++++++++++ app/src/main/res/values-sq/strings.xml | 25 +++++++++++++++++++++++++ app/src/main/res/values-ta/strings.xml | 25 +++++++++++++++++++++++++ app/src/main/res/values-tr/strings.xml | 15 +++++++++++++++ 5 files changed, 115 insertions(+) create mode 100644 app/src/main/res/values-in/strings.xml create mode 100644 app/src/main/res/values-sk/strings.xml create mode 100644 app/src/main/res/values-sq/strings.xml create mode 100644 app/src/main/res/values-ta/strings.xml diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml new file mode 100644 index 00000000..dbdd3fbf --- /dev/null +++ b/app/src/main/res/values-in/strings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml new file mode 100644 index 00000000..dbdd3fbf --- /dev/null +++ b/app/src/main/res/values-sk/strings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml new file mode 100644 index 00000000..dbdd3fbf --- /dev/null +++ b/app/src/main/res/values-sq/strings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml new file mode 100644 index 00000000..dbdd3fbf --- /dev/null +++ b/app/src/main/res/values-ta/strings.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index d01d781f..f158b52f 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -28,7 +28,9 @@ Ayrıca Yorumlar Gönderine Yorumlar Beğeniler + Bahsedilen Yeniden paylaşılan + Paylaşım Başlatıldı Hata: Pod listesi alınamadı! Üzgünüm, devam etmek için internete bağlı olmalısın. @@ -73,6 +75,7 @@ Protokol Pod adresi Eksik değer + Akışta son ziyaret edilen sayfaya git? Durum çubuğunu ana görünümde gizle Durum çubuğunu gizle Başlığı ana görünümde göster @@ -89,6 +92,7 @@ Menü Kaydırıcı + Gezinme çekmecesindeki girişlerin görünürlüğünü kontrol et Kullanıcı Genel Yönetici @@ -134,6 +138,7 @@ Sunucu Port Proxy kullanımını devre dışı bırakmak için uygulamanın yeniden başlatılması gerekiyor + Orbot proxy hazır ayarı yüklendi Chrome Özel Sekmeler ile harici bağlantılar açın. Bu özelliği kullanabilmek için Chromium, Firefox veya Google Chrome\'un yüklü olması gerekir.\n ÖNEMLİ NOT: Chrome Özel Sekmeler, yapılandırılmış proxy sunucuları kullanmaz! @@ -142,15 +147,19 @@ diaspora* hesap ayarlarını aç Kişi listenizi yönetin Etiketleri yönetin + Mevcut takip edilen etiketleri takipten vazgeç Hesabı Değiştir Yerel oturum verilerini silin ve başka bir diaspora * pod(a)/hesab(a) geçin Bu, tüm çerezleri ve oturum verilerini siler. Gerçekten hesabını değiştirmek istiyor musun? Önbelleği temizle WebView önbelleğini temizle Kaydırma yaparken üst ve alt araç çubuklarını otomatik olarak gizle + Araç Çubuklarını Otomatik Gizle + shared-by-notice ekle Bu uygulamaya, paylaşılan metinlere bir referans ekleyin: [örn #dandelion] Çeşitli + Tamamen Sıfırlama Uygulama ile ilgili tüm ayarları yerel olarak sil ve tüm hesaplardan çıkış yap Bu, uygulamanın tüm değiştirilen ayarlarını varsayılan değerlerine sıfırlar ve tüm podlardan çıkar. İndirdiğiniz görüntülere donulmaz. Devam etmek istediğine emin misin? Temel reklam engelleyiciyi etkinleştirin. Reklamlar yerleşik görünümlere dahil edilebilir @@ -186,6 +195,7 @@ Hey %1$s ! #dandelion’a bir göz at! Yardımcılar + Bu uygulamayı şu anda geliştiren ve devam ettiren <br><br>%1$s Katkıda bulunanlar %1$s<br><br>Teşekkürler! GNU GPLv3+ License @@ -193,6 +203,11 @@ Şu kütüphaneler kullanıldı: LeafPic\'ten biraz ilham ve kod aldık. Göz atabilirsiniz, özgür bir yazılım! Daha fazla göster + YouTube linklerini harici uygulamada açmak için etkinleştir + YouTube linkleri + Hesabınızın temasını değiştirin + Yenilemek için çek + Yenilemek için sayfanın üst kısmından çekin\nDeğişikliklerin geçerli olması için uygulamayı yeniden başlat. Bağış yap Bu projeyi beğendiniz mi? Projenin iyileştirilmesini ve sorunların çözülmesini istiyor musunuz?\n\nUygulama geliştirmek ve onunla ilgili blog gönderileri yazmak çok zaman alıyor! Projenin devam edebilmesi için yardım etmek istiyorsanız, lütfen küçük bir bağış yapmayı düşünün!\n\nBu proje boş zamanlarımda, tamamen ücretsiz ve reklamsız olarak geliştirilmiştir! From f9951f3b162fc879edda3fb00c632b4d104043f5 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Mon, 23 Dec 2019 21:20:56 +0100 Subject: [PATCH 10/49] Release v1.3.3 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index f957ce4d..cf74d251 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { defaultConfig { resValue "string", "manifest_package_id", "com.github.dfa.diaspora_android" applicationId "com.github.dfa.diaspora_android" - versionName "1.3.2" - versionCode 43 + versionName "1.3.3" + versionCode 44 vectorDrawables.useSupportLibrary = true minSdkVersion rootProject.ext.version_minSdk From a686fea141d16462af4fdb1e6f81b82160fce8b5 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sun, 9 Feb 2020 12:46:29 +0100 Subject: [PATCH 11/49] Bump junit from 4.12 to 4.13 (#261); New Crowdin translations (#260, #263) --- app/build.gradle | 2 +- app/src/main/res/values-gl/strings.xml | 10 +++++----- app/src/main/res/values-ru/strings.xml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index cf74d251..561e9aed 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -101,7 +101,7 @@ dependencies { // Jars implementation fileTree(dir: 'libs', include: ['*.jar']) - testImplementation 'junit:junit:4.12' + testImplementation 'junit:junit:4.13' // Android standard libs implementation "com.android.support:appcompat-v7:${version_library_appcompat}" diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 414cbe12..81987154 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -4,14 +4,14 @@ Abrir cadro de navegación Pechar cadro de navegación - Refrescar + Actualizar Pechar Cancelar Axustes Notificacións - Conversa - Fío de comentarios + Conversas + Cronoloxía Perfil Aspecto Actividades @@ -30,10 +30,10 @@ Gústame Mencionado Compartido - Comezou a compartir + Xa compartes Problema: non se obtivo a lista de nodos! - Desculpe, precisa unha conexión a internet para esa tarefa + Desculpa, tes que ter conexión a internet para esto Confirmación Quere saír? diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 3891dbec..8feba6c7 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -202,7 +202,7 @@ Расскажите мне больше Открывать ссылки на Youtube во внешних приложениях Ссылки на Youtube - Изменить тему вашей учетной записи + Изменить тему вашей учётной записи Потяните для обновления Потяните вниз, чтобы обновить страницу.\nВам нужно перезапустить приложение, чтобы изменения вступили в силу. Поддержать проект From 0f6b1c3ec33d0a5d30fb5c5b83f9d1f1b84d33e5 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sun, 9 Feb 2020 12:49:26 +0100 Subject: [PATCH 12/49] Update opoc --- .../net/gsantner/opoc/util/ShareUtil.java | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java index 4ebea3b7..01f92be9 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java +++ b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java @@ -144,8 +144,10 @@ public class ShareUtil { * @param chooserText The title text for the chooser, or null for default */ public void showChooser(final Intent intent, final String chooserText) { - _context.startActivity(Intent.createChooser(intent, - chooserText != null ? chooserText : _chooserTitle)); + try { + _context.startActivity(Intent.createChooser(intent, chooserText != null ? chooserText : _chooserTitle)); + } catch (Exception ignored) { + } } /** @@ -445,7 +447,10 @@ public class ShareUtil { android.content.ClipboardManager cm = ((android.content.ClipboardManager) _context.getSystemService(Context.CLIPBOARD_SERVICE)); if (cm != null) { ClipData clip = ClipData.newPlainText(_context.getPackageName(), text); - cm.setPrimaryClip(clip); + try { + cm.setPrimaryClip(clip); + } catch (Exception ignored) { + } return true; } } @@ -566,19 +571,13 @@ public class ShareUtil { } } - // external/ prefix for External storage - if (fileStr.startsWith((tmps = "external/"))) { - File f = new File(Uri.decode(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + fileStr.substring(tmps.length()))); - if (f.exists()) { - return f; - } - } - - // media/ prefix for External storage - if (fileStr.startsWith((tmps = "media/"))) { - File f = new File(Uri.decode(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + fileStr.substring(tmps.length()))); - if (f.exists()) { - return f; + // prefix for External storage (/storage/emulated/0 /// /sdcard/) --> e.g. "content://com.amaze.filemanager/storage_root/file.txt" = "/sdcard/file.txt" + for (String prefix : new String[]{"external/", "media/", "storage_root/"}) { + if (fileStr.startsWith((tmps = prefix))) { + File f = new File(Uri.decode(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + fileStr.substring(tmps.length()))); + if (f.exists()) { + return f; + } } } @@ -1096,7 +1095,11 @@ public class ShareUtil { for (int i = 0; i < parts.length; i++) { DocumentFile nextDof = dof.findFile(parts[i]); if (nextDof == null) { - nextDof = ((i < parts.length - 1) || isDir) ? dof.createDirectory(parts[i]) : dof.createFile("image", parts[i]); + try { + nextDof = ((i < parts.length - 1) || isDir) ? dof.createDirectory(parts[i]) : dof.createFile("image", parts[i]); + } catch (Exception ignored) { + nextDof = null; + } } dof = nextDof; } From cc16b84011fd3b6aa7ab0d44bcbf0f31149f2a38 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sun, 9 Feb 2020 13:12:07 +0100 Subject: [PATCH 13/49] Add seconds to 'save picture' date format, closes #262 --- app/src/main/java/net/gsantner/opoc/util/ShareUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java index 01f92be9..3d49b083 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java +++ b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java @@ -81,8 +81,8 @@ import static android.app.Activity.RESULT_OK; @SuppressWarnings({"UnusedReturnValue", "WeakerAccess", "SameParameterValue", "unused", "deprecation", "ConstantConditions", "ObsoleteSdkInt", "SpellCheckingInspection", "JavadocReference"}) public class ShareUtil { public final static String EXTRA_FILEPATH = "real_file_path_2"; - public final static SimpleDateFormat SDF_RFC3339_ISH = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm", Locale.getDefault()); - public final static SimpleDateFormat SDF_SHORT = new SimpleDateFormat("yyMMdd-HHmm", Locale.getDefault()); + public final static SimpleDateFormat SDF_RFC3339_ISH = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss", Locale.getDefault()); + public final static SimpleDateFormat SDF_SHORT = new SimpleDateFormat("yyMMdd-HHmmss", Locale.getDefault()); public final static String MIME_TEXT_PLAIN = "text/plain"; public final static String PREF_KEY__SAF_TREE_URI = "pref_key__saf_tree_uri"; From c5849d7d6a61f302e6f848d7470d9c24f4a891b1 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sun, 9 Feb 2020 13:12:59 +0100 Subject: [PATCH 14/49] Release v1.3.4 --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 561e9aed..ea9c622f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { defaultConfig { resValue "string", "manifest_package_id", "com.github.dfa.diaspora_android" applicationId "com.github.dfa.diaspora_android" - versionName "1.3.3" - versionCode 44 + versionName "1.3.4" + versionCode 45 vectorDrawables.useSupportLibrary = true minSdkVersion rootProject.ext.version_minSdk From a66d7bf3b2c674d0cf7be9dc1ef75517a156ea15 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sun, 29 Mar 2020 19:33:19 +0200 Subject: [PATCH 15/49] New Crowdin translations (#264) --- CHANGELOG.md | 2 +- README.md | 2 +- app/src/main/res/values-gl/strings.xml | 62 +++++++++++++------------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bb1931f..bcb1c3f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -![](https://test.gsantner.net/matomo/piwik.php?action_name=inapp_changelog&idsite=2&rec=1&urlref=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FCHANGELOG.md&_cvar=%7B%221%22%3A%5B%22source%22%2C%22changelog%22%5D%2C%222%22%3A%5B%22project%22%2C%22dandelion%22%5D%2C%223%22%3A%5B%22packageid%22%2C%22com.github.dfa.diaspora_android%22%5D%2C%224%22%3A%5B%22referrer%22%2C%22https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FCHANGELOG.md%22%5D%7D) +![](https://r.gsantner.net/matomo/piwik.php?action_name=inapp_changelog&idsite=2&rec=1&urlref=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FCHANGELOG.md&_cvar=%7B%221%22%3A%5B%22source%22%2C%22changelog%22%5D%2C%222%22%3A%5B%22project%22%2C%22dandelion%22%5D%2C%223%22%3A%5B%22packageid%22%2C%22com.github.dfa.diaspora_android%22%5D%2C%224%22%3A%5B%22referrer%22%2C%22https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FCHANGELOG.md%22%5D%7D) ### v1.3.x diff --git a/README.md b/README.md index 8c9f1474..592e94a0 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ [![Translate - with Stringlate](https://img.shields.io/badge/stringlate-translate-green.svg)](https://lonamiwebs.github.io/stringlate/translate?git=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion.git&mail=gro.xobliam@@rentnasg) [![Chat - Matrix](https://img.shields.io/badge/chat-on%20matrix-blue.svg)](https://matrix.to/#/#dandelion:matrix.org) [![Chat - FreeNode IRC](https://img.shields.io/badge/chat-on%20irc-blue.svg)](https://kiwiirc.com/client/irc.freenode.net/?nick=dandelion-anon|?##dandelion) [![Donate](https://img.shields.io/badge/donate-appreciation-orange.svg)](https://gsantner.net/supportme/?project=dandelion&source=readme) -[![Donate LiberaPay](https://img.shields.io/badge/donate-liberapay-orange.svg)](https://liberapay.com/gsantner/donate) ![](https://test.gsantner.net/matomo/piwik.php?action_name=readme&idsite=2&rec=1&urlref=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FREADME.md&_cvar=%7B%221%22%3A%5B%22source%22%2C%22readme%22%5D%2C%222%22%3A%5B%22project%22%2C%22dandelion%22%5D%2C%223%22%3A%5B%22packageid%22%2C%22com.github.dfa.diaspora_android%22%5D%2C%224%22%3A%5B%22referrer%22%2C%22https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FREADME.md%22%5D%7D) +[![Donate LiberaPay](https://img.shields.io/badge/donate-liberapay-orange.svg)](https://liberapay.com/gsantner/donate) ![](https://r.gsantner.net/matomo/piwik.php?action_name=readme&idsite=2&rec=1&urlref=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FREADME.md&_cvar=%7B%221%22%3A%5B%22source%22%2C%22readme%22%5D%2C%222%22%3A%5B%22project%22%2C%22dandelion%22%5D%2C%223%22%3A%5B%22packageid%22%2C%22com.github.dfa.diaspora_android%22%5D%2C%224%22%3A%5B%22referrer%22%2C%22https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FREADME.md%22%5D%7D) # dandelion\* diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 81987154..48cb70be 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -56,7 +56,7 @@ Compartir… Etiquetas Persoas - Por favor, engada un nome + Por favor, engade un nome Compartir ligazón Gardar imaxe Compartir imaxe @@ -66,19 +66,19 @@ Non se cargou a imaxe - Debe permitir \"Permiso de acceso a almacenamento\" para gardar capturas. Pode - pechar a aplicación ou reiniciar o dispositivo. Se non permite acceder ao almacenamento pero que utilizar máis tarde a captura de pantalla, poderá permitir posteriormente o acceso na sección de permisos do dispositivo onde pode activar o \"permiso de acceso a almacenamento\" para dandelion*. - Ten que permitir \"Permiso de acceso a almacenamento\" para gardar/subir imaxes. Despois de iso debería - pechar a aplicación ou reiniciar o dispositivo. Se non permite acceder ao almacenamento, para poder gardar imaxes posteriormente, deberá abrir: preferencias do sistema - apps - dandelion* no dispositivo. - Na sección de permisos pode activar o \"permiso de escritura no almacenamento\". + Debes permitir \"Permiso de acceso a almacenamento\" para gardar capturas. Podes + pechar a aplicación ou reiniciar o dispositivo. Se non permites acceder ao almacenamento pero queres utilizar máis tarde a captura de pantalla, poderás permitir posteriormente o acceso na sección de permisos do dispositivo onde podes activar o \"permiso de acceso a almacenamento\" para dandelion*. + Tes que permitir \"Permiso de acceso a almacenamento\" para gardar/subir imaxes. Despois de iso deberías + pechar a aplicación ou reiniciar o dispositivo. Se non permites acceder ao almacenamento, para poder gardar imaxes posteriormente, deberás abrir: preferencias do sistema - apps - dandelion* no dispositivo. + Na sección de permisos podes activar o \"permiso de escritura no almacenamento\". Permiso denegado. - Permiso concedido. Inténteo de novo. + Permiso concedido. Inténtao de novo. Nodo personalizado Nome do nodo Protocolo Enderezo do nodo Faltan datos - Ir a última paxina lida na conversa? + Ir a última páxina lida na conversa? Agochar a barra de estado na vista principal Agochar barra de estado Mostrar título na vista principal @@ -86,7 +86,7 @@ Atallo do lanzador A barra superior carga a conversa - Pulse nun espazo baldeiro na barra superior para abrir a conversa + Preme nun espazo baleiro na barra superior para abrir a conversa Aparencia Rede @@ -95,13 +95,13 @@ Cadro de navegación - Controle a visibiidade das entradas no cadro de navegación + Controla a visibiidade das entradas no cadro de navegación Usuaria Xeral Admin Decorado e cores - Estableza qué cores se utilizan na aplicación + Escolle qué cores se utilizan na aplicación Cor primaria Cor das barras de ferramentas Cor de énfase @@ -111,7 +111,7 @@ Notificacións extendidas Extender a icona da campá de notificación con un menú desplegable que mostre a categoría das notificacións - Cambiar o idioma de esta aplicación. Reinicie para que se aplique o troco + Cambiar o idioma de esta aplicación. Reinicia para que se aplique o troco Idioma Idioma do sistema @@ -135,7 +135,7 @@ Cargar axustes proxy para Tor (Orbot) HTTP Proxy Proxy Habilitar Proxy - Proxy para o tráfico de dandelion* para saltar cortalumes.\nPodería precisar reinicio. Esto podería non funcionar en algúns móbiles. + Proxy para o tráfico de dandelion* para saltar cortalumes.\nPodería precisar reinicio. Esto podería non funcionar nalgúns móbiles. Servidor Porto Precisa reiniciar a app para desactivar o uso do proxy @@ -145,12 +145,12 @@ Axustes personais Abrir os axustes da conta diaspora* - Xestione a súa lista de contactos + Xestiona a lista de contactos Xestionar etiquetas - Deixar de seguir etiquetas que segue + Deixar de seguir etiquetas que segues Mudar de conta Eliminar os datos locais da sesión e cambiar a outro nodo/conta de diaspora* - Esto eliminará todas as cookies e datos de sesión. Seguro que quere mudar de conta? + Esto eliminará todas as cookies e datos de sesión. Seguro que queres mudar de conta? Limpar cache Limpar a cache da VistaWeb Agochar automáticamente as barras superior e inferior mentras desplaza @@ -160,8 +160,8 @@ Varios Restablecer completamente - Eliminar todas os axustes locais do app e desconectar todas as contas - Esto restablecerá todos os axustes da aplicación ao valor por omisión e desconectarao de todos os nodos. As súas imaxes descargadas permanecerán. Seguro que quere proceder? + Eliminar todolos axustes locais da app e desconectar todas as contas + Esto restablecerá todos os axustes da aplicación ao valor por omisión e desconectarate de todolos nodos. As imaxes descargadas permanecerán. Seguro que queres proceder? Activar un AdBlocker básico. Poderían verse anuncios por exemplo en vistas incrustadas Bloquear publicidade Sobre @@ -179,19 +179,19 @@ Nome do perfil do nodo: %1$s Dominio do nodo: %1$s Ficheiro de depuración copiado ao portapapeis - dandelion* é a súa aplicación para a rede social diaspora*. Engade características como barras de ferramentas e soporte para servidores proxy como a rede Tor para a súa experiencia social. + dandelion* é a túa aplicación para a rede social diaspora*. Engade características como barras de ferramentas e soporte para servidores proxy como a rede Tor. Contribúa ao código! - dandelion* é desenvolto libre, libre de Liberdade, e segue o espíritu que marca o proxecto diaspora*. Se quere contribuír, adiante! Por agora somos un equipo pequeno, así que agradecemos calquer tipo de axuda! - Obteña as fontes - Traduza a app! - Non está a aplicación no seu idioma? Pode cambiar eso! Por qué non nos axuda traducíndoa? Utilizamos a plataforma Crowdin para que calquera poida traducir a app. + dandelion* é desenvolta libre, libre de Liberdade, e segue o espíritu que marca o proxecto diaspora*. Se queres contribuír, adiante! Por agora somos un equipo pequeno, así que agradecemos calquer tipo de axuda! + Aquí as fontes + Traduce a app! + Non está a aplicación no teu idioma? Podes cambiar eso! Por qué non nos axudas traducíndoa? Utilizamos a plataforma Crowdin para que calquera poida traducir a app. Deixame traducir - Qué lle parece! - dandelion* aínda está en desenvolvemento, asi que si ten suxerencias de calquer tipo o valoración, por favor utilice o noso xestor de erros para facérnolo saber! + Danos a túa opinión! + dandelion* aínda está en desenvolvemento, asi que se tes suxestións de calquer tipo ou valoración, por favor usa o noso xestor de errros para facérnolo saber! Reporte erros - Difunda! - Dígalle aos seus amigos e familiares que utiliza diaspora* e #dandelion! Por qué no escribir sobre a experiencia? Encantaríanos saber de vostede! - Comparta a aplicación + Difunde! + Dille aos teus amigos e familiares que utilizas diaspora* e #dandelion! Por qué non escribir sobre a experiencia? Encantaríanos saber de ti! + Comparte a aplicación Ei!! Olla #dandelion! %1$s Mantedores @@ -205,9 +205,9 @@ Cóntame máis Activar para abrir vídeos YouTube nunha app externa Ligazóns YouTube - Cambiar o decorado da súa conta - Tire para actualizar - Tirar hacia abaixo na parte superior da páxina.\nDebe reiniciar a app para que os cambios se apliquen. + Cambiar o decorado da túa conta + Tira para actualizar + Tirar hacia abaixo na parte superior da páxina.\nDebes reiniciar a app para que os cambios se apliquen. Doar Gústache este proxecto? Queres que siga mellorando e resolvendo os problemas?\n\nDesenvolver aplicacións e escribir a documentación leva moito tempo! Se queres apoiar ao proxecto para que continúe, por favor, considera facer unha pequena doazón!\n\nEste proxecto desenvólvese no tempo libre, ofrécese libre e gratuitamente e sen publicidade! From ea1ee6bc405d3259f33dceeb55dc1ad5f5b0e736 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sun, 29 Mar 2020 19:53:32 +0200 Subject: [PATCH 16/49] Update opoc --- build.gradle | 4 ++-- gradle/wrapper/gradle-wrapper.properties | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index cb5254e4..69f42bd6 100644 --- a/build.gradle +++ b/build.gradle @@ -13,8 +13,8 @@ import java.text.SimpleDateFormat buildscript { ext { - version_gradle_tools = "3.5.3" - version_plugin_kotlin = "1.3.61" + version_gradle_tools = "3.6.1" + version_plugin_kotlin = "1.3.71" enable_plugin_kotlin = false version_compileSdk = 28 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index ccb1db55..505b369a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip From 875f613cd91b960a30e617010c5797263976e69f Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Mon, 20 Apr 2020 02:01:40 +0200 Subject: [PATCH 17/49] Update supportme link to https --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 592e94a0..4456c0f7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://travis-ci.org/gsantner/dandelion.svg?branch=master)](https://travis-ci.org/gsantner/dandelion) [![Translate - with Stringlate](https://img.shields.io/badge/stringlate-translate-green.svg)](https://lonamiwebs.github.io/stringlate/translate?git=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion.git&mail=gro.xobliam@@rentnasg) [![Chat - Matrix](https://img.shields.io/badge/chat-on%20matrix-blue.svg)](https://matrix.to/#/#dandelion:matrix.org) [![Chat - FreeNode IRC](https://img.shields.io/badge/chat-on%20irc-blue.svg)](https://kiwiirc.com/client/irc.freenode.net/?nick=dandelion-anon|?##dandelion) -[![Donate](https://img.shields.io/badge/donate-appreciation-orange.svg)](https://gsantner.net/supportme/?project=dandelion&source=readme) +[![Donate](https://img.shields.io/badge/donate-appreciation-orange.svg)](https://gsantner.net/page/supportme.html?project=dandelion&source=gh_readme) [![Donate LiberaPay](https://img.shields.io/badge/donate-liberapay-orange.svg)](https://liberapay.com/gsantner/donate) ![](https://r.gsantner.net/matomo/piwik.php?action_name=readme&idsite=2&rec=1&urlref=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FREADME.md&_cvar=%7B%221%22%3A%5B%22source%22%2C%22readme%22%5D%2C%222%22%3A%5B%22project%22%2C%22dandelion%22%5D%2C%223%22%3A%5B%22packageid%22%2C%22com.github.dfa.diaspora_android%22%5D%2C%224%22%3A%5B%22referrer%22%2C%22https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FREADME.md%22%5D%7D) # dandelion\* @@ -78,7 +78,7 @@ For more licensing informations, see [`3rd party licenses`](/app/src/main/res/ra ### Notice #### Maintainers -- gsantner ([GitHub](https://github.com/gsantner), [Web](https://gsantner.net/supportme/?project=dandelion&source=readme), [diaspora*](https://pod.geraspora.de/people/d1cbdd70095301341e834860008dbc6c)) - - Bitcoin: [1B9ZyYdQoY9BxMe9dRUEKaZbJWsbQqfXU5](https://gsantner.net/supportme/?project=dandelion&source=readme) +- gsantner ([GitHub](https://github.com/gsantner), [Web](https://gsantner.net/page/supportme.html?project=dandelion&source=gh_readme), [diaspora*](https://pod.geraspora.de/people/d1cbdd70095301341e834860008dbc6c)) + - Bitcoin: [1B9ZyYdQoY9BxMe9dRUEKaZbJWsbQqfXU5](https://gsantner.net/page/supportme.html?project=dandelion&source=gh_readme) - vanitasvitae ([GitHub](https://github.com/vanitasvitae), [diaspora*](https://pod.geraspora.de/people/bbd7af90fbec013213e34860008dbc6c)) - Bitcoin: 1Ao3W6NaQv3xKppviB7RSFKjHo6PGd8RTy From cf1f0100bacdc6b3930b7d5ea299179daa75bf50 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Fri, 29 May 2020 23:22:35 +0200 Subject: [PATCH 18/49] Update crowdin bot commit message template --- crowdin.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crowdin.yml b/crowdin.yml index d5fff4b3..3413c37c 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,4 +1,6 @@ # vim: sw=2 ts=2 noexpandtab: +commit_message: "[ci skip] Crowdin translation bot: New translations for %language%" +append_commit_message: false files: - source: /app/src/main/res/values/strings.xml translation: /app/src/main/res/values-%android_code%/%original_file_name% From a7dd4a6166ad196e73b2ffa048ffdd651bf23d2f Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Fri, 29 May 2020 21:27:09 +0000 Subject: [PATCH 19/49] New Crowdin translations (#267) --- app/src/main/res/values-af/strings.xml | 1 - app/src/main/res/values-ar/strings.xml | 1 - app/src/main/res/values-bn/strings.xml | 1 - app/src/main/res/values-bs/strings.xml | 1 - app/src/main/res/values-ca/strings.xml | 1 - app/src/main/res/values-cs/strings.xml | 1 - app/src/main/res/values-da/strings.xml | 1 - app/src/main/res/values-de/strings.xml | 1 - app/src/main/res/values-el/strings.xml | 1 - app/src/main/res/values-es/strings.xml | 1 - app/src/main/res/values-fa/strings.xml | 1 - app/src/main/res/values-fi/strings.xml | 1 - app/src/main/res/values-fil/strings.xml | 1 - app/src/main/res/values-fr/strings.xml | 1 - app/src/main/res/values-gl/strings.xml | 1 - app/src/main/res/values-hi/strings.xml | 1 - app/src/main/res/values-hu/strings.xml | 1 - app/src/main/res/values-in/strings.xml | 1 - app/src/main/res/values-it/strings.xml | 1 - app/src/main/res/values-iw/strings.xml | 1 - app/src/main/res/values-ja/strings.xml | 1 - app/src/main/res/values-jw/strings.xml | 1 - app/src/main/res/values-kab/strings.xml | 1 - app/src/main/res/values-ko/strings.xml | 1 - app/src/main/res/values-ml/strings.xml | 1 - app/src/main/res/values-mr/strings.xml | 1 - app/src/main/res/values-nb-rNO/strings.xml | 1 - app/src/main/res/values-nl/strings.xml | 1 - app/src/main/res/values-no/strings.xml | 1 - app/src/main/res/values-pa/strings.xml | 1 - app/src/main/res/values-pl/strings.xml | 1 - app/src/main/res/values-pt-rBR/strings.xml | 1 - app/src/main/res/values-pt/strings.xml | 1 - app/src/main/res/values-ro/strings.xml | 1 - app/src/main/res/values-ru/strings.xml | 1 - app/src/main/res/values-sc/strings.xml | 1 - app/src/main/res/values-sk/strings.xml | 1 - app/src/main/res/values-sq/strings.xml | 1 - app/src/main/res/values-sr-rRS/strings.xml | 1 - app/src/main/res/values-sr/strings.xml | 1 - app/src/main/res/values-sv/strings.xml | 1 - app/src/main/res/values-ta/strings.xml | 1 - app/src/main/res/values-te/strings.xml | 1 - app/src/main/res/values-tr/strings.xml | 1 - app/src/main/res/values-uk/strings.xml | 11 +++++++++-- app/src/main/res/values-ur/strings.xml | 1 - app/src/main/res/values-vi/strings.xml | 1 - app/src/main/res/values-zh-rCN/strings.xml | 1 - app/src/main/res/values-zh-rTW/strings.xml | 1 - 49 files changed, 9 insertions(+), 50 deletions(-) diff --git a/app/src/main/res/values-af/strings.xml b/app/src/main/res/values-af/strings.xml index b0073f8b..3956db71 100644 --- a/app/src/main/res/values-af/strings.xml +++ b/app/src/main/res/values-af/strings.xml @@ -1,5 +1,4 @@ - Maak navigasie balk oop diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 8758ec6b..19b6acfc 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-bn/strings.xml b/app/src/main/res/values-bn/strings.xml index dbdd3fbf..43d88f4b 100644 --- a/app/src/main/res/values-bn/strings.xml +++ b/app/src/main/res/values-bn/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-bs/strings.xml b/app/src/main/res/values-bs/strings.xml index 94570037..fd455277 100644 --- a/app/src/main/res/values-bs/strings.xml +++ b/app/src/main/res/values-bs/strings.xml @@ -1,5 +1,4 @@ - Otvori navigacijsku ladicu diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index 9e1c43f9..c91ed813 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -1,5 +1,4 @@ - Obre el calaix de navegació diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index c2b0f40b..9d1675a3 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -1,5 +1,4 @@ - Otevøít navigaèní panel diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index b1107d43..1c540912 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -1,5 +1,4 @@ - Genindlæs diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 5b667b70..518262ec 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1,5 +1,4 @@ - NavDrawer öffnen diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index dbdd3fbf..43d88f4b 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index efe59429..bd46b3cc 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,5 +1,4 @@ - Abrir el panel de navegación diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index a9f80280..c2c00825 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-fi/strings.xml b/app/src/main/res/values-fi/strings.xml index dbdd3fbf..43d88f4b 100644 --- a/app/src/main/res/values-fi/strings.xml +++ b/app/src/main/res/values-fi/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-fil/strings.xml b/app/src/main/res/values-fil/strings.xml index 9b86c208..04cb116a 100644 --- a/app/src/main/res/values-fil/strings.xml +++ b/app/src/main/res/values-fil/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index c2911e57..bbdb4f36 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1,5 +1,4 @@ - Ouvrir le tiroir de navigation diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index 48cb70be..b6f49c8b 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -1,5 +1,4 @@ - Abrir cadro de navegación diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 650b8a62..8b3f62d4 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -1,5 +1,4 @@ - नेविगेशन ड्रॉवर खोलें diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 6f3c7934..b51b1df7 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -1,5 +1,4 @@ - Újratölt diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index dbdd3fbf..43d88f4b 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 02946483..ba09d501 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,5 +1,4 @@ - Apri barra di navigazione diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 22e2a857..148fe0aa 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index e81464fa..0cf49504 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -1,5 +1,4 @@ - ナビゲーションドロワーを開く diff --git a/app/src/main/res/values-jw/strings.xml b/app/src/main/res/values-jw/strings.xml index dbdd3fbf..43d88f4b 100644 --- a/app/src/main/res/values-jw/strings.xml +++ b/app/src/main/res/values-jw/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-kab/strings.xml b/app/src/main/res/values-kab/strings.xml index 49088e42..798670f3 100644 --- a/app/src/main/res/values-kab/strings.xml +++ b/app/src/main/res/values-kab/strings.xml @@ -1,5 +1,4 @@ - Ldi umuɣ n tunigin diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 05bcc52f..f7d5740d 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1,5 +1,4 @@ - 사이드 메뉴 열기 diff --git a/app/src/main/res/values-ml/strings.xml b/app/src/main/res/values-ml/strings.xml index 4ff52c1b..2f9811b6 100644 --- a/app/src/main/res/values-ml/strings.xml +++ b/app/src/main/res/values-ml/strings.xml @@ -1,5 +1,4 @@ - വീണ്ടും ലോഡ് ചെയ്യുക diff --git a/app/src/main/res/values-mr/strings.xml b/app/src/main/res/values-mr/strings.xml index dbdd3fbf..43d88f4b 100644 --- a/app/src/main/res/values-mr/strings.xml +++ b/app/src/main/res/values-mr/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index b2c5ccdc..5d3acae5 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -1,5 +1,4 @@ - Åpne navigasjonsskuff diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 4eaa84e2..11172034 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -1,5 +1,4 @@ - Open navigatiemenu diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml index 2ef280f0..e56fc1d8 100644 --- a/app/src/main/res/values-no/strings.xml +++ b/app/src/main/res/values-no/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml index dbdd3fbf..43d88f4b 100644 --- a/app/src/main/res/values-pa/strings.xml +++ b/app/src/main/res/values-pa/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 402dd6b1..6276b52b 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -1,5 +1,4 @@ - Otwórz panel nawigacyjny diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 0fb2bdbf..4a7f49cb 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -1,5 +1,4 @@ - Abra o painel de navegação diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 22867fd6..c4400b01 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -1,5 +1,4 @@ - Abrir menu de navegação diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index cd05a96c..b14cad56 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -1,5 +1,4 @@ - Reîncarcă diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 8feba6c7..9eca992b 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1,5 +1,4 @@ - Открыть панель навигации diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index 8810cfd3..ae43bce8 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -1,5 +1,4 @@ - Aberi su pannellu de nàvigu diff --git a/app/src/main/res/values-sk/strings.xml b/app/src/main/res/values-sk/strings.xml index dbdd3fbf..43d88f4b 100644 --- a/app/src/main/res/values-sk/strings.xml +++ b/app/src/main/res/values-sk/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-sq/strings.xml b/app/src/main/res/values-sq/strings.xml index dbdd3fbf..43d88f4b 100644 --- a/app/src/main/res/values-sq/strings.xml +++ b/app/src/main/res/values-sq/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-sr-rRS/strings.xml b/app/src/main/res/values-sr-rRS/strings.xml index 3f101997..6d3bf4a2 100644 --- a/app/src/main/res/values-sr-rRS/strings.xml +++ b/app/src/main/res/values-sr-rRS/strings.xml @@ -1,5 +1,4 @@ - Otvori navigacioni panel diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 485742e2..f85ef840 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index a729399b..283be7c9 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -1,5 +1,4 @@ - Stäng navigeringsmenyn diff --git a/app/src/main/res/values-ta/strings.xml b/app/src/main/res/values-ta/strings.xml index dbdd3fbf..43d88f4b 100644 --- a/app/src/main/res/values-ta/strings.xml +++ b/app/src/main/res/values-ta/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-te/strings.xml b/app/src/main/res/values-te/strings.xml index dbdd3fbf..43d88f4b 100644 --- a/app/src/main/res/values-te/strings.xml +++ b/app/src/main/res/values-te/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index f158b52f..dac3bb80 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -1,5 +1,4 @@ - Gezinme çekmecesini aç diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 5436cfc7..30da2c28 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -1,10 +1,11 @@ - Відкрити панель навігації Закрити панель навігації Перезавантажити + Закрити + Скасувати Налаштування Сповіщення @@ -58,7 +59,7 @@ Поширити посилання Зберегти зображення Поділитися зображенням - Відкрити у зовнішньому браузері… + Відкрити у зовнішньому браузері… Копіювати адресу посилання у буфер обміну Копіювати зображення у буфер обміну @@ -204,5 +205,11 @@ Використовуються такі бібліотеки: Ми взяли трохи натхнення і коду з LeafPic. Це також вільне програмне забезпечення, тож користуйтеся! Хочу знати більше + Увімкнути для відкриття посилань Youtube у зовнішньому застосунку + Youtube посилання + Змінити тему вашого облікового запису + Потягніть, щоб оновити + Потягніть сторінку згори вниз, щоб оновити.\nВам потрібно перезавантажити застосунок, щоб зміни набрали сили. Пожертвувати + Вам подобається цей проект? Бажаєте, щоб його покращували й виправляли помилки? \n\nРозробка застосунків та написання пов\'язаних статей у блозі займає багато часу! Якщо ви хочете допомогти цьому проекту розвиватися далі — зробіть маленьке пожертвування!\n\nЦей проект розроблений у вільний час, не містить реклами та є абсолютно безкоштовним! diff --git a/app/src/main/res/values-ur/strings.xml b/app/src/main/res/values-ur/strings.xml index dbdd3fbf..43d88f4b 100644 --- a/app/src/main/res/values-ur/strings.xml +++ b/app/src/main/res/values-ur/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index e575411b..c38cc780 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -1,5 +1,4 @@ - diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 1df262f3..2fd76705 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -1,5 +1,4 @@ - 打开导航栏 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index e8b9431c..ddcd27b6 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1,5 +1,4 @@ - 開啟側邊導覽選單 From 93aadae64b2f9688ef7d500d4457301bca7945fc Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Thu, 24 Sep 2020 23:18:12 +0200 Subject: [PATCH 20/49] [ci skip] Crowdin translation bot: New translations for Swedish (#272) --- app/src/main/res/values-sv/strings.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 283be7c9..fd993b66 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -1,7 +1,7 @@ - Stäng navigeringsmenyn + Öppna navigeringslådan Stäng navigeringslådan Ladda om Avsluta @@ -205,6 +205,11 @@ Följande bibliotek används: Vi hämtade inspiration och kod från LeafPic. Kika på det, det är också fri programvara! Berätta mer + Aktivera för att öppna Youtube-länkar i en extern app + Youtube-länkar + Ändra temat för ditt konto + Dra för att uppdatera + Dra ner på toppen av sidan för att uppdatera.\nDu måste starta om appen för att ändringarna ska träda i kraft. Donera Gillar du detta projektet? Vill du att det förbättras och att buggar åtgärdas snabbt?\n\nAtt utveckla appar och skriva relaterade blogginlägg tar mycket tid! Om du vill hjälpa till så att projektet kan fortgå så kan du överväga att ge en liten donation!\n\nDetta projektet utvecklas av volontärer på fritiden och är helt utan reklam! From 7b1897b2e0eff9f4475cce99bcb4db4dd24dbe04 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Fri, 13 Nov 2020 21:56:16 +0100 Subject: [PATCH 21/49] crowdin: Add macedonian --- crowdin.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/crowdin.yml b/crowdin.yml index 3413c37c..4dcdc120 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -56,4 +56,5 @@ files: kn: kn # Kannada (Asian) ta: ta # Tamil (Asian) sq: sq # Albanian + mk: mk # Macedonian translate_attributes: 0 From 20d75acd399b5352ab4055cf6bea2eda4f1c5142 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sat, 5 Dec 2020 22:08:40 +0100 Subject: [PATCH 22/49] New Crowdin updates (#276) --- app/src/main/res/values-mk/strings.xml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 app/src/main/res/values-mk/strings.xml diff --git a/app/src/main/res/values-mk/strings.xml b/app/src/main/res/values-mk/strings.xml new file mode 100644 index 00000000..43d88f4b --- /dev/null +++ b/app/src/main/res/values-mk/strings.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + From fa7e37ccbabd92a7e79f7d336566f816a1775e65 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Tue, 8 Dec 2020 08:41:38 +0100 Subject: [PATCH 23/49] Remove Travis CI - Open Source love is gone --- .travis.yml | 48 ------------------------------------------------ 1 file changed, 48 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index b4204f72..00000000 --- a/.travis.yml +++ /dev/null @@ -1,48 +0,0 @@ -language: android -jdk: oraclejdk8 - -before_cache: - # Do not cache a few Gradle files/directories (see https://docs.travis-ci.com/user/languages/java/#Caching) - - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock - - rm -fr $HOME/.gradle/caches/*/plugin-resolution/ - -cache: - directories: - # Android SDK - - $HOME/android-sdk-dl - - $HOME/android-sdk - - # Gradle dependencies - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ - - # Android build cache (see http://tools.android.com/tech-docs/build-cache) - - $HOME/.android/build-cache - -install: - # Download and unzip the Android SDK tools (if not already there thanks to the cache mechanism) - # Latest version available here: https://developer.android.com/studio/index.html#downloads - - if test ! -e $HOME/android-sdk-dl/sdk-tools.zip ; then curl https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip > $HOME/android-sdk-dl/sdk-tools.zip ; fi - - unzip -qq -n $HOME/android-sdk-dl/sdk-tools.zip -d $HOME/android-sdk - - # Install or update Android SDK components (will not do anything if already up to date thanks to the cache mechanism) - - echo y | $HOME/android-sdk/tools/bin/sdkmanager 'tools' > /dev/null - - echo y | $HOME/android-sdk/tools/bin/sdkmanager 'platform-tools' > /dev/null - - echo y | $HOME/android-sdk/tools/bin/sdkmanager 'build-tools;26.0.2' > /dev/null - - echo y | $HOME/android-sdk/tools/bin/sdkmanager 'platforms;android-27' > /dev/null - - echo y | $HOME/android-sdk/tools/bin/sdkmanager 'extras;google;m2repository' > /dev/null - -branches: - except: - - gh-pages - - l10n_master - - crowdin - -env: - global: - - ANDROID_HOME=$HOME/android-sdk - matrix: - - TASK="clean lintFlavorDefaultDebug --stacktrace" - - TASK="clean build check -x lint --stacktrace" - -script: "./gradlew --no-daemon --parallel $TASK" From 6fbd399a4bd1a74606df26d4d52bb4ef81a24242 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Wed, 9 Dec 2020 00:57:31 +0100 Subject: [PATCH 24/49] Update gsantner/opoc libs/utils --- .../format/markdown/SimpleMarkdownParser.java | 14 ++ .../opoc/ui/SearchOrCustomTextDialog.java | 201 ++++++++++++------ .../java/net/gsantner/opoc/util/Callback.java | 28 +++ .../net/gsantner/opoc/util/ContextUtils.java | 8 +- .../net/gsantner/opoc/util/FileUtils.java | 19 +- .../net/gsantner/opoc/util/NetworkUtils.java | 4 +- .../net/gsantner/opoc/util/ShareUtil.java | 10 +- build.gradle | 11 +- 8 files changed, 221 insertions(+), 74 deletions(-) diff --git a/app/src/main/java/net/gsantner/opoc/format/markdown/SimpleMarkdownParser.java b/app/src/main/java/net/gsantner/opoc/format/markdown/SimpleMarkdownParser.java index 1d3f016b..91d666ce 100644 --- a/app/src/main/java/net/gsantner/opoc/format/markdown/SimpleMarkdownParser.java +++ b/app/src/main/java/net/gsantner/opoc/format/markdown/SimpleMarkdownParser.java @@ -125,6 +125,20 @@ public class SimpleMarkdownParser { return text; } }; + public final static SmpFilter FILTER_H_TO_SUP = new SmpFilter() { + @Override + public String filter(String text) { + text = text + .replace("

", "") + .replace("

", "") + .replace("

", "") + .replace("

", "") + .replace("

", "") + .replace("

", "") + ; + return text; + } + }; public final static SmpFilter FILTER_NONE = new SmpFilter() { @Override public String filter(String text) { diff --git a/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java b/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java index 3371f4b8..7ba77cea 100644 --- a/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java +++ b/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java @@ -11,12 +11,14 @@ package net.gsantner.opoc.ui; import android.app.Activity; +import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Color; import android.graphics.Typeface; import android.os.AsyncTask; import android.os.Build; import android.support.annotation.ColorInt; +import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.StringRes; @@ -24,10 +26,14 @@ import android.support.design.widget.Snackbar; import android.support.v7.app.AlertDialog; import android.support.v7.widget.AppCompatEditText; import android.text.Editable; +import android.text.Spannable; +import android.text.SpannableString; import android.text.TextUtils; import android.text.TextWatcher; +import android.util.Pair; import android.view.Gravity; import android.view.KeyEvent; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; @@ -58,16 +64,23 @@ public class SearchOrCustomTextDialog { public static class DialogOptions { public Callback.a1 callback; - public List data = new ArrayList<>(); - public List highlightData = new ArrayList<>(); - public List iconsForData = new ArrayList<>(); + public Callback.a2 withPositionCallback; + public List data; + public List highlightData; + public List iconsForData; public String messageText = ""; + public String defaultText = ""; public boolean isSearchEnabled = true; public boolean isDarkDialog = false; public int dialogWidthDp = WindowManager.LayoutParams.MATCH_PARENT; public int dialogHeightDp = WindowManager.LayoutParams.WRAP_CONTENT; public int gravity = Gravity.NO_GRAVITY; public int searchInputType = 0; + public boolean searchIsRegex = false; + public Callback.a1 highlighter; + public String extraFilter = null; + + public Callback.a0 neutralButtonCallback = null; @ColorInt public int textColor = 0xFF000000; @@ -76,77 +89,122 @@ public class SearchOrCustomTextDialog { @StringRes public int cancelButtonText = android.R.string.cancel; @StringRes + public int neutralButtonText = 0; + @StringRes public int okButtonText = android.R.string.ok; @StringRes - public int titleText = android.R.string.untitled; + public int titleText = 0; @StringRes public int searchHintText = android.R.string.search_go; } + private static class WithPositionAdapter extends ArrayAdapter> { + + final LayoutInflater mInflater; + final @LayoutRes + int mLayout; + final DialogOptions dopt; + final List> filteredItems; + final Pattern extraPattern; + + WithPositionAdapter(Context context, @LayoutRes int layout, List> 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); + } + + @NonNull + @Override + public View getView(int pos, @Nullable View convertView, @NonNull ViewGroup parent) { + final Pair item = getItem(pos); + final String text = item.first; + final int posInOriginalList = item.second; + + final TextView textView; + if (convertView == null) { + textView = (TextView) mInflater.inflate(mLayout, parent, false); + } else { + textView = (TextView) convertView; + } + + if (posInOriginalList >= 0 && dopt.iconsForData != null && posInOriginalList < dopt.iconsForData.size() && dopt.iconsForData.get(posInOriginalList) != 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); + } + + if (dopt.highlightData != null) { + final boolean hl = dopt.highlightData.contains(text); + textView.setTextColor(hl ? dopt.highlightColor : dopt.textColor); + textView.setTypeface(null, hl ? Typeface.BOLD : Typeface.NORMAL); + } + + if (dopt.highlighter != null) { + Spannable s = new SpannableString(text); + dopt.highlighter.callback(s); + textView.setText(s); + } else { + textView.setText(text); + } + + return textView; + } + + @Override + public Filter getFilter() { + return new Filter() { + @SuppressWarnings("unchecked") + @Override + protected void publishResults(final CharSequence constraint, final FilterResults results) { + filteredItems.clear(); + filteredItems.addAll((List>) results.values); + notifyDataSetChanged(); + } + + @Override + protected FilterResults performFiltering(final CharSequence constraint) { + final ArrayList> 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)); + } + } + } + + 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 allItems = new ArrayList<>(dopt.data); - final List filteredItems = new ArrayList<>(allItems); + final List> 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 ArrayAdapter listAdapter = new ArrayAdapter(activity, android.R.layout.simple_list_item_1, filteredItems) { - @NonNull - @Override - public View getView(int pos, @Nullable View convertView, @NonNull ViewGroup parent) { - TextView textView = (TextView) super.getView(pos, convertView, parent); - String text = textView.getText().toString(); - - int posInOriginalList = dopt.data.indexOf(text); - if (posInOriginalList >= 0 && dopt.iconsForData != null && posInOriginalList < dopt.iconsForData.size() && dopt.iconsForData.get(posInOriginalList) != 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); - textView.setTextColor(hl ? dopt.highlightColor : dopt.textColor); - textView.setTypeface(null, hl ? Typeface.BOLD : Typeface.NORMAL); - - return textView; - } - - @Override - public Filter getFilter() { - return new Filter() { - @SuppressWarnings("unchecked") - @Override - protected void publishResults(final CharSequence constraint, final FilterResults results) { - filteredItems.clear(); - filteredItems.addAll((List) results.values); - notifyDataSetChanged(); - } - - @Override - protected FilterResults performFiltering(final CharSequence constraint) { - final FilterResults res = new FilterResults(); - final ArrayList resList = new ArrayList<>(); - final String fil = constraint.toString(); - - for (final CharSequence str : allItems) { - if ("".equals(fil) || str.toString().toLowerCase(Locale.getDefault()).contains(fil.toLowerCase(Locale.getDefault()))) { - resList.add(str); - } - } - res.values = resList; - res.count = resList.size(); - return res; - } - }; - } - }; + final WithPositionAdapter listAdapter = new WithPositionAdapter(activity, android.R.layout.simple_list_item_1, filteredItems, dopt); final AppCompatEditText searchEditText = new AppCompatEditText(activity); + searchEditText.setText(dopt.defaultText); searchEditText.setSingleLine(true); searchEditText.setMaxLines(1); searchEditText.setTextColor(dopt.textColor); @@ -174,24 +232,35 @@ public class SearchOrCustomTextDialog { listView.setAdapter(listAdapter); listView.setVisibility(dopt.data != null && !dopt.data.isEmpty() ? View.VISIBLE : View.GONE); linearLayout.setOrientation(LinearLayout.VERTICAL); + if (dopt.isSearchEnabled) { LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); int px = (int) (new ContextUtils(listView.getContext()).convertDpToPx(8)); lp.setMargins(px, px / 2, px, px / 2); linearLayout.addView(searchEditText, lp); } + final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0); layoutParams.weight = 1; linearLayout.addView(listView, layoutParams); if (!TextUtils.isEmpty(dopt.messageText)) { dialogBuilder.setMessage(dopt.messageText); } + dialogBuilder.setView(linearLayout) .setOnCancelListener(null) .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) { dialogBuilder.setTitle(dopt.titleText); } + if (dopt.isSearchEnabled) { dialogBuilder.setPositiveButton(dopt.okButtonText, (dialogInterface, i) -> { dialogInterface.dismiss(); @@ -205,7 +274,11 @@ public class SearchOrCustomTextDialog { listView.setOnItemClickListener((parent, view, position, id) -> { dialog.dismiss(); if (dopt.callback != null) { - dopt.callback.callback(filteredItems.get(position).toString()); + dopt.callback.callback(filteredItems.get(position).first); + } + if (dopt.withPositionCallback != null) { + final Pair item = filteredItems.get(position); + dopt.withPositionCallback.callback(item.first, item.second); } }); @@ -220,7 +293,6 @@ public class SearchOrCustomTextDialog { return false; }); - Window w; if ((w = dialog.getWindow()) != null && dopt.isSearchEnabled) { w.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); @@ -241,6 +313,9 @@ public class SearchOrCustomTextDialog { if (dopt.isSearchEnabled) { searchEditText.requestFocus(); } + if (dopt.defaultText != null) { + listAdapter.getFilter().filter(searchEditText.getText()); + } } diff --git a/app/src/main/java/net/gsantner/opoc/util/Callback.java b/app/src/main/java/net/gsantner/opoc/util/Callback.java index 7a3186e8..640b5cce 100644 --- a/app/src/main/java/net/gsantner/opoc/util/Callback.java +++ b/app/src/main/java/net/gsantner/opoc/util/Callback.java @@ -37,6 +37,10 @@ public class Callback { void callback(A arg1, B arg2, C arg3, D arg4, E arg5); } + public interface b0 { + boolean callback(); + } + public interface b1
{ boolean callback(A arg1); } @@ -56,4 +60,28 @@ public class Callback { public interface b5 { boolean callback(A arg1, B arg2, C arg3, D arg4, E arg5); } + + public interface s0 { + String callback(); + } + + public interface s1 { + String callback(A arg1); + } + + public interface s2 { + String callback(A arg1, B arg2); + } + + public interface s3 { + String callback(A arg1, B arg2, C arg3); + } + + public interface s4 { + String callback(A arg1, B arg2, C arg3, D arg4); + } + + public interface s5 { + String callback(A arg1, B arg2, C arg3, D arg4, E arg5); + } } diff --git a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java index 141f1b47..cab0128d 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java @@ -893,7 +893,7 @@ public class ContextUtils { public CharSequence filter(CharSequence src, int start, int end, Spanned dest, int dstart, int dend) { if (src.length() < 1) return null; char last = src.charAt(src.length() - 1); - String illegal = "|\\?*<\":>+[]/'"; + String illegal = "|\\?*<\":>[]/'"; if (illegal.indexOf(last) > -1) return src.subSequence(0, src.length() - 1); return null; } @@ -935,7 +935,11 @@ public class ContextUtils { ContentResolver cr = _context.getContentResolver(); mimeType = cr.getType(uri); } 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()); // Try to guess if the recommended methods fail diff --git a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java index c8a2b6d3..4e96a8ec 100644 --- a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java @@ -409,9 +409,10 @@ public class FileUtils { if (guess == null || guess.isEmpty()) { guess = "*/*"; - int dot = file.getName().lastIndexOf(".") + 1; - if (dot > 0 && dot < file.getName().length()) { - switch (file.getName().substring(dot)) { + String filename = file.getName().replace(".jenc", ""); + int dot = filename.lastIndexOf(".") + 1; + if (dot > 0 && dot < filename.length()) { + switch (filename.substring(dot)) { case "md": case "markdown": case "mkd": @@ -488,4 +489,16 @@ public class FileUtils { ret[2] = (int) (diff / 1000) % 60; // sec 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"); + } + } } diff --git a/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java b/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java index a8c564c6..08e36948 100644 --- a/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java @@ -24,6 +24,7 @@ import java.net.URL; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -150,6 +151,7 @@ public class NetworkUtils { return performCall(url, method, data, null); } + @SuppressWarnings("CharsetObjectCanBeUsed") private static String performCall(final URL url, final String method, final String data, final HttpURLConnection existingConnection) { try { final HttpURLConnection connection = existingConnection != null @@ -160,7 +162,7 @@ public class NetworkUtils { if (data != null && !data.isEmpty()) { connection.setDoOutput(true); final OutputStream output = connection.getOutputStream(); - output.write(data.getBytes(Charset.forName(UTF8))); + output.write(data.getBytes(Charset.forName("UTF-8"))); output.flush(); output.close(); } diff --git a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java index 3d49b083..9f5b0147 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java +++ b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java @@ -78,7 +78,7 @@ import static android.app.Activity.RESULT_OK; * Also allows to parse/fetch information out of shared information. * (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 { public final static String EXTRA_FILEPATH = "real_file_path_2"; public final static SimpleDateFormat SDF_RFC3339_ISH = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss", Locale.getDefault()); @@ -90,6 +90,8 @@ public class ShareUtil { public final static int REQUEST_PICK_PICTURE = 50002; public final static int REQUEST_SAF = 50003; + public final static int MIN_OVERWRITE_LENGTH = 5; + protected static String _lastCameraPictureFilepath; protected Context _context; @@ -1132,7 +1134,9 @@ public class ShareUtil { try { FileOutputStream fileOutputStream = null; ParcelFileDescriptor pfd = null; - if (file.canWrite() || (!file.exists() && file.getParentFile().canWrite())) { + final boolean existingEmptyFile = file.canWrite() && file.length() < MIN_OVERWRITE_LENGTH; + final boolean nonExistingCreatableFile = !file.exists() && file.getParentFile().canWrite(); + if (existingEmptyFile || nonExistingCreatableFile) { if (isDirectory) { file.mkdirs(); } else { @@ -1144,7 +1148,7 @@ public class ShareUtil { if (isDirectory) { // Nothing to do } else { - pfd = _context.getContentResolver().openFileDescriptor(dof.getUri(), "w"); + pfd = _context.getContentResolver().openFileDescriptor(dof.getUri(), "rw"); fileOutputStream = new FileOutputStream(pfd.getFileDescriptor()); } } diff --git a/build.gradle b/build.gradle index 69f42bd6..0ecd8134 100644 --- a/build.gradle +++ b/build.gradle @@ -13,8 +13,8 @@ import java.text.SimpleDateFormat buildscript { ext { - version_gradle_tools = "3.6.1" - version_plugin_kotlin = "1.3.71" + version_gradle_tools = "3.6.3" + version_plugin_kotlin = "1.3.72" enable_plugin_kotlin = false version_compileSdk = 28 @@ -59,6 +59,13 @@ allprojects { tasks.matching { task -> task.name.matches('.*generate.*Resources') }.all { task -> task.dependsOn copyRepoFiles } + + tasks.matching {it instanceof Test}.all { // Enable unit test output, html+xml output + testLogging.events "passed", "skipped", "failed", "standardOut", "standardError" + testLogging.showStandardStreams = true + reports.junitXml.enabled = true + reports.html.enabled = true + } } task clean(type: Delete) { From ff62aa5a07b69ac6cf69cbfb85610a57b1f8dd01 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Wed, 9 Dec 2020 01:07:24 +0100 Subject: [PATCH 25/49] Add Makefile; CI: Remove Circle/Travis, add GitHub Actions --- .github/workflows/build-android-project.yml | 69 +++++++++++++++++++++ .gitignore | 1 + Makefile | 55 ++++++++++++++++ app/build.gradle | 7 ++- circle.yml | 38 ------------ 5 files changed, 129 insertions(+), 41 deletions(-) create mode 100644 .github/workflows/build-android-project.yml create mode 100644 Makefile delete mode 100644 circle.yml diff --git a/.github/workflows/build-android-project.yml b/.github/workflows/build-android-project.yml new file mode 100644 index 00000000..b0dae337 --- /dev/null +++ b/.github/workflows/build-android-project.yml @@ -0,0 +1,69 @@ +name: "CI" + +on: [push, pull_request_target] + +jobs: + build: + if: "!contains(github.event.head_commit.message, 'ci skip') && (!contains(github.event_name, 'pull_request') || (contains(github.event_name, 'pull_request') && github.event.pull_request.head.repo.full_name != github.repository))" + runs-on: ubuntu-latest + steps: + + - name: "Checkout: Code" + uses: actions/checkout@v2 + + + - name: "Checkout: Code (PR)" + uses: actions/checkout@v2 + if: "contains(github.event_name, 'pull_request')" + with: + ref: ${{github.event.pull_request.head.ref}} + repository: ${{github.event.pull_request.head.repo.full_name}} + + - name: "Setup: Java" + uses: actions/setup-java@v1 + with: + java-version: 1.8 + + - name: "Cache: Gradle" + uses: actions/cache@v2 + with: + path: | + ~/.gradle + .gradle + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('gradle/wrapper/gradle-wrapper.*') }} + + - name: "Build: Project with make" + run: make clean all + + - name: "Build: List dist files" + if: always() + run: find dist -type f -maxdepth 2 + + - name: "Artifacts: All" + if: always() + uses: actions/upload-artifact@v2.2.1 + with: + name: "all" + path: dist + retention-days: 5 + + - name: "Artifacts: Android APK" + uses: actions/upload-artifact@v2.2.1 + with: + name: "android-apk" + path: | + dist/*.apk + + - name: "Test: JUnit report" + if: always() + uses: mikepenz/action-junit-report@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + report_paths: 'dist/tests/TEST-*.xml' + check_name: "JUnit" + + - name: "Test: Android Lint" + if: always() + uses: yutailang0119/action-android-lint@v1.0.2 + with: + xml_path: 'dist/lint/lint-results-flavorDefaultDebug.xml' diff --git a/.gitignore b/.gitignore index 6aa6839b..59057232 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ tmp/ ### Gradle ### .gradle build/ +dist/ gradle-app.setting # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..14eef72c --- /dev/null +++ b/Makefile @@ -0,0 +1,55 @@ +# License of Makefile: Public Domain / CC0 +.PHONY: $(shell sed -n -e '/^$$/ { n ; /^[^ .\#][^ ]*:/ { s/:.*$$// ; p ; } ; }' $(MAKEFILE_LIST)) +.NOTPARALLEL: clean +.DEFAULT_GOAL := all + +env-%: + @: $(if ${${*}},,$(error Environment variable $* not set)) +#################################################################################### + +DIST_DIR = dist +MOVE = mv + +all: $(DIST_DIR) lint test build + +#################################################################################### + +$(DIST_DIR): + mkdir -p ${DIST_DIR} + +.NOTPARALLEL: gradle gradle-check-error +gradle: env-ANDROID_SDK_ROOT + mkdir -p $(DIST_DIR)/log/ + chmod +x gradlew + ./gradlew --no-daemon --parallel --stacktrace $A 2>&1 | tee "$(DIST_DIR)/log/gradle.log" + @echo "-----------------------------------------------------------------------------------" + +gradle-check-error: + mv "$(DIST_DIR)/log/gradle.log" "$(DIST_DIR)/log/gradle$A.log" + cat "$(DIST_DIR)/log/gradle$A.log" | grep "BUILD " | tail -n1 | grep -q "BUILD SUCCESSFUL in" + +build: + rm -f $(DIST_DIR)/*.apk + $(MAKE) A="clean assembleFlavorAtest -x lint" gradle + find app -type f -iname '*.apk' | grep -v 'unsigned.apk' | xargs cp -R -t $(DIST_DIR)/ + $(MAKE) A="-build" gradle-check-error + +lint: + rm -Rf $(DIST_DIR)/lint + mkdir -p $(DIST_DIR)/lint/ + $(MAKE) A="lintFlavorDefaultDebug" gradle + find app -type f -iname 'lint-results-*' | xargs cp -R -t $(DIST_DIR)/lint + $(MAKE) A="-lint" gradle-check-error + +test: + rm -Rf $(DIST_DIR)/tests + $(MAKE) A="testFlavorDefaultDebugUnitTest -x lint" gradle + mkdir -p app/build/test-results/testFlavorDefaultDebugUnitTest && echo 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHRlc3RzdWl0ZSBuYW1lPSJkdW1teSIgdGVzdHM9IjEiIHNraXBwZWQ9IjAiIGZhaWx1cmVzPSIwIiBlcnJvcnM9IjAiIHRpbWVzdGFtcD0iMjAyMC0xMi0wOFQwMDowMDowMCIgaG9zdG5hbWU9ImxvY2FsaG9zdCIgdGltZT0iMC4wMSI+CiAgPHByb3BlcnRpZXMvPgogIDx0ZXN0Y2FzZSBuYW1lPSJkdW1teSIgY2xhc3NuYW1lPSJkdW1teSIgdGltZT0iMC4wMSIvPgogIDxzeXN0ZW0tb3V0PjwhW0NEQVRBW11dPjwvc3lzdGVtLW91dD4KICA8c3lzdGVtLWVycj48IVtDREFUQVtdXT48L3N5c3RlbS1lcnI+CjwvdGVzdHN1aXRlPgo=' | base64 -d > 'app/build/test-results/testFlavorDefaultDebugUnitTest/TEST-dummy.xml' + find app -type d -iname 'testFlavorDefaultDebugUnitTest' | xargs cp -R -t $(DIST_DIR)/ + mv ${DIST_DIR}/testFlavorDefaultDebugUnitTest $(DIST_DIR)/tests + $(MAKE) A="-test" gradle-check-error + +clean: + $(MAKE) A="clean" gradle + rm -Rf $(DIST_DIR) app/build app/flavor* + $(MAKE) $(DIST_DIR) diff --git a/app/build.gradle b/app/build.gradle index ea9c622f..41dab2d3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,6 +21,7 @@ android { buildConfigField "boolean", "IS_TEST_BUILD", "false" buildConfigField "boolean", "IS_GPLAY_BUILD", "false" buildConfigField "String[]", "DETECTED_ANDROID_LOCALES", "${findUsedAndroidLocales()}" + buildConfigField "String", "BUILD_DATE", "\"${getBuildDate()}\"" buildConfigField "String", "GITHASH", "\"${getGitHash()}\"" setProperty("archivesBaseName", applicationId + "-v" + versionCode + "-" + versionName) } @@ -89,8 +90,7 @@ android { } lintOptions { - disable 'MissingTranslation' - disable 'InvalidPackage' + disable 'MissingTranslation', 'InvalidPackage', 'ObsoleteLintCustomCheck', 'DefaultLocale', 'UnusedAttribute', 'VectorRaster', 'InflateParams', 'IconLocation', 'UnusedResources', 'TypographyEllipsis' abortOnError false } } @@ -118,9 +118,10 @@ dependencies { implementation 'commons-io:commons-io:2.6' implementation "info.guardianproject.netcipher:netcipher:${version_library_netcipher}" implementation "info.guardianproject.netcipher:netcipher-webkit:${version_library_netcipher}" + //noinspection AnnotationProcessorOnCompilePath implementation "com.jakewharton:butterknife:${version_library_butterknife}" if (enable_plugin_kotlin) { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$version_plugin_kotlin" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${version_plugin_kotlin}" } // Processors diff --git a/circle.yml b/circle.yml deleted file mode 100644 index 35978980..00000000 --- a/circle.yml +++ /dev/null @@ -1,38 +0,0 @@ -################### -general: - artifacts: - - /home/ubuntu/dandelion/app/build/outputs/apk/ - branches: - ignore: - - gh-pages - - l10n_master - - crowdin - -################### -machine: - java: - version: oraclejdk8 - environment: - ANDROID_HOME: /usr/local/android-sdk-linux - -################### -dependencies: - pre: - # Android SDK Platform - - if [ ! -d "/usr/local/android-sdk-linux/platforms/android-26" ]; then echo y | android update sdk --no-ui --all --filter "android-26"; fi - # Android SDK Build-tools - - if [ ! -d "/usr/local/android-sdk-linux/build-tools/26.0.1" ]; then echo y | android update sdk --no-ui --all --filter "build-tools-26.0.1"; fi - # Android Support Repository - deprecated - #- if [ ! -d "/usr/local/android-sdk-linux/extras/android/m2repository/com/android/support/design/26.2.0" ]; then echo y | android update sdk --no-ui --all --filter "extra-android-m2repository"; fi - - - cache_directories: - - /usr/local/android-sdk-linux/platforms/android-26 - - /usr/local/android-sdk-linux/build-tools/26.0.1 - #- /usr/local/android-sdk-linux/extras/android/m2repository - -################### -test: - override: - - (./gradlew assembleFlavorDefault): - timeout: 360 From f3b3c6a1609884ae06f47059b93dfc22f751a6f0 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Wed, 9 Dec 2020 11:59:36 +0100 Subject: [PATCH 26/49] disable AndroidSupportMeWrapper --- .../com/github/dfa/diaspora_android/activity/MainActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java b/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java index 2e57295b..290cad2e 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java @@ -664,7 +664,7 @@ public class MainActivity extends ThemedActivity protected void onResume() { AppLog.v(this, "onResume()"); super.onResume(); - new AndroidSupportMeWrapper(this).mainOnResume(); + //new AndroidSupportMeWrapper(this).mainOnResume(); AppLog.v(this, "Register BroadcastReceivers"); LocalBroadcastManager.getInstance(this).registerReceiver(brSetTitle, new IntentFilter(ACTION_UPDATE_TITLE_FROM_URL)); LocalBroadcastManager.getInstance(this).registerReceiver(brOpenExternalLink, new IntentFilter(ACTION_OPEN_EXTERNAL_URL)); From 4ebd3932509f927874765de030fd4c36f40b1a9c Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Wed, 9 Dec 2020 12:08:05 +0100 Subject: [PATCH 27/49] Update v1.3.5 (translations/libs only) --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 41dab2d3..09c8527f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { defaultConfig { resValue "string", "manifest_package_id", "com.github.dfa.diaspora_android" applicationId "com.github.dfa.diaspora_android" - versionName "1.3.4" - versionCode 45 + versionName "1.3.5" + versionCode 46 vectorDrawables.useSupportLibrary = true minSdkVersion rootProject.ext.version_minSdk From ceb98c4258c74c67276144068f67519cf4cf2d4f Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Mon, 21 Dec 2020 23:50:58 +0100 Subject: [PATCH 28/49] gh actions pull_request action --- .github/workflows/build-android-project.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-android-project.yml b/.github/workflows/build-android-project.yml index b0dae337..3f8ac46d 100644 --- a/.github/workflows/build-android-project.yml +++ b/.github/workflows/build-android-project.yml @@ -1,6 +1,6 @@ name: "CI" -on: [push, pull_request_target] +on: [push, pull_request] jobs: build: From 369abf14a54e1b799bb48668108d39edb05ee150 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Tue, 22 Dec 2020 03:39:33 +0100 Subject: [PATCH 29/49] CI/CD: Remove special junit/lint jobs --- .github/workflows/build-android-project.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.github/workflows/build-android-project.yml b/.github/workflows/build-android-project.yml index 3f8ac46d..df243d07 100644 --- a/.github/workflows/build-android-project.yml +++ b/.github/workflows/build-android-project.yml @@ -53,17 +53,3 @@ jobs: name: "android-apk" path: | dist/*.apk - - - name: "Test: JUnit report" - if: always() - uses: mikepenz/action-junit-report@v1 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - report_paths: 'dist/tests/TEST-*.xml' - check_name: "JUnit" - - - name: "Test: Android Lint" - if: always() - uses: yutailang0119/action-android-lint@v1.0.2 - with: - xml_path: 'dist/lint/lint-results-flavorDefaultDebug.xml' From f1464b5f8f76991cda77f0860e0edb4d2e786216 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Wed, 23 Dec 2020 14:45:38 +0100 Subject: [PATCH 30/49] ci add comment for cleanup as github has no delete-all button --- .github/workflows/build-android-project.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/build-android-project.yml b/.github/workflows/build-android-project.yml index df243d07..07923101 100644 --- a/.github/workflows/build-android-project.yml +++ b/.github/workflows/build-android-project.yml @@ -1,3 +1,16 @@ +############################################################################################################################## +# # Cleanup: +#const sleep = ms => () => new Promise((resolve, reject) => window.setTimeout(resolve, ms)); +#Promise.resolve() +#.then(() => { document.getElementsByClassName("details-overlay details-reset position-relative d-inline-block ")[3].children[0].click(); }) +#.then(sleep(500)) +#.then(() => { document.getElementsByClassName("dropdown-item btn-link menu-item-danger")[0].click(); }) +#.then(sleep(1000)) +#.then(() => { document.getElementsByClassName("btn btn-block btn-danger")[0].click();}); +# +# while [ 1 ] ; do sleep 4; xdotool key Up; sleep 0.1; xdotool key Return; done +############################################################################################################################## + name: "CI" on: [push, pull_request] From 97d9bf434ec57bdd536093fa764d7023d690ec57 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Tue, 12 Jan 2021 20:23:10 +0100 Subject: [PATCH 31/49] Various additions & improvements to opoc utils --- .../opoc/ui/SearchOrCustomTextDialog.java | 62 +++++++-------- .../net/gsantner/opoc/util/ActivityUtils.java | 20 +++-- .../java/net/gsantner/opoc/util/AdBlock.java | 78 +++++++++++++++---- .../net/gsantner/opoc/util/ContextUtils.java | 26 ++++++- .../net/gsantner/opoc/util/FileUtils.java | 7 ++ .../net/gsantner/opoc/util/NetworkUtils.java | 11 ++- 6 files changed, 147 insertions(+), 57 deletions(-) diff --git a/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java b/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java index 7ba77cea..f0558275 100644 --- a/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java +++ b/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java @@ -26,6 +26,7 @@ import android.support.design.widget.Snackbar; import android.support.v7.app.AlertDialog; import android.support.v7.widget.AppCompatEditText; import android.text.Editable; +import android.text.InputType; import android.text.Spannable; import android.text.SpannableString; import android.text.TextUtils; @@ -75,7 +76,7 @@ public class SearchOrCustomTextDialog { public int dialogWidthDp = WindowManager.LayoutParams.MATCH_PARENT; public int dialogHeightDp = WindowManager.LayoutParams.WRAP_CONTENT; public int gravity = Gravity.NO_GRAVITY; - public int searchInputType = 0; + public int searchInputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS; public boolean searchIsRegex = false; public Callback.a1 highlighter; public String extraFilter = null; @@ -99,21 +100,20 @@ public class SearchOrCustomTextDialog { } private static class WithPositionAdapter extends ArrayAdapter> { + @LayoutRes + final int _layout; + final LayoutInflater _inflater; + final DialogOptions _dopt; + final List> _filteredItems; + final Pattern _extraPattern; - final LayoutInflater mInflater; - final @LayoutRes - int mLayout; - final DialogOptions dopt; - final List> filteredItems; - final Pattern extraPattern; - - WithPositionAdapter(Context context, @LayoutRes int layout, List> 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); + WithPositionAdapter(Context c_context, @LayoutRes int c_layout, List> c_filteredItems, DialogOptions c_dopt) { + super(c_context, c_layout, c_filteredItems); + _inflater = LayoutInflater.from(c_context); + _layout = c_layout; + _dopt = c_dopt; + _filteredItems = c_filteredItems; + _extraPattern = (c_dopt.extraFilter == null ? null : Pattern.compile(c_dopt.extraFilter)); } @NonNull @@ -125,30 +125,30 @@ public class SearchOrCustomTextDialog { final TextView textView; if (convertView == null) { - textView = (TextView) mInflater.inflate(mLayout, parent, false); + textView = (TextView) _inflater.inflate(_layout, parent, false); } else { textView = (TextView) convertView; } - if (posInOriginalList >= 0 && dopt.iconsForData != null && posInOriginalList < dopt.iconsForData.size() && dopt.iconsForData.get(posInOriginalList) != 0) { - textView.setCompoundDrawablesWithIntrinsicBounds(dopt.iconsForData.get(posInOriginalList), 0, 0, 0); + if (posInOriginalList >= 0 && _dopt.iconsForData != null && posInOriginalList < _dopt.iconsForData.size() && _dopt.iconsForData.get(posInOriginalList) != 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)); + textView.setCompoundDrawableTintList(ColorStateList.valueOf(_dopt.isDarkDialog ? Color.WHITE : Color.BLACK)); } } else { textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); } - if (dopt.highlightData != null) { - final boolean hl = dopt.highlightData.contains(text); - textView.setTextColor(hl ? dopt.highlightColor : dopt.textColor); + if (_dopt.highlightData != null) { + final boolean hl = _dopt.highlightData.contains(text); + textView.setTextColor(hl ? _dopt.highlightColor : _dopt.textColor); textView.setTypeface(null, hl ? Typeface.BOLD : Typeface.NORMAL); } - if (dopt.highlighter != null) { + if (_dopt.highlighter != null) { Spannable s = new SpannableString(text); - dopt.highlighter.callback(s); + _dopt.highlighter.callback(s); textView.setText(s); } else { textView.setText(text); @@ -163,8 +163,8 @@ public class SearchOrCustomTextDialog { @SuppressWarnings("unchecked") @Override protected void publishResults(final CharSequence constraint, final FilterResults results) { - filteredItems.clear(); - filteredItems.addAll((List>) results.values); + _filteredItems.clear(); + _filteredItems.addAll((List>) results.values); notifyDataSetChanged(); } @@ -172,14 +172,14 @@ public class SearchOrCustomTextDialog { protected FilterResults performFiltering(final CharSequence constraint) { final ArrayList> resList = new ArrayList<>(); - if (dopt.data != null) { + 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(); + 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)); + final boolean matchRegex = _dopt.searchIsRegex && (str.toString().matches(fil)); if (matchExtra && (matchNormal || matchRegex || emptySearch)) { resList.add(new Pair<>(str, i)); } diff --git a/app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java b/app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java index 024d0f2f..41c86e17 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java @@ -13,7 +13,6 @@ package net.gsantner.opoc.util; import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.ComponentName; -import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; @@ -39,7 +38,7 @@ import android.webkit.WebView; import android.widget.ScrollView; -@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "SpellCheckingInspection"}) +@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "SpellCheckingInspection", "rawtypes", "UnusedReturnValue"}) public class ActivityUtils extends net.gsantner.opoc.util.ContextUtils { //######################## //## Members, Constructors @@ -239,13 +238,22 @@ public class ActivityUtils extends net.gsantner.opoc.util.ContextUtils { } public ActivityUtils setLauncherActivityEnabled(Class activityClass, boolean enable) { - Context context = _context.getApplicationContext(); - PackageManager pkg = context.getPackageManager(); - ComponentName component = new ComponentName(context, activityClass); - pkg.setComponentEnabledSetting(component, enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); + try { + ComponentName component = new ComponentName(_context, activityClass); + _context.getPackageManager().setComponentEnabledSetting(component, enable ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); + } catch (Exception ignored) { + } return this; } + public boolean isLauncherEnabled(Class activityClass) { + try { + ComponentName component = new ComponentName(_context, activityClass); + return _context.getPackageManager().getComponentEnabledSetting(component) != PackageManager.COMPONENT_ENABLED_STATE_DISABLED; + } catch (Exception ignored) { + } + return false; + } @ColorInt public Integer getCurrentPrimaryColor() { diff --git a/app/src/main/java/net/gsantner/opoc/util/AdBlock.java b/app/src/main/java/net/gsantner/opoc/util/AdBlock.java index 304a4b85..5045d0f2 100644 --- a/app/src/main/java/net/gsantner/opoc/util/AdBlock.java +++ b/app/src/main/java/net/gsantner/opoc/util/AdBlock.java @@ -46,8 +46,9 @@ import java.util.Set; /** * Simple Host-Based AdBlocker */ -@SuppressWarnings({"WeakerAccess", "SpellCheckingInspection", "unused"}) +@SuppressWarnings({"WeakerAccess", "SpellCheckingInspection", "unused", "TryFinallyCanBeTryWithResources"}) public class AdBlock { + private static final Object synchronizeObj = new Object(); private static final AdBlock instance = new AdBlock(); public static AdBlock getInstance() { @@ -61,7 +62,9 @@ public class AdBlock { //######################## private final Set _adblockHostsFromRaw = new HashSet<>(); private final Set _adblockHosts = new HashSet<>(); - private boolean _isLoaded; + private final List> _customBlockCallbacks = new ArrayList<>(); + private boolean _isLoaded = false; + private boolean _isAdblockLogging = false; //######################## //## @@ -72,25 +75,47 @@ public class AdBlock { } public boolean isAdHost(String urlS) { + boolean block = false; if (urlS != null && !urlS.isEmpty() && urlS.startsWith("http")) { try { - URI url = new URI(urlS); + URI url; + try { + url = new URI(urlS); + } catch (Exception e) { + url = new URI(urlS.replaceFirst("[?].*", "")); + } String host = url.getHost().trim(); if (host.startsWith("www.") && host.length() >= 4) { host = host.substring(4); } - return _adblockHosts.contains(host) || _adblockHosts.contains("www." + host); + block = _adblockHosts.contains(host) || _adblockHosts.contains("www." + host); + for (Callback.b3 cb : _customBlockCallbacks) { + if (block) { + break; + } + try { + block = cb.callback(url, urlS, host); + } catch (Exception ignored) { + } + } } catch (URISyntaxException e) { e.printStackTrace(); } } - return false; + + if (_isAdblockLogging) { + Log.d(getClass().getSimpleName(), "UrlAllowed-" + (block ? "N" : "Y") + " " + urlS); + } + return block; } public AdBlock reset() { - _adblockHosts.clear(); - _adblockHosts.addAll(_adblockHostsFromRaw); + synchronized (synchronizeObj) { + _adblockHosts.clear(); + _adblockHosts.addAll(_adblockHostsFromRaw); + _customBlockCallbacks.clear(); + } return this; } @@ -102,7 +127,7 @@ public class AdBlock { return new WebResourceResponse("text/plain", "utf-8", new ByteArrayInputStream("".getBytes())); } - public void addBlockedHosts(String... hosts) { + public AdBlock addBlockedHosts(String... hosts) { for (String host : hosts) { if (host != null) { host = host.trim(); @@ -110,23 +135,29 @@ public class AdBlock { host = host.substring(4); } if (!host.startsWith("#") && !host.startsWith("\"")) { - _adblockHosts.add(host); + synchronized (synchronizeObj) { + _adblockHosts.add(host); + } } } } - + return this; } - public void loadHostsFromRawAssetsAsync(final Context context) { - new Thread(new Runnable() { - @Override - public void run() { - try { + public void loadHostsFromRawAssetsAsync(final Context context, final boolean... debugIgnoreAssets) { + if (debugIgnoreAssets != null && debugIgnoreAssets.length > 0 && debugIgnoreAssets[0]) { + _isLoaded = true; + return; + } + + new Thread(() -> { + try { + synchronized (synchronizeObj) { loadHostsFromRawAssets(context); _isLoaded = true; - } catch (IOException e) { - e.printStackTrace(); } + } catch (IOException e) { + e.printStackTrace(); } }).start(); } @@ -172,4 +203,17 @@ public class AdBlock { } return adblockResIds; } + + // URI uri, String url, String host + public AdBlock addCustomBlockCallback(Callback.b3 cb) { + synchronized (synchronizeObj) { + _customBlockCallbacks.add(cb); + } + return this; + } + + public AdBlock setLogEnabled(boolean isAdblockLogging) { + _isAdblockLogging = isAdblockLogging; + return this; + } } diff --git a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java index cab0128d..e2949db7 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java @@ -67,7 +67,9 @@ import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; +import android.view.Surface; import android.view.View; +import android.view.WindowManager; import android.webkit.MimeTypeMap; import android.widget.ImageView; import android.widget.TextView; @@ -90,7 +92,7 @@ import static android.content.Context.VIBRATOR_SERVICE; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; import static android.graphics.Bitmap.CompressFormat; -@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "ObsoleteSdkInt", "deprecation", "SpellCheckingInspection", "TryFinallyCanBeTryWithResources", "UnusedAssignment"}) +@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "ObsoleteSdkInt", "deprecation", "SpellCheckingInspection", "TryFinallyCanBeTryWithResources", "UnusedAssignment", "UnusedReturnValue"}) public class ContextUtils { // // Members, Constructors @@ -257,7 +259,7 @@ public class ContextUtils { * Send a {@link Intent#ACTION_VIEW} Intent with given paramter * If the parameter is an string a browser will get triggered */ - public void openWebpageInExternalBrowser(final String url) { + public ContextUtils openWebpageInExternalBrowser(final String url) { try { Uri uri = Uri.parse(url); Intent intent = new Intent(Intent.ACTION_VIEW, uri); @@ -266,6 +268,7 @@ public class ContextUtils { } catch (Exception e) { e.printStackTrace(); } + return this; } /** @@ -1011,6 +1014,25 @@ public class ContextUtils { vibrator.vibrate(ms_v); } } + + /* + Check if Wifi is connected. Requires these permissions in AndroidManifest: + + + */ + @SuppressLint("MissingPermission") + public boolean isWifiConnected(boolean... enabledOnly) { + final boolean doEnabledCheckOnly = enabledOnly != null && enabledOnly.length > 0 && enabledOnly[0]; + final ConnectivityManager connectivityManager = (ConnectivityManager) _context.getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); + final NetworkInfo wifiInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + return wifiInfo != null && (doEnabledCheckOnly ? wifiInfo.isAvailable() : wifiInfo.isConnected()); + } + + // Returns if the device is currently in portrait orientation (landscape=false) + public boolean isDeviceOrientationPortrait() { + final int rotation = ((WindowManager) _context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getOrientation(); + return (rotation == Surface.ROTATION_0) || (rotation == Surface.ROTATION_180); + } } diff --git a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java index 4e96a8ec..22e3da39 100644 --- a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java @@ -501,4 +501,11 @@ public class FileUtils { return String.format(Locale.getDefault(), "%.2f%s", (bytes / 1000000000f), "TB"); } } + + public static File join(File file, String... childSegments) { + for (final String s : childSegments != null ? childSegments : new String[0]) { + file = new File(file, s); + } + return file; + } } diff --git a/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java b/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java index 08e36948..09d6795b 100644 --- a/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java @@ -24,7 +24,6 @@ import java.net.URL; import java.net.URLDecoder; import java.net.URLEncoder; import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -222,4 +221,14 @@ public class NetworkUtils { return result; } + + public static void httpGetAsync(final String url, final Callback.a1 callback) { + new Thread(() -> { + try { + String c = NetworkUtils.performCall(url, GET); + callback.callback(c); + } catch (Exception ignored) { + } + }).start(); + } } From e5866ffb2bf0d879074e7480acfa70ccfafe97df Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Mon, 18 Jan 2021 21:32:50 +0100 Subject: [PATCH 32/49] Update opoc --- .../net/gsantner/opoc/util/ActivityUtils.java | 20 +++++++++++++++++++ .../net/gsantner/opoc/util/ShareUtil.java | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java b/app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java index 41c86e17..08da999a 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java @@ -11,8 +11,10 @@ package net.gsantner.opoc.util; import android.app.Activity; +import android.app.ActivityManager; import android.content.ActivityNotFoundException; import android.content.ComponentName; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; @@ -37,6 +39,8 @@ import android.view.inputmethod.InputMethodManager; import android.webkit.WebView; import android.widget.ScrollView; +import java.util.List; + @SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "SpellCheckingInspection", "rawtypes", "UnusedReturnValue"}) public class ActivityUtils extends net.gsantner.opoc.util.ContextUtils { @@ -324,4 +328,20 @@ public class ActivityUtils extends net.gsantner.opoc.util.ContextUtils { } catch (Exception ignored) { } } + + // Make activity/app not show up in the recents history - call before finish / System.exit + public ActivityUtils removeActivityFromHistory() { + try { + ActivityManager am = (ActivityManager) _activity.getSystemService(Context.ACTIVITY_SERVICE); + if (am != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { + List tasks = am.getAppTasks(); + if (tasks != null && !tasks.isEmpty()) { + tasks.get(0).setExcludeFromRecents(true); + } + } + + } catch (Exception ignored) { + } + return this; + } } diff --git a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java index 9f5b0147..82a2c03a 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java +++ b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java @@ -1148,7 +1148,7 @@ public class ShareUtil { if (isDirectory) { // Nothing to do } else { - pfd = _context.getContentResolver().openFileDescriptor(dof.getUri(), "rw"); + pfd = _context.getContentResolver().openFileDescriptor(dof.getUri(), "rwt"); fileOutputStream = new FileOutputStream(pfd.getFileDescriptor()); } } From c9c10a6fd4eebe5ef89e6267dc95f1ce0e0dd8af Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sun, 28 Feb 2021 22:09:03 +0100 Subject: [PATCH 33/49] Add language Sinhala (Sri Lanka) --- crowdin.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/crowdin.yml b/crowdin.yml index 4dcdc120..592b34ae 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -57,4 +57,5 @@ files: ta: ta # Tamil (Asian) sq: sq # Albanian mk: mk # Macedonian + si-LK: si # Sinhala (Sri Lanka) translate_attributes: 0 From a76a463cd4d93868dbb7c15562a8380a79a686bf Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sat, 13 Mar 2021 14:25:09 +0100 Subject: [PATCH 34/49] Add language Esperanto, by @gsantner --- crowdin.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/crowdin.yml b/crowdin.yml index 592b34ae..4e269b3e 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -58,4 +58,5 @@ files: sq: sq # Albanian mk: mk # Macedonian si-LK: si # Sinhala (Sri Lanka) + eo: eo # Esperanto translate_attributes: 0 From d923630b4217a42d362f304a359e2ce207d2521f Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Wed, 19 May 2021 20:48:50 +0200 Subject: [PATCH 35/49] Update README badges, remove IRC --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4456c0f7..f8856559 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ -[![GitHub release](https://img.shields.io/github/tag/gsantner/dandelion.svg)](https://github.com/gsantner/dandelion/releases) -[![Build Status](https://travis-ci.org/gsantner/dandelion.svg?branch=master)](https://travis-ci.org/gsantner/dandelion) -[![Translate - with Stringlate](https://img.shields.io/badge/stringlate-translate-green.svg)](https://lonamiwebs.github.io/stringlate/translate?git=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion.git&mail=gro.xobliam@@rentnasg) -[![Chat - Matrix](https://img.shields.io/badge/chat-on%20matrix-blue.svg)](https://matrix.to/#/#dandelion:matrix.org) [![Chat - FreeNode IRC](https://img.shields.io/badge/chat-on%20irc-blue.svg)](https://kiwiirc.com/client/irc.freenode.net/?nick=dandelion-anon|?##dandelion) -[![Donate](https://img.shields.io/badge/donate-appreciation-orange.svg)](https://gsantner.net/page/supportme.html?project=dandelion&source=gh_readme) -[![Donate LiberaPay](https://img.shields.io/badge/donate-liberapay-orange.svg)](https://liberapay.com/gsantner/donate) ![](https://r.gsantner.net/matomo/piwik.php?action_name=readme&idsite=2&rec=1&urlref=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FREADME.md&_cvar=%7B%221%22%3A%5B%22source%22%2C%22readme%22%5D%2C%222%22%3A%5B%22project%22%2C%22dandelion%22%5D%2C%223%22%3A%5B%22packageid%22%2C%22com.github.dfa.diaspora_android%22%5D%2C%224%22%3A%5B%22referrer%22%2C%22https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FREADME.md%22%5D%7D) +[![GitHub releases](https://img.shields.io/github/tag/gsantner/dandelion.svg)](https://github.com/gsantner/dandelion/releases) +[![GitHub downloads](https://img.shields.io/github/downloads/gsantner/dandelion/total.svg?logo=github&logoColor=lime)](https://github.com/gsantner/dandelion/releases) +[![Translate on Crowdin](https://img.shields.io/badge/translate-crowdin-green.svg)](https://crowdin.com/project/diaspora-for-android/invite) +[![Donate - say thanks](https://img.shields.io/badge/donate-say%20thanks-red.svg)](https://gsantner.net/page/supportme.html?project=dandelion&source=readme) +[![Chat on Matrix](https://img.shields.io/badge/chat-matrix-blue.svg)](https://matrix.to/#/#dandelion:matrix.org) +[![GitHub CI](https://github.com/gsantner/dandelion/workflows/CI/badge.svg)](https://github.com/gsantner/dandelion/actions) +[![Codacy code quality](https://img.shields.io/codacy/grade/aff869c440bc48b7bd64680e97cbc453)](https://www.codacy.com/app/gsantner/dandelion) # dandelion\* @@ -43,8 +44,7 @@ The project uses [AOSP Java Code Style](https://source.android.com/source/code-s Translations can be contributed on GitHub or via [E-Mail](https://gsantner.net/#contact). You can use Stringlate ([![Translate - with Stringlate](https://img.shields.io/badge/stringlate-translate-green.svg)](https://lonamiwebs.github.io/stringlate/translate?git=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion.git)) to translate the project directly on your Android phone. It allows you to export as E-Mail attachement and to post on GitHub. -Join our IRC or Matrix channel (bridged) and say hello! Don't be afraid to start talking. [![Chat - Matrix](https://img.shields.io/badge/chat-on%20matrix-blue.svg)](https://matrix.to/#/#dandelion:matrix.org) [![Chat - FreeNode IRC](https://img.shields.io/badge/chat-on%20irc-blue.svg)](https://kiwiirc.com/client/irc.freenode.net/?nick=dandelion-anon|?##dandelion) - +Join our Matrix channel and say hello! Don't be afraid to start talking. [![Chat - Matrix](https://img.shields.io/badge/chat-on%20matrix-blue.svg)](https://matrix.to/#/#dandelion:matrix.org) Note that the main project members are working on this project for free during leisure time, are mostly busy with their job/university/school, and may not react or start coding immediately. From 904f2af20a8d572e61aa23849ab915569d362863 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sun, 1 Aug 2021 13:30:21 +0200 Subject: [PATCH 36/49] Update gs/opoc utilities --- app/src/main/AndroidManifest.xml | 5 +- .../com/github/dfa/diaspora_android/App.java | 2 + .../activity/DiasporaStreamFragment.java | 6 +- .../web/ContextMenuWebView.java | 2 +- .../opoc/activity/GsFragmentBase.java | 3 +- .../opoc/android/dummy/MenuItemDummy.java | 351 ++++++++++++++++++ .../opoc/android/dummy/TextWatcherDummy.java | 58 +++ .../SharedPreferencesPropertyBackend.java | 59 ++- .../opoc/ui/SearchOrCustomTextDialog.java | 337 ++++++++--------- .../net/gsantner/opoc/util/ContextUtils.java | 66 ++-- .../net/gsantner/opoc/util/FileUtils.java | 87 +++-- .../net/gsantner/opoc/util/ShareUtil.java | 67 ++-- build.gradle | 4 +- 13 files changed, 737 insertions(+), 310 deletions(-) create mode 100644 app/src/main/java/net/gsantner/opoc/android/dummy/MenuItemDummy.java create mode 100644 app/src/main/java/net/gsantner/opoc/android/dummy/TextWatcherDummy.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ba46503f..2e1a7bd1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -15,6 +15,7 @@ android:allowBackup="false" android:icon="@drawable/ic_launcher" android:label="@string/app_name" + android:requestLegacyExternalStorage="true" android:theme="@style/DiasporaLight"> - @@ -68,6 +70,7 @@ + diff --git a/app/src/main/java/com/github/dfa/diaspora_android/App.java b/app/src/main/java/com/github/dfa/diaspora_android/App.java index 6f5ca2e6..150cb378 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/App.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/App.java @@ -36,6 +36,7 @@ import com.github.dfa.diaspora_android.util.DiasporaUrlHelper; import net.gsantner.opoc.util.AdBlock; import net.gsantner.opoc.util.ContextUtils; +import net.gsantner.opoc.util.ShareUtil; public class App extends Application { private volatile static App app; @@ -51,6 +52,7 @@ public class App extends Application { @Override public void onCreate() { super.onCreate(); + ShareUtil.setFileProviderAuthority(BuildConfig.APPLICATION_ID); app = this; final Context c = getApplicationContext(); appSettings = AppSettings.get(); diff --git a/app/src/main/java/com/github/dfa/diaspora_android/activity/DiasporaStreamFragment.java b/app/src/main/java/com/github/dfa/diaspora_android/activity/DiasporaStreamFragment.java index b583fffe..03517332 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/activity/DiasporaStreamFragment.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/activity/DiasporaStreamFragment.java @@ -128,7 +128,7 @@ public class DiasporaStreamFragment extends BrowserFragment { @Override public boolean onOptionsItemSelected(MenuItem item) { AppLog.d(this, "StreamFragment.onOptionsItemSelected()"); - ShareUtil shu = new ShareUtil(getContext()).setFileProviderAuthority(BuildConfig.APPLICATION_ID); + ShareUtil shu = new ShareUtil(getContext()); PermissionChecker permc = new PermissionChecker(getActivity()); switch (item.getItemId()) { case R.id.action_reload: { @@ -185,7 +185,7 @@ public class DiasporaStreamFragment extends BrowserFragment { if (permc.mkdirIfStoragePermissionGranted(fileSaveDirectory)) { Bitmap bmp = ShareUtil.getBitmapFromWebView(webView); String filename = "dandelion-" + ShareUtil.SDF_SHORT.format(new Date()) + ".jpg"; - _cu.writeImageToFileJpeg(new File(fileSaveDirectory, filename), bmp); + _cu.writeImageToFile(new File(fileSaveDirectory, filename), bmp); Snackbar.make(webView, getString(R.string.saving_screenshot_as) + " " + filename, Snackbar.LENGTH_LONG).show(); } @@ -195,7 +195,7 @@ public class DiasporaStreamFragment extends BrowserFragment { case R.id.action_share_screenshot: { if (permc.doIfExtStoragePermissionGranted(getString(R.string.screenshot_permission__appspecific))) { - shu.shareImage(ShareUtil.getBitmapFromWebView(webView), Bitmap.CompressFormat.JPEG); + shu.shareImage(ShareUtil.getBitmapFromWebView(webView)); } return true; } diff --git a/app/src/main/java/com/github/dfa/diaspora_android/web/ContextMenuWebView.java b/app/src/main/java/com/github/dfa/diaspora_android/web/ContextMenuWebView.java index 277b2caa..e1194c9e 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/web/ContextMenuWebView.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/web/ContextMenuWebView.java @@ -78,7 +78,7 @@ public class ContextMenuWebView extends NestedWebView { public boolean onMenuItemClick(MenuItem item) { HitTestResult result = getHitTestResult(); String url = result.getExtra(); - final ShareUtil shu = new ShareUtil(context).setFileProviderAuthority(BuildConfig.APPLICATION_ID); + final ShareUtil shu = new ShareUtil(context); final PermissionChecker permc = new PermissionChecker(parentActivity); final AppSettings appSettings = new AppSettings(context); diff --git a/app/src/main/java/net/gsantner/opoc/activity/GsFragmentBase.java b/app/src/main/java/net/gsantner/opoc/activity/GsFragmentBase.java index 7dcf0317..efaf4f77 100644 --- a/app/src/main/java/net/gsantner/opoc/activity/GsFragmentBase.java +++ b/app/src/main/java/net/gsantner/opoc/activity/GsFragmentBase.java @@ -24,6 +24,7 @@ import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; +import net.gsantner.opoc.android.dummy.MenuItemDummy; import net.gsantner.opoc.util.ContextUtils; import butterknife.ButterKnife; @@ -37,7 +38,7 @@ public abstract class GsFragmentBase extends Fragment { protected ContextUtils _cu; protected Bundle _savedInstanceState = null; - protected Menu _fragmentMenu; + protected Menu _fragmentMenu = new MenuItemDummy.Menu(); @Override public void onCreate(Bundle savedInstanceState) { diff --git a/app/src/main/java/net/gsantner/opoc/android/dummy/MenuItemDummy.java b/app/src/main/java/net/gsantner/opoc/android/dummy/MenuItemDummy.java new file mode 100644 index 00000000..a222ab07 --- /dev/null +++ b/app/src/main/java/net/gsantner/opoc/android/dummy/MenuItemDummy.java @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2021 Gregor Santner + * License: Creative Commons Zero (CC0 1.0) / Public Domain + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * You can do whatever you want with this. If we meet some day, and you think it is worth it, + * you can buy me a drink in return. Provided as is without any kind of warranty. Do not blame + * or ask for support if something goes wrong. - Gregor Santner + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +package net.gsantner.opoc.android.dummy; + +import android.content.ComponentName; +import android.content.Intent; +import android.graphics.drawable.Drawable; +import android.view.ActionProvider; +import android.view.ContextMenu; +import android.view.KeyEvent; +import android.view.MenuItem; +import android.view.SubMenu; +import android.view.View; + +public class MenuItemDummy implements MenuItem { + private final int _itemId; + + public MenuItemDummy(final int itemId) { + _itemId = itemId; + } + + @Override + public int getItemId() { + return _itemId; + } + + @Override + public int getGroupId() { + return 0; + } + + @Override + public int getOrder() { + return 0; + } + + @Override + public MenuItem setTitle(CharSequence title) { + return null; + } + + @Override + public MenuItem setTitle(int title) { + return null; + } + + @Override + public CharSequence getTitle() { + return null; + } + + @Override + public MenuItem setTitleCondensed(CharSequence title) { + return null; + } + + @Override + public CharSequence getTitleCondensed() { + return null; + } + + @Override + public MenuItem setIcon(Drawable icon) { + return null; + } + + @Override + public MenuItem setIcon(int iconRes) { + return null; + } + + @Override + public Drawable getIcon() { + return null; + } + + @Override + public MenuItem setIntent(Intent intent) { + return null; + } + + @Override + public Intent getIntent() { + return null; + } + + @Override + public MenuItem setShortcut(char numericChar, char alphaChar) { + return null; + } + + @Override + public MenuItem setNumericShortcut(char numericChar) { + return null; + } + + @Override + public char getNumericShortcut() { + return 0; + } + + @Override + public MenuItem setAlphabeticShortcut(char alphaChar) { + return null; + } + + @Override + public char getAlphabeticShortcut() { + return 0; + } + + @Override + public MenuItem setCheckable(boolean checkable) { + return null; + } + + @Override + public boolean isCheckable() { + return false; + } + + @Override + public MenuItem setChecked(boolean checked) { + return null; + } + + @Override + public boolean isChecked() { + return false; + } + + @Override + public MenuItem setVisible(boolean visible) { + return null; + } + + @Override + public boolean isVisible() { + return false; + } + + @Override + public MenuItem setEnabled(boolean enabled) { + return null; + } + + @Override + public boolean isEnabled() { + return false; + } + + @Override + public boolean hasSubMenu() { + return false; + } + + @Override + public SubMenu getSubMenu() { + return null; + } + + @Override + public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) { + return null; + } + + @Override + public ContextMenu.ContextMenuInfo getMenuInfo() { + return null; + } + + @Override + public void setShowAsAction(int actionEnum) { + } + + @Override + public MenuItem setShowAsActionFlags(int actionEnum) { + return null; + } + + @Override + public MenuItem setActionView(View view) { + return null; + } + + @Override + public MenuItem setActionView(int resId) { + return null; + } + + @Override + public View getActionView() { + return null; + } + + @Override + public MenuItem setActionProvider(ActionProvider actionProvider) { + return null; + } + + @Override + public ActionProvider getActionProvider() { + return null; + } + + @Override + public boolean expandActionView() { + return false; + } + + @Override + public boolean collapseActionView() { + return false; + } + + @Override + public boolean isActionViewExpanded() { + return false; + } + + @Override + public MenuItem setOnActionExpandListener(OnActionExpandListener listener) { + return null; + } + + + public static class Menu implements android.view.Menu { + @Override + public MenuItem add(CharSequence title) { + return add(0, 0, 0, ""); + } + + @Override + public MenuItem add(int titleRes) { + return add(0, 0, 0, ""); + } + + @Override + public MenuItem add(int groupId, int itemId, int order, CharSequence title) { + return new MenuItemDummy(itemId); + } + + @Override + public MenuItem add(int groupId, int itemId, int order, int titleRes) { + return add(0, 0, 0, ""); + } + + @Override + public SubMenu addSubMenu(CharSequence title) { + return null; + } + + @Override + public SubMenu addSubMenu(int titleRes) { + return null; + } + + @Override + public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) { + return null; + } + + @Override + public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) { + return null; + } + + @Override + public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller, Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) { + return 0; + } + + @Override + public void removeItem(int id) { + } + + @Override + public void removeGroup(int groupId) { + } + + @Override + public void clear() { + } + + @Override + public void setGroupCheckable(int group, boolean checkable, boolean exclusive) { + } + + @Override + public void setGroupVisible(int group, boolean visible) { + } + + @Override + public void setGroupEnabled(int group, boolean enabled) { + } + + @Override + public boolean hasVisibleItems() { + return false; + } + + @Override + public MenuItem findItem(int id) { + return null; + } + + @Override + public int size() { + return 0; + } + + @Override + public MenuItem getItem(int index) { + return null; + } + + @Override + public void close() { + } + + @Override + public boolean performShortcut(int keyCode, KeyEvent event, int flags) { + return false; + } + + @Override + public boolean isShortcutKey(int keyCode, KeyEvent event) { + return false; + } + + @Override + public boolean performIdentifierAction(int id, int flags) { + return false; + } + + @Override + public void setQwertyMode(boolean isQwerty) { + } + } +} diff --git a/app/src/main/java/net/gsantner/opoc/android/dummy/TextWatcherDummy.java b/app/src/main/java/net/gsantner/opoc/android/dummy/TextWatcherDummy.java new file mode 100644 index 00000000..a21bf1f3 --- /dev/null +++ b/app/src/main/java/net/gsantner/opoc/android/dummy/TextWatcherDummy.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 Gregor Santner + * License: Creative Commons Zero (CC0 1.0) / Public Domain + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * You can do whatever you want with this. If we meet some day, and you think it is worth it, + * you can buy me a drink in return. Provided as is without any kind of warranty. Do not blame + * or ask for support if something goes wrong. - Gregor Santner + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ +package net.gsantner.opoc.android.dummy; + +import android.text.Editable; +import android.text.TextWatcher; + +import net.gsantner.opoc.util.Callback; + +@SuppressWarnings({"unused", "SpellCheckingInspection"}) +public class TextWatcherDummy implements TextWatcher { + @Override + public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) { + } + + @Override + public void onTextChanged(final CharSequence s, final int start, final int before, final int count) { + } + + @Override + public void afterTextChanged(final Editable s) { + } + + public static TextWatcher before(final Callback.a4 impl) { + return new TextWatcherDummy() { + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + impl.callback(s, start, count, after); + } + }; + } + + public static TextWatcher on(final Callback.a4 impl) { + return new TextWatcherDummy() { + public void onTextChanged(final CharSequence s, final int start, final int before, final int count) { + impl.callback(s, start, before, count); + } + }; + } + + public static TextWatcher after(final Callback.a1 impl) { + return new TextWatcherDummy() { + public void afterTextChanged(final Editable s) { + impl.callback(s); + } + }; + } +} diff --git a/app/src/main/java/net/gsantner/opoc/preference/SharedPreferencesPropertyBackend.java b/app/src/main/java/net/gsantner/opoc/preference/SharedPreferencesPropertyBackend.java index 6950e522..64e7596c 100644 --- a/app/src/main/java/net/gsantner/opoc/preference/SharedPreferencesPropertyBackend.java +++ b/app/src/main/java/net/gsantner/opoc/preference/SharedPreferencesPropertyBackend.java @@ -42,6 +42,7 @@ import android.support.annotation.StringRes; import android.support.v4.content.ContextCompat; import android.text.TextUtils; +import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -201,11 +202,15 @@ public class SharedPreferencesPropertyBackend implements PropertyBackend values, final SharedPreferences pref) { @@ -219,9 +224,7 @@ public class SharedPreferencesPropertyBackend implements PropertyBackend getStringListOne(String key, final SharedPreferences pref) { ArrayList ret = new ArrayList<>(); - String value = pref - .getString(key, ARRAY_SEPARATOR) - .replace(ARRAY_SEPARATOR_SUBSTITUTE, ARRAY_SEPARATOR); + String value = getString(key, ARRAY_SEPARATOR).replace(ARRAY_SEPARATOR_SUBSTITUTE, ARRAY_SEPARATOR); if (value.equals(ARRAY_SEPARATOR) || TextUtils.isEmpty(value)) { return ret; } @@ -277,11 +280,15 @@ public class SharedPreferencesPropertyBackend implements PropertyBackend getIntListOne(String key, final SharedPreferences pref) { ArrayList ret = new ArrayList<>(); - String value = pref.getString(key, ARRAY_SEPARATOR); + String value = getString(key, ARRAY_SEPARATOR); if (value.equals(ARRAY_SEPARATOR)) { return ret; } @@ -361,11 +368,15 @@ public class SharedPreferencesPropertyBackend implements PropertyBackend callback; - public Callback.a2 withPositionCallback; - public List data; - public List highlightData; + + // Callback for search text or text of single item + @Nullable + public Callback.a1 callback = null; + + // Callback for indices of selected items. + // List will contain single item if isMultiSelectEnabled == false; + @Nullable + public Callback.a1> positionCallback = null; + + public boolean isMultiSelectEnabled = false; + public List data = null; + public List highlightData = null; public List iconsForData; public String messageText = ""; public String defaultText = ""; @@ -78,8 +86,9 @@ public class SearchOrCustomTextDialog { public int gravity = Gravity.NO_GRAVITY; public int searchInputType = InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS; public boolean searchIsRegex = false; - public Callback.a1 highlighter; + public Callback.a1 highlighter = null; public String extraFilter = null; + public List preSelected = null; public Callback.a0 neutralButtonCallback = null; @@ -97,41 +106,57 @@ public class SearchOrCustomTextDialog { public int titleText = 0; @StringRes public int searchHintText = android.R.string.search_go; + @DrawableRes + public int clearInputIcon = android.R.drawable.ic_input_delete; } - private static class WithPositionAdapter extends ArrayAdapter> { + private static class Adapter extends ArrayAdapter { @LayoutRes - final int _layout; - final LayoutInflater _inflater; - final DialogOptions _dopt; - final List> _filteredItems; - final Pattern _extraPattern; + private final int _layout; + private final int _layoutHeight; + private final LayoutInflater _inflater; + private final DialogOptions _dopt; + private final List _filteredItems; + private final Set _selectedItems; + private final Pattern _extraPattern; - WithPositionAdapter(Context c_context, @LayoutRes int c_layout, List> c_filteredItems, DialogOptions c_dopt) { - super(c_context, c_layout, c_filteredItems); - _inflater = LayoutInflater.from(c_context); - _layout = c_layout; - _dopt = c_dopt; - _filteredItems = c_filteredItems; - _extraPattern = (c_dopt.extraFilter == null ? null : Pattern.compile(c_dopt.extraFilter)); + public static Adapter create(final Context context, final DialogOptions dopt) { + return new Adapter(context, dopt, dopt.isMultiSelectEnabled ? android.R.layout.simple_list_item_multiple_choice : android.R.layout.simple_list_item_1, new ArrayList<>()); + } + + private Adapter(final Context context, final DialogOptions dopt, final int layout, final List filteredItems) { + super(context, layout, filteredItems); + _layout = layout; + _filteredItems = filteredItems; + _inflater = LayoutInflater.from(context); + _dopt = dopt; + _extraPattern = (_dopt.extraFilter == null ? null : Pattern.compile(_dopt.extraFilter)); + _selectedItems = new HashSet<>(_dopt.preSelected != null ? _dopt.preSelected : Collections.emptyList()); + ContextUtils cu = new ContextUtils(context); + _layoutHeight = (int) cu.convertDpToPx(36); + cu.freeContextRef(); } @NonNull @Override public View getView(int pos, @Nullable View convertView, @NonNull ViewGroup parent) { - final Pair item = getItem(pos); - final String text = item.first; - final int posInOriginalList = item.second; + final int index = getItem(pos); final TextView textView; if (convertView == null) { textView = (TextView) _inflater.inflate(_layout, parent, false); + textView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT)); + textView.setMinHeight(_layoutHeight); } else { textView = (TextView) convertView; } - if (posInOriginalList >= 0 && _dopt.iconsForData != null && posInOriginalList < _dopt.iconsForData.size() && _dopt.iconsForData.get(posInOriginalList) != 0) { - textView.setCompoundDrawablesWithIntrinsicBounds(_dopt.iconsForData.get(posInOriginalList), 0, 0, 0); + if (textView instanceof Checkable) { + ((Checkable) textView).setChecked(_selectedItems.contains(index)); + } + + if (index >= 0 && _dopt.iconsForData != null && index < _dopt.iconsForData.size() && _dopt.iconsForData.get(index) != 0) { + textView.setCompoundDrawablesWithIntrinsicBounds(_dopt.iconsForData.get(index), 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)); @@ -140,6 +165,7 @@ public class SearchOrCustomTextDialog { textView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); } + final CharSequence text = _dopt.data.get(index).toString(); if (_dopt.highlightData != null) { final boolean hl = _dopt.highlightData.contains(text); textView.setTextColor(hl ? _dopt.highlightColor : _dopt.textColor); @@ -157,6 +183,7 @@ public class SearchOrCustomTextDialog { return textView; } + @NonNull @Override public Filter getFilter() { return new Filter() { @@ -164,24 +191,25 @@ public class SearchOrCustomTextDialog { @Override protected void publishResults(final CharSequence constraint, final FilterResults results) { _filteredItems.clear(); - _filteredItems.addAll((List>) results.values); + _filteredItems.addAll((List) results.values); notifyDataSetChanged(); } @Override protected FilterResults performFiltering(final CharSequence constraint) { - final ArrayList> resList = new ArrayList<>(); + final List 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 String str = _dopt.data.get(i).toString(); 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)); + final Locale locale = Locale.getDefault(); + final boolean matchNormal = str.toLowerCase(locale).contains(fil.toLowerCase(locale)); + final boolean matchRegex = _dopt.searchIsRegex && (str.matches(fil)); if (matchExtra && (matchNormal || matchRegex || emptySearch)) { - resList.add(new Pair<>(str, i)); + resList.add(i); } } } @@ -196,12 +224,11 @@ public class SearchOrCustomTextDialog { } public static void showMultiChoiceDialogWithSearchFilterUI(final Activity activity, final DialogOptions dopt) { - final List> 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 Adapter listAdapter = Adapter.create(activity, dopt); final AppCompatEditText searchEditText = new AppCompatEditText(activity); searchEditText.setText(dopt.defaultText); @@ -211,21 +238,30 @@ public class SearchOrCustomTextDialog { searchEditText.setHintTextColor((dopt.textColor & 0x00FFFFFF) | 0x99000000); searchEditText.setHint(dopt.searchHintText); searchEditText.setInputType(dopt.searchInputType == 0 ? searchEditText.getInputType() : dopt.searchInputType); + searchEditText.addTextChangedListener(TextWatcherDummy.after((cbEditable) -> listAdapter.getFilter().filter(cbEditable))); - searchEditText.addTextChangedListener(new TextWatcher() { - @Override - public void afterTextChanged(final Editable arg0) { - listAdapter.getFilter().filter(searchEditText.getText()); - } + final ContextUtils cu = new ContextUtils(activity); + final int margin = (int) cu.convertDpToPx(8); + cu.freeContextRef(); - @Override - public void onTextChanged(final CharSequence arg0, final int arg1, final int arg2, final int arg3) { - } + final LinearLayout searchLayout = new LinearLayout(activity); + searchLayout.setOrientation(LinearLayout.HORIZONTAL); - @Override - public void beforeTextChanged(final CharSequence arg0, final int arg1, final int arg2, final int arg3) { - } - }); + LinearLayout.LayoutParams lp; + lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT, 1); + lp.gravity = Gravity.START | Gravity.BOTTOM; + searchLayout.addView(searchEditText, lp); + + // 'Button to clear the search box' + final ImageView clearButton = new ImageView(activity); + clearButton.setImageResource(dopt.clearInputIcon); + TooltipCompat.setTooltipText(clearButton, activity.getString(android.R.string.cancel)); + clearButton.setColorFilter(dopt.isDarkDialog ? Color.WHITE : Color.parseColor("#ff505050")); + lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT, 0); + lp.gravity = Gravity.END | Gravity.CENTER_VERTICAL; + lp.setMargins(margin, 0, (int) (margin * 1.5), 0); + searchLayout.addView(clearButton, lp); + clearButton.setOnClickListener((v) -> searchEditText.setText("")); final ListView listView = new ListView(activity); final LinearLayout linearLayout = new LinearLayout(activity); @@ -234,10 +270,9 @@ public class SearchOrCustomTextDialog { linearLayout.setOrientation(LinearLayout.VERTICAL); if (dopt.isSearchEnabled) { - LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); - int px = (int) (new ContextUtils(listView.getContext()).convertDpToPx(8)); - lp.setMargins(px, px / 2, px, px / 2); - linearLayout.addView(searchEditText, lp); + lp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); + lp.setMargins(margin, margin / 2, margin, margin / 2); + linearLayout.addView(searchLayout, lp); } final LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, 0); @@ -251,36 +286,32 @@ public class SearchOrCustomTextDialog { .setOnCancelListener(null) .setNegativeButton(dopt.cancelButtonText, (dialogInterface, i) -> dialogInterface.dismiss()); + if (dopt.titleText != 0) { + dialogBuilder.setTitle(dopt.titleText); + } + + // Ok button action + if ((dopt.isSearchEnabled && dopt.callback != null) || (dopt.isMultiSelectEnabled)) { + dialogBuilder.setPositiveButton(dopt.okButtonText, (dialogInterface, i) -> { + final String searchText = dopt.isSearchEnabled ? searchEditText.getText().toString() : null; + if (dopt.positionCallback != null && !listAdapter._selectedItems.isEmpty()) { + final List sel = new ArrayList<>(listAdapter._selectedItems); + Collections.sort(sel); + dopt.positionCallback.callback(sel); + } else if (dopt.callback != null && !TextUtils.isEmpty(searchText)) { + dopt.callback.callback(searchText); + } + }); + } + + // Setup neutralbutton if (dopt.neutralButtonCallback != null && dopt.neutralButtonText != 0) { dialogBuilder.setNeutralButton(dopt.neutralButtonText, (dialogInterface, i) -> { dopt.neutralButtonCallback.callback(); }); } - if (dopt.titleText != 0) { - dialogBuilder.setTitle(dopt.titleText); - } - - if (dopt.isSearchEnabled) { - dialogBuilder.setPositiveButton(dopt.okButtonText, (dialogInterface, i) -> { - dialogInterface.dismiss(); - if (dopt.callback != null && !TextUtils.isEmpty(searchEditText.getText().toString())) { - dopt.callback.callback(searchEditText.getText().toString()); - } - }); - } - final AlertDialog dialog = dialogBuilder.create(); - listView.setOnItemClickListener((parent, view, position, id) -> { - dialog.dismiss(); - if (dopt.callback != null) { - dopt.callback.callback(filteredItems.get(position).first); - } - if (dopt.withPositionCallback != null) { - final Pair item = filteredItems.get(position); - dopt.withPositionCallback.callback(item.first, item.second); - } - }); searchEditText.setOnKeyListener((keyView, keyCode, keyEvent) -> { if ((keyEvent.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { @@ -316,117 +347,49 @@ public class SearchOrCustomTextDialog { if (dopt.defaultText != null) { listAdapter.getFilter().filter(searchEditText.getText()); } - } + // Helper function to trigger callback with single item + final Callback.b1 directActivate = (position) -> { + final int index = listAdapter._filteredItems.get(position); + dialog.dismiss(); + if (dopt.callback != null) { + dopt.callback.callback(dopt.data.get(index).toString()); + } + if (dopt.positionCallback != null) { + dopt.positionCallback.callback(Collections.singletonList(index)); + } + return true; + }; - public static SearchFilesTask recursiveFileSearch(Activity activity, File searchDir, String query, Callback.a1> callback) { - query = query.replaceAll("(? { + okButton.setText(okText.replace("%d", Integer.toString(listAdapter._selectedItems.size()))); + }; - public static class SearchFilesTask extends AsyncTask> implements IOFileFilter { - private final Callback.a1> _callback; - private final File _searchDir; - private final String _query; - private final boolean _isRegex; - private final WeakReference _activityRef; + // Set ok button text initially + setOkButtonState.callback(); - private final Pattern _regex; - private Snackbar _snackBar; - - public SearchFilesTask(Activity activity, File searchDir, String query, Callback.a1> callback, boolean isRegex) { - _searchDir = searchDir; - _query = isRegex ? query : query.toLowerCase(); - _callback = callback; - _isRegex = isRegex; - _regex = isRegex ? Pattern.compile(_query) : null; - _activityRef = new WeakReference<>(activity); - } - - // Called for both, file and folder filter - @Override - public boolean accept(File file) { - return isMatching(file, true); - } - - // Not called - @Override - public boolean accept(File dir, String name) { - return isMatching(new File(dir, name), true); - } - - // In iterateFilesAndDirs, subdirs are only scanned when returning true on it - // But those dirs will also occur in iterator - // Hence call this aagain with alwaysMatchDir=false - public boolean isMatching(File file, boolean alwaysMatchDir) { - if (file.isDirectory()) { - // Do never scan .git directories, lots of files, lots of time - if (file.getName().equals(".git")) { - return false; + // Item click action + listView.setOnItemClickListener((parent, textView, pos, id) -> { + if (dopt.isMultiSelectEnabled) { + final int index = listAdapter._filteredItems.get(pos); + if (listAdapter._selectedItems.contains(index)) { + listAdapter._selectedItems.remove(index); + } else { + listAdapter._selectedItems.add(index); } - if (alwaysMatchDir) { - return true; + if (textView instanceof Checkable) { + ((Checkable) textView).setChecked(listAdapter._selectedItems.contains(index)); } + setOkButtonState.callback(); + } else { + directActivate.callback(pos); } - String name = file.getName(); - file = file.getParentFile(); - return _isRegex ? _regex.matcher(name).matches() : name.toLowerCase().contains(_query); - } + }); - @Override - protected void onPreExecute() { - super.onPreExecute(); - if (_activityRef.get() != null) { - _snackBar = Snackbar.make(_activityRef.get().findViewById(android.R.id.content), _query + "...", Snackbar.LENGTH_INDEFINITE); - _snackBar.setAction(android.R.string.cancel, (v) -> { - _snackBar.dismiss(); - cancel(true); - }).show(); - } - } - - @Override - protected List doInBackground(Void... voidp) { - List ret = new ArrayList<>(); - - boolean first = true; - Iterator iter = null; - try { - iter = FileUtils.iterateFilesAndDirs(_searchDir, this, this); - } catch (Exception ex) { - // Iterator may throw an error at creation - return ret; - } - while (iter.hasNext() && !isCancelled()) { - File f = iter.next(); - if (first) { - first = false; - if (f.equals(_searchDir)) { - continue; - } - } - if (f.isFile() || (f.isDirectory() && isMatching(f, false))) { - ret.add(f.getAbsolutePath().replace(_searchDir.getAbsolutePath() + "/", "")); - } - } - return ret; - } - - @Override - protected void onPostExecute(List ret) { - super.onPostExecute(ret); - if (_snackBar != null) { - _snackBar.dismiss(); - } - if (_callback != null) { - try { - _callback.callback(ret); - } catch (Exception ignored) { - } - } - new ActivityUtils(_activityRef.get()).hideSoftKeyboard().freeContextRef(); - } + // long click always activates + listView.setOnItemLongClickListener((parent, view, pos, id) -> directActivate.callback(pos)); } } diff --git a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java index e2949db7..58bc8009 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java @@ -78,10 +78,10 @@ import net.gsantner.opoc.format.markdown.SimpleMarkdownParser; 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.lang.reflect.Field; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -146,11 +146,11 @@ public class ContextUtils { /** * Get String by given string ressource identifier (textual) */ - public String rstr(final String strResKey) { + public String rstr(final String strResKey, Object... a0getResKeyAsFallback) { try { return rstr(getResId(ResType.STRING, strResKey)); } catch (Resources.NotFoundException e) { - return null; + return a0getResKeyAsFallback != null && a0getResKeyAsFallback.length > 0 ? strResKey : null; } } @@ -295,14 +295,27 @@ public class ContextUtils { * Falls back to applicationId of the app which may differ from manifest. */ public Object getBuildConfigValue(final String fieldName) { - String pkg = getPackageIdManifest() + ".BuildConfig"; + final String pkg = getPackageIdManifest() + ".BuildConfig"; try { Class c = Class.forName(pkg); return c.getField(fieldName).get(null); } catch (Exception e) { e.printStackTrace(); - return null; } + return null; + } + + public List getBuildConfigFields() { + final String pkg = getPackageIdManifest() + ".BuildConfig"; + final List fields = new ArrayList<>(); + try { + for (Field f : Class.forName(pkg).getFields()) { + fields.add(f.getName()); + } + } catch (Exception e) { + e.printStackTrace(); + } + return fields; } /** @@ -745,44 +758,27 @@ public class ContextUtils { return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); } - /** - * Write the given {@link Bitmap} to {@code imageFile}, in {@link CompressFormat#JPEG} format - */ - public boolean writeImageToFileJpeg(final File imageFile, final Bitmap image) { - return writeImageToFile(imageFile, image, Bitmap.CompressFormat.JPEG, 95); - } - /** * Write the given {@link Bitmap} to filesystem * * @param targetFile The file to be written in - * @param image The image as android {@link Bitmap} - * @param format One format of {@link CompressFormat}, null will determine based on filename - * @param quality Quality level, defaults to 95 + * @param image Android {@link Bitmap} * @return True if writing was successful */ - public boolean writeImageToFile(final File targetFile, final Bitmap image, CompressFormat format, Integer quality) { + public boolean writeImageToFile(final File targetFile, final Bitmap image, Integer... a0quality) { + final int quality = (a0quality != null && a0quality.length > 0 && a0quality[0] >= 0 && a0quality[0] <= 100) ? a0quality[0] : 70; + final String lc = targetFile.getAbsolutePath().toLowerCase(Locale.ROOT); + final CompressFormat format = lc.endsWith(".webp") ? CompressFormat.WEBP : (lc.endsWith(".png") ? CompressFormat.PNG : CompressFormat.JPEG); + + boolean ok = false; File folder = new File(targetFile.getParent()); - if (quality == null || quality < 0 || quality > 100) { - quality = 95; - } - if (format == null) { - format = CompressFormat.JPEG; - String lc = targetFile.getAbsolutePath().toLowerCase(Locale.ROOT); - if (lc.endsWith(".png")) { - format = CompressFormat.PNG; - } - if (lc.endsWith(".webp")) { - format = CompressFormat.WEBP; - } - } if (folder.exists() || folder.mkdirs()) { FileOutputStream stream = null; try { - stream = new FileOutputStream(targetFile); // overwrites this image every time + stream = new FileOutputStream(targetFile); image.compress(format, quality, stream); - return true; - } catch (FileNotFoundException ignored) { + ok = true; + } catch (Exception ignored) { } finally { try { if (stream != null) { @@ -792,7 +788,11 @@ public class ContextUtils { } } } - return false; + try { + image.recycle(); + } catch (Exception ignored) { + } + return ok; } /** diff --git a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java index 22e3da39..130021ea 100644 --- a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java @@ -11,6 +11,8 @@ package net.gsantner.opoc.util; +import android.text.TextUtils; + import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; @@ -37,7 +39,7 @@ import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Pattern; -@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "SpellCheckingInspection", "deprecation"}) +@SuppressWarnings({"WeakerAccess", "unused", "SameParameterValue", "SpellCheckingInspection", "deprecation", "TryFinallyCanBeTryWithResources"}) public class FileUtils { // Used on methods like copyFile(src, dst) private static final int BUFFER_SIZE = 4096; @@ -391,45 +393,58 @@ public class FileUtils { */ public static String getMimeType(File file) { String guess = null; - if (file != null && file.exists() && file.isFile()) { - InputStream is = null; - try { - is = new BufferedInputStream(new FileInputStream(file)); - guess = URLConnection.guessContentTypeFromStream(is); - } catch (IOException e) { - e.printStackTrace(); - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException ignored) { + if (file != null) { + if (file.exists() && file.isFile()) { + InputStream is = null; + try { + is = new BufferedInputStream(new FileInputStream(file)); + guess = URLConnection.guessContentTypeFromStream(is); + } catch (Exception ignored) { + } finally { + if (is != null) { + try { + is.close(); + } catch (Exception ignored) { + } } } } - if (guess == null || guess.isEmpty()) { - guess = "*/*"; - String filename = file.getName().replace(".jenc", ""); - int dot = filename.lastIndexOf(".") + 1; - if (dot > 0 && dot < filename.length()) { - switch (filename.substring(dot)) { - case "md": - case "markdown": - case "mkd": - case "mdown": - case "mkdn": - case "mdwn": - case "rmd": - guess = "text/markdown"; - break; - case "txt": - guess = "text/plain"; - break; - } + String filename = file.getName().replace(".jenc", ""); + int dot = filename.lastIndexOf(".") + 1; + if (dot > 0 && dot < filename.length()) { + switch (filename.substring(dot)) { + case "md": + case "markdown": + case "mkd": + case "mdown": + case "mkdn": + case "mdwn": + case "rmd": + guess = "text/markdown"; + break; + case "txt": + guess = "text/plain"; + break; + case "webp": + guess = "image/webp"; + break; + case "jpg": + case "jpeg": + guess = "image/jpeg"; + break; + case "png": + guess = "image/png"; + break; } } + + if (TextUtils.isEmpty(guess)) { + guess = URLConnection.guessContentTypeFromName(filename); + } } - return guess; + + return TextUtils.isEmpty(guess) ? "*/*" : guess; } public static boolean isTextFile(File file) { @@ -496,9 +511,11 @@ public class FileUtils { } 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"); + return String.format(Locale.getDefault(), "%.2f%s", (bytes / 1000000f), "MB"); + } else if (bytes < 1000000000000L) { + return String.format(Locale.getDefault(), "%.2f%s", (bytes / 1000000000f), "GB"); } else { - return String.format(Locale.getDefault(), "%.2f%s", (bytes / 1000000000f), "TB"); + return String.format(Locale.getDefault(), "%.2f%s", (bytes / 1000000000000f), "TB"); } } diff --git a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java index 82a2c03a..01bbd468 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java +++ b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java @@ -83,6 +83,7 @@ public class ShareUtil { public final static String EXTRA_FILEPATH = "real_file_path_2"; public final static SimpleDateFormat SDF_RFC3339_ISH = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss", Locale.getDefault()); public final static SimpleDateFormat SDF_SHORT = new SimpleDateFormat("yyMMdd-HHmmss", Locale.getDefault()); + public final static SimpleDateFormat SDF_IMAGES = new SimpleDateFormat("yyyyMMdd-HHmmss", Locale.getDefault()); //20190511-230845 public final static String MIME_TEXT_PLAIN = "text/plain"; public final static String PREF_KEY__SAF_TREE_URI = "pref_key__saf_tree_uri"; @@ -93,9 +94,9 @@ public class ShareUtil { public final static int MIN_OVERWRITE_LENGTH = 5; protected static String _lastCameraPictureFilepath; + protected static String _fileProviderAuthority; protected Context _context; - protected String _fileProviderAuthority; protected String _chooserTitle; public ShareUtil(final Context context) { @@ -118,9 +119,8 @@ public class ShareUtil { return _fileProviderAuthority; } - public ShareUtil setFileProviderAuthority(final String fileProviderAuthority) { + public static void setFileProviderAuthority(final String fileProviderAuthority) { _fileProviderAuthority = fileProviderAuthority; - return this; } @@ -230,9 +230,9 @@ public class ShareUtil { intent.putExtra(Intent.EXTRA_STREAM, fileUri); showChooser(intent, null); return true; - } catch (Exception e) { // FileUriExposed(API24) / IllegalArgument - return false; + } catch (Exception ignored) { // FileUriExposed(API24) / IllegalArgument } + return false; } /** @@ -320,17 +320,6 @@ public class ShareUtil { return false; } - /** - * Share the given bitmap with given format - * - * @param bitmap Image - * @param format A {@link Bitmap.CompressFormat}, supporting JPEG,PNG,WEBP - * @return if success, true - */ - public boolean shareImage(final Bitmap bitmap, final Bitmap.CompressFormat format) { - return shareImage(bitmap, format, 95, "SharedImage"); - } - /** * Share the given bitmap with given format * @@ -340,20 +329,36 @@ public class ShareUtil { * @param quality Quality of the exported image [0-100] * @return if success, true */ - public boolean shareImage(final Bitmap bitmap, final Bitmap.CompressFormat format, final int quality, final String imageName) { + public boolean shareImage(final Bitmap bitmap, final Integer... quality) { try { - String ext = format.name().toLowerCase(); - File file = File.createTempFile(imageName, "." + ext.replace("jpeg", "jpg"), _context.getExternalCacheDir()); - if (bitmap != null && new ContextUtils(_context).writeImageToFile(file, bitmap, format, quality)) { - shareStream(file, "image/" + ext); + File file = new File(_context.getCacheDir(), getFilenameWithTimestamp()); + if (bitmap != null && new ContextUtils(_context).writeImageToFile(file, bitmap, quality)) { + String x = FileUtils.getMimeType(file); + shareStream(file, FileUtils.getMimeType(file)); return true; } - } catch (IOException e) { - e.printStackTrace(); + } catch (Exception ignored) { } return false; } + /** + * Generate a filename based off current datetime in filename (year, month, day, hour, minute, second) + * Examples: Screenshot_20210208-184301_Trebuchet.png IMG_20190511-230845.jpg + * + * @param A0prefixA1postfixA2ext All arguments are optional and default values are taken for null + * [0] = Prefix [Screenshot/IMG] + * [1] = Postfix [Trebuchet] + * [2] = File extensions [jpg/png/txt] + * @return Filename + */ + public static String getFilenameWithTimestamp(String... A0prefixA1postfixA2ext) { + final String prefix = (((A0prefixA1postfixA2ext != null && A0prefixA1postfixA2ext.length > 0 && !TextUtils.isEmpty(A0prefixA1postfixA2ext[0])) ? A0prefixA1postfixA2ext[0] : "Screenshot") + "_").trim().replaceFirst("^_$", ""); + final String postfix = ("_" + ((A0prefixA1postfixA2ext != null && A0prefixA1postfixA2ext.length > 1 && !TextUtils.isEmpty(A0prefixA1postfixA2ext[1])) ? A0prefixA1postfixA2ext[1] : "")).trim().replaceFirst("^_$", ""); + final String ext = (A0prefixA1postfixA2ext != null && A0prefixA1postfixA2ext.length > 2 && !TextUtils.isEmpty(A0prefixA1postfixA2ext[2])) ? A0prefixA1postfixA2ext[2] : "jpg"; + return String.format("%s%s%s.%s", prefix.trim(), SDF_IMAGES.format(new Date()), postfix.trim(), ext.toLowerCase().replace(".", "").replace("jpeg", "jpg")); + } + /** * Print a {@link WebView}'s contents, also allows to create a PDF * @@ -405,21 +410,21 @@ public class ShareUtil { * @return A {@link Bitmap} or null */ @Nullable - public static Bitmap getBitmapFromWebView(final WebView webView) { + public static Bitmap getBitmapFromWebView(final WebView webView, final boolean... a0fullpage) { try { //Measure WebView's content - int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); - int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); - webView.measure(widthMeasureSpec, heightMeasureSpec); - webView.layout(0, 0, webView.getMeasuredWidth(), webView.getMeasuredHeight()); + if (a0fullpage != null && a0fullpage.length > 0 && a0fullpage[0]) { + int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); + webView.measure(widthMeasureSpec, heightMeasureSpec); + webView.layout(0, 0, webView.getMeasuredWidth(), webView.getMeasuredHeight()); + } //Build drawing cache and store its size webView.buildDrawingCache(); - int measuredWidth = webView.getMeasuredWidth(); - int measuredHeight = webView.getMeasuredHeight(); //Creates the bitmap and draw WebView's content on in - Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888); + Bitmap bitmap = Bitmap.createBitmap(webView.getMeasuredWidth(), webView.getMeasuredHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.drawBitmap(bitmap, 0, bitmap.getHeight(), new Paint()); diff --git a/build.gradle b/build.gradle index 0ecd8134..d4722bf0 100644 --- a/build.gradle +++ b/build.gradle @@ -17,8 +17,8 @@ buildscript { version_plugin_kotlin = "1.3.72" enable_plugin_kotlin = false - version_compileSdk = 28 - version_buildTools = "28.0.3" + version_compileSdk = 29 + version_buildTools = "29.0.3" version_minSdk = 17 // https://developer.android.com/topic/libraries/support-library/ From 0cf003ea386959fe0f59ca96181264ca76e26c7e Mon Sep 17 00:00:00 2001 From: James Addison Date: Sun, 1 Aug 2021 12:38:59 +0100 Subject: [PATCH 37/49] Update README screenshot references (PR #291) --- README.md | 18 +++++++++--------- SCREENSHOTS.md | 16 ---------------- 2 files changed, 9 insertions(+), 25 deletions(-) delete mode 100644 SCREENSHOTS.md diff --git a/README.md b/README.md index f8856559..74db9a84 100644 --- a/README.md +++ b/README.md @@ -62,18 +62,18 @@ For more licensing informations, see [`3rd party licenses`](/app/src/main/res/ra ## Screenshots
- - - - - + + + + +
- - - - + + + +
### Notice diff --git a/SCREENSHOTS.md b/SCREENSHOTS.md deleted file mode 100644 index 9403120d..00000000 --- a/SCREENSHOTS.md +++ /dev/null @@ -1,16 +0,0 @@ -## Screenshots - -
- - - - - -
- -
- - - - -
From ceb0002546ee63231d2d55cca30864408457f0c1 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sun, 1 Aug 2021 14:12:03 +0200 Subject: [PATCH 38/49] Update translations (PR #286) --- app/src/main/res/values-eo/strings.xml | 24 ++++++++++++++ app/src/main/res/values-si/strings.xml | 46 ++++++++++++++++++++++++++ app/src/main/res/values-sv/strings.xml | 4 +-- 3 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 app/src/main/res/values-eo/strings.xml create mode 100644 app/src/main/res/values-si/strings.xml diff --git a/app/src/main/res/values-eo/strings.xml b/app/src/main/res/values-eo/strings.xml new file mode 100644 index 00000000..43d88f4b --- /dev/null +++ b/app/src/main/res/values-eo/strings.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-si/strings.xml b/app/src/main/res/values-si/strings.xml new file mode 100644 index 00000000..1f38d92a --- /dev/null +++ b/app/src/main/res/values-si/strings.xml @@ -0,0 +1,46 @@ + + + + වසන්න + අවලංගු + + සැකසුම් + දැනුම්දීම් + සංවාද + පැතිකඩ + සොයන්න + + + + තව + යෙදුමෙන් පිටවන්න + + + කෙටුම්පත + + + ජාලය + + + පරිශීලක + + + භාෂාව + + සාමාන්‍ය + + + + පෙරකලාසිය + පෙරකලාසිය සබල කරන්න + + + ගිණුම වෙනස් කරන්න + + පිලිබඳව + බලපත්‍රය + යෙදුම + උපාංගය + + පරිත්‍යාග + diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index fd993b66..87f418b5 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -46,7 +46,7 @@ Ta skärmdump av en webbsida Sparar bild som Sparar skärmdump som: - Länkadress kopierad… + Länkadressen kopierades ... Nytt inlägg Till toppen Sök på taggar eller personer @@ -59,7 +59,7 @@ Dela länkadress Spara bild Dela bild - Öppna i en extern webbläsare… + Öppna i en extern webbläsare... Kopiera länkadress Kopiera bildadressen From 5a5d1d66b380628cbdb592c85b59f08ce481e29f Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sun, 1 Aug 2021 14:31:44 +0200 Subject: [PATCH 39/49] Update CHANGELOG --- CHANGELOG.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bcb1c3f5..8c6c9d68 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,11 @@ -![](https://r.gsantner.net/matomo/piwik.php?action_name=inapp_changelog&idsite=2&rec=1&urlref=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FCHANGELOG.md&_cvar=%7B%221%22%3A%5B%22source%22%2C%22changelog%22%5D%2C%222%22%3A%5B%22project%22%2C%22dandelion%22%5D%2C%223%22%3A%5B%22packageid%22%2C%22com.github.dfa.diaspora_android%22%5D%2C%224%22%3A%5B%22referrer%22%2C%22https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion%2FCHANGELOG.md%22%5D%7D) +### Recent changes +- See [Discussions](https://github.com/gsantner/dandelion/discussions), [Issues](https://github.com/gsantner/dandelion/issues) and [Project website](https://gsantner.net/) to see what is going on. - -### v1.3.x +### v1.4.0 +- Add seconds to 'save picture' date format - Updated translations - Added german F-Droid description translation +- Update to Android SDK 29 ### v1.3.0 - Add option to open youtube links external/in YouTube app (optional) From c42b4995b3e22501673d2089a1c980fd147ee4cc Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Thu, 9 Sep 2021 22:43:58 +0200 Subject: [PATCH 40/49] Update crowdin config --- crowdin.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crowdin.yml b/crowdin.yml index 4e269b3e..512c28f1 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -1,11 +1,14 @@ # vim: sw=2 ts=2 noexpandtab: -commit_message: "[ci skip] Crowdin translation bot: New translations for %language%" +commit_message: "[ci skip] Update translations (%language%)" append_commit_message: false files: - source: /app/src/main/res/values/strings.xml translation: /app/src/main/res/values-%android_code%/%original_file_name% languages_mapping: android_code: + az: az # Azerbaijani + ckb: ckb # Sorani (Kurdish) + kmr: kmr # Kurmanji (Kurdish) gl: gl # Galician sc: sc # Sardinian kab: kab # Kabyle From 8161353de7c41eb1fca5b7f35dc5eb9cfc3a62b9 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Thu, 9 Sep 2021 22:46:37 +0200 Subject: [PATCH 41/49] New Crowdin updates (#292) --- app/src/main/res/values-zh-rTW/strings.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index ddcd27b6..7e9d0298 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -202,6 +202,9 @@ 再多說一些 使用其他應用程式來開啟 Youtube 連結 Youtube 連結 + 修改帳號的佈景主題 + 下拉可更新 + 從頁面的上方下拉一下可以更新內容。\n這個設定修改後需要重啟應用程式才會生效。 贊助 - 喜歡這個專案嗎?希望它繼續改善而且問題得到解決嗎?\n\n開發應用程式以及撰寫相關部落格文章都需要很多時間!如果你想要幫忙讓專案可以繼續,請考慮小額捐款!\n\n這個專案是在閒暇時間開發的,完全免費,並且沒有任何廣告! + 喜歡這個專案嗎?希望它繼續改善,而且問題得到解決嗎?\n\n無論是開發應用程式,還是撰寫相關部落格文章,都需要很多時間!如果你想要幫助專案持續發展,請考慮給我們小額捐款!\n\n這個專案是在閒暇時間開發的,完全免費,並且沒有任何廣告! From de378b8adc6eed592bd2a6ffe54aa460d47de892 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sat, 2 Oct 2021 13:04:29 +0200 Subject: [PATCH 42/49] Add language Odia/Oriya (India), Update translations (#293) --- app/src/main/res/values-az/strings.xml | 24 ++++++++++++++++++++++++ app/src/main/res/values-ckb/strings.xml | 24 ++++++++++++++++++++++++ app/src/main/res/values-kmr/strings.xml | 24 ++++++++++++++++++++++++ app/src/main/res/values-or/strings.xml | 24 ++++++++++++++++++++++++ crowdin.yml | 1 + 5 files changed, 97 insertions(+) create mode 100644 app/src/main/res/values-az/strings.xml create mode 100644 app/src/main/res/values-ckb/strings.xml create mode 100644 app/src/main/res/values-kmr/strings.xml create mode 100644 app/src/main/res/values-or/strings.xml diff --git a/app/src/main/res/values-az/strings.xml b/app/src/main/res/values-az/strings.xml new file mode 100644 index 00000000..43d88f4b --- /dev/null +++ b/app/src/main/res/values-az/strings.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-ckb/strings.xml b/app/src/main/res/values-ckb/strings.xml new file mode 100644 index 00000000..43d88f4b --- /dev/null +++ b/app/src/main/res/values-ckb/strings.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-kmr/strings.xml b/app/src/main/res/values-kmr/strings.xml new file mode 100644 index 00000000..43d88f4b --- /dev/null +++ b/app/src/main/res/values-kmr/strings.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml new file mode 100644 index 00000000..43d88f4b --- /dev/null +++ b/app/src/main/res/values-or/strings.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/crowdin.yml b/crowdin.yml index 512c28f1..c23f5159 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -62,4 +62,5 @@ files: mk: mk # Macedonian si-LK: si # Sinhala (Sri Lanka) eo: eo # Esperanto + or: or # Odia/Oriya (India) translate_attributes: 0 From 37f586912f274498f991c98fb801c2bd8c916ed2 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sat, 9 Oct 2021 20:17:11 +0200 Subject: [PATCH 43/49] Change link to domain podupti.me -> diaspora.fediverse.observer, closes #295, by @gsantner --- metadata/de/full_description.txt | 2 +- metadata/en-US/full_description.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/metadata/de/full_description.txt b/metadata/de/full_description.txt index 00eb10fd..b723eddb 100644 --- a/metadata/de/full_description.txt +++ b/metadata/de/full_description.txt @@ -12,7 +12,7 @@ Verbessere dein Netzwerk-Erlebnis durch nützliche Features: 🈯 Getrennte App- und Systemsprache. Nutze die App in beliebiger Sprache (zB. Englisch) und behalte deine Systemsprache (zB. Deutsch) bei. -🔐 Du bist noch auf der Suche nach einem Pod um dich zu registrieren? Die App bringt eine große Liste mit und weitere Pods findest du auf
podupti.me. +🔐 Du bist noch auf der Suche nach einem Pod um dich zu registrieren? Die App bringt eine große Liste mit und weitere Pods findest du auf diaspora.fediverse.observer. 🍻 Mehrere Accounts: Nutze dandelion* und dandelior* um zwei Accounts auf dem gleichen Gerät zu nutzen. Die Apps besitzen eigene Icons und unterschiedliche Vorgabefarben. diff --git a/metadata/en-US/full_description.txt b/metadata/en-US/full_description.txt index cb8fdf60..6e6ba779 100644 --- a/metadata/en-US/full_description.txt +++ b/metadata/en-US/full_description.txt @@ -12,7 +12,7 @@ It adds useful features to your networking experience: 🈯 Use in any language that the app is translated in - for example in German but have English as system language. -🔐 Looking for a pod to register? The app lists many pods with more being listed at podupti.me. +🔐 Looking for a pod to register? The app lists many pods with more being listed at diaspora.fediverse.observer. 🍻 Multiple accounts: You can use dandelion* and dandelior* to use two accounts at the same time on one device. They use a different icon and other default colors. From b80cc3ab042282d1d41bb199d4dcd8c074ce0b12 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sat, 28 May 2022 20:55:42 +0200 Subject: [PATCH 44/49] Add croatian & thai language to translation system --- crowdin.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/crowdin.yml b/crowdin.yml index c23f5159..b3830177 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -63,4 +63,6 @@ files: si-LK: si # Sinhala (Sri Lanka) eo: eo # Esperanto or: or # Odia/Oriya (India) + hr: hr # Croatia + th: th # Thai translate_attributes: 0 From 67b0bbbfd2fc5a4258c7f2097e40a469d65734fe Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sat, 28 May 2022 21:03:18 +0200 Subject: [PATCH 45/49] Update translations (PR #294) --- app/src/main/res/values-hr/strings.xml | 24 +++++++ app/src/main/res/values-or/strings.xml | 95 ++++++++++++++++++++++++++ app/src/main/res/values-si/strings.xml | 36 ++++++++++ app/src/main/res/values-th/strings.xml | 24 +++++++ 4 files changed, 179 insertions(+) create mode 100644 app/src/main/res/values-hr/strings.xml create mode 100644 app/src/main/res/values-th/strings.xml diff --git a/app/src/main/res/values-hr/strings.xml b/app/src/main/res/values-hr/strings.xml new file mode 100644 index 00000000..43d88f4b --- /dev/null +++ b/app/src/main/res/values-hr/strings.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index 43d88f4b..4411af7f 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -1,24 +1,119 @@ + ନେଭିଗେସନ୍ ଡ୍ରୟର୍ ଖୋଲନ୍ତୁ + ନେଭିଗେସନ୍ ଡ୍ରୟର୍ ବନ୍ଦ କରନ୍ତୁ + ପୁନଃଲୋଡ୍ କରନ୍ତୁ + ବନ୍ଦ କରନ୍ତୁ + ବାତିଲ୍ କର + ସେଟିଂସମୂହ + ବିଜ୍ଞପ୍ତି + ବାର୍ତ୍ତାଳାପ + ପ୍ରୋଫାଇଲ୍ + ସନ୍ଧାନ କରନ୍ତୁ + ପରିବର୍ତ୍ତନ ଲଗ୍ + ପରିସଂଖ୍ୟାନ + ସବୁ ବିଜ୍ଞପ୍ତି + ନିଶ୍ଚିତକରଣ + ଅଧିକ + ବିଷୟରେ | ସହାୟତା + ପାଠ୍ୟ ଭାବରେ ଲିଙ୍କ୍ ଅଂଶୀଦାର କରନ୍ତୁ + ୱେବପୃଷ୍ଠାର ସ୍କ୍ରିନସଟ୍ ଅଂଶୀଦାର କରନ୍ତୁ + ୱେବପୃଷ୍ଠାର ସ୍କ୍ରିନସଟ୍ ନିଅନ୍ତୁ + ଏଥିରେ ପ୍ରତିଛବି ସଞ୍ଚୟ କରୁଛି + ଲିଙ୍କ୍ ଠିକଣା କପି ହୋଇଛି … + ଶୀର୍ଷକୁ ଯାଆନ୍ତୁ + ଆପ୍ ବାହାରକୁ ଯାଆନ୍ତୁ + ମୋବାଇଲ୍/ଡେସ୍କଟପ୍ ଦର୍ଶନ ଟୋଗଲ୍ କରନ୍ତୁ + ଅଂଶୀଦାର… + ଦୟାକରି ଏକ ନାମ ଯୋଡ଼ନ୍ତୁ + ଲିଙ୍କ୍ ଠିକଣା ଅଂଶୀଦାର କରନ୍ତୁ + ପ୍ରତିଛବି ସଞ୍ଚୟ କରନ୍ତୁ + ପ୍ରତିଛବି ଅଂଶୀଦାର କରନ୍ତୁ + ପ୍ରତିଛବି ଲୋଡ୍ କରିବାରେ ଅସମର୍ଥ + ପ୍ରୋଟୋକଲ୍ + ମୁଖ୍ୟ ଦର୍ଶନରେ ସ୍ଥିତି ଦଣ୍ଡିକା ଲୁଚାନ୍ତୁ + ସ୍ଥିତି ଦଣ୍ଡିକା ଲୁଚାଅ + ମୁଖ୍ୟ ଦର୍ଶନରେ ଆଖ୍ୟା ଦେଖାନ୍ତୁ + ଆଖ୍ୟା ଦେଖାନ୍ତୁ + ଉନ୍ମୋଚକ ସର୍ଟକଟ୍ + ରୂପ + ନେଟୱର୍କ + ଉପଭୋକ୍ତା + ସାଧାରଣ + ବ୍ୟବସ୍ଥାପକ + ଥିମ୍ ଏବଂ ରଙ୍ଗ + ଏହି ଆପ୍ ର ଭାଷା ବଦଳାନ୍ତୁ। ପରିବର୍ତ୍ତନଗୁଡ଼ିକ କାର୍ଯ୍ୟକାରୀ ହେବା ପାଇଁ ଆପ୍ ପୁନଃଆରମ୍ଭ କରନ୍ତୁ + ଭାଷା + ସିଷ୍ଟମ୍ ଭାଷା + ଫଣ୍ଟ ଆକାର + ସାଧାରଣ + ବଡ଼ + ବିରାଟ + ପ୍ରତିଛବିଗୁଡ଼ିକୁ ଧାରଣ କରନ୍ତୁ + ସ୍କ୍ରିନ୍ ଘୂର୍ଣ୍ଣନ + ଡିଫଲ୍ଟ + ପୋର୍ଟ୍ରେଟ୍ + ଲ୍ୟାଣ୍ଡସ୍କେପ୍ + ପ୍ରକ୍ସି + ପ୍ରକ୍ସି ସକ୍ଷମ କରନ୍ତୁ + ଆକାଉଣ୍ଟ୍ ବଦଳାନ୍ତୁ + ଏହା ସମସ୍ତ କୁକୀ ଏବଂ ଅଧିବେଶନ ଡାଟା ଲିଭାଇଦେବ। ଆପଣ ପ୍ରକୃତରେ ଆପଣଙ୍କ ଆକାଉଣ୍ଟ୍ ପରିବର୍ତ୍ତନ କରିବାକୁ ଚାହାଁନ୍ତି କି? + ବିବିଧ + ପୂର୍ଣ୍ଣ ପୁନଃସେଟ୍ + ମୌଳିକ AdBlocker ସକ୍ଷମ କରନ୍ତୁ। ବିଜ୍ଞାପନଗୁଡ଼ିକ ଗ୍ରଥିତ ଦର୍ଶନରେ ଅନ୍ତର୍ଭୁକ୍ତ ହୋଇପାରେ + ବିଜ୍ଞାପନଗୁଡ଼ିକୁ ଅବରୋଧ କରନ୍ତୁ + ବିଷୟରେ + ଲାଇସେନ୍ସ + ଆପ୍ଲିକେସନ୍ + ଡିଭାଇସ୍ + ଆପ୍ ସଂସ୍କରଣ: %1$s + ଆଣ୍ଡ୍ରଏଡ୍ ସଂସ୍କରଣ: %1$s + ଡିଭାଇସ୍ ନାମ: %1$s + କୋଡ୍ ନାମ: %1$s + ଉତ୍ସ ପ୍ରାପ୍ତ କରନ୍ତୁ + ଆପ୍ ଅନୁବାଦ କରନ୍ତୁ! + ଆପ୍ ଆପଣଙ୍କ ଭାଷାରେ ଉପଲବ୍ଧ ନାହିଁ କି? ଆପଣ ଏହା ବଦଳାଇପାରିବେ! ଆପଣ ଏହାକୁ ଅନୁବାଦ କରି ଆମକୁ କାହିଁକି ସାହାଯ୍ୟ କରୁନାହାଁନ୍ତି? ଆପ୍ ଅନୁବାଦ କରିବାରେ ଯେକୌଣସି ବ୍ୟକ୍ତିଙ୍କୁ ସକ୍ଷମ କରିବା ପାଇଁ ଆମେ Crowdin ବ୍ୟବହାର କରୁ। + ମୋତେ ଅନୁବାଦ କରିବାକୁ ଦିଅ + ମତାମତ ଦିଅନ୍ତୁ! + dandelion* ଏପର୍ଯ୍ୟନ୍ତ ବିକାଶରେ ଅଛି, ତେଣୁ ଯଦି ଆପଣଙ୍କର ପରାମର୍ଶ କିମ୍ୱା କୌଣସି ପ୍ରକାରର ମତାମତ ରହିଛି, ତେବେ ଦୟାକରି ଆମକୁ ଜଣାଇବା ପାଇଁ ଆମର ବଗ୍ ଟ୍ରାକର୍ ବ୍ୟବହାର କରନ୍ତୁ! + ବଗ୍‌ ରିପୋର୍ଟ୍‌ କରନ୍ତୁ + ଶବ୍ଦ ବିସ୍ତାର କରନ୍ତୁ! + diaspora* ଏବଂ #dandelion ବିଷୟରେ ଆପଣଙ୍କ ବନ୍ଧୁ ଏବଂ ପରିବାରକୁ କୁହନ୍ତୁ! ଆପଣ ଆପଣଙ୍କର ଅନୁଭୂତି ବିଷୟରେ କାହିଁକି ବ୍ଲଗ୍ କରୁନାହଁ? ଆମେ ଆପଣଙ୍କଠାରୁ ଶୁଣିବାକୁ ପସନ୍ଦ କରିବୁ! + ଆପ୍ ଅଂଶୀଦାର କରନ୍ତୁ + ଆଜ୍ଞା! #dandelion କୁ ଥରେ ଦେଖିଯାଆନ୍ତୁ! %1$s + ରକ୍ଷଣାବେକ୍ଷଣକାରୀ + ଏହି ଆପ୍ ବର୍ତ୍ତମାନ <br><br>%1$sଙ୍କ ଦ୍ୱାରା ବିକାଶ ଓ ରକ୍ଷଣାବେକ୍ଷଣ କରାଯାଉଛି + ଯୋଗଦାନକାରୀ + %1$s<br><br>ଧନ୍ୟବାଦ! + GNU GPLv3+ ଲାଇସେନ୍ସ + ତୃତୀୟ-ପକ୍ଷ ଲାଇବ୍ରେରୀ + ନିମ୍ନଲିଖିତ ଲାଇବ୍ରେରୀଗୁଡ଼ିକ ବ୍ୟବହାର ହୋଇଛି: + ଆମେ LeafPic ରୁ କିଛି ପ୍ରେରଣା ଏବଂ କୋଡ୍ ନେଇଛୁ। ଯାଆନ୍ତୁ ଏହାକୁ ଥରେ ଦେଖି ଆସନ୍ତୁ, ଏହା ବି ଏକ ମାଗଣା ସଫ୍ଟୱେର୍! + ମୋତେ ଆହୁରି କୁହନ୍ତୁ + ବାହ୍ୟ ଆପରେ YouTube ଲିଙ୍କ୍ ଖୋଲିବା ପାଇଁ ସକ୍ଷମ କରନ୍ତୁ + YouTube ଲିଙ୍କଗୁଡ଼ିକ + ଆପଣଙ୍କ ଆକାଉଣ୍ଟର ଥିମ୍ ପରିବର୍ତ୍ତନ କରନ୍ତୁ + ସତେଜ କରିବାକୁ ଟାଣନ୍ତୁ + ଦାନ କରନ୍ତୁ diff --git a/app/src/main/res/values-si/strings.xml b/app/src/main/res/values-si/strings.xml index 1f38d92a..2187f861 100644 --- a/app/src/main/res/values-si/strings.xml +++ b/app/src/main/res/values-si/strings.xml @@ -1,6 +1,7 @@ + නැවත පූරණය වසන්න අවලංගු @@ -8,28 +9,55 @@ දැනුම්දීම් සංවාද පැතිකඩ + ක්‍රියාකාරකම් + අදහස් දැක්විණි + සැඳහුම් + ප්‍රසිද්ධ සොයන්න + සබඳතා + සංඛ්‍යාලේඛන + සියළුම දැනුම්දීම් + එවගේම අදහස් දැක්විණි + ඔබට පිටවීමට ඇවැසිද? තව + පිළිබඳව | උපකාර + ප්‍රසිද්ධ ක්‍රියාකාරකම් + වාර්තා + වියමන පිටුවෙහි තිරසේයාවක් බෙදාගන්න + වියමන පිටුවෙහි තිර සේයාවක් අරගන්න + ලෙස තිරසේයාව සුරකින්න: + සබැඳියේ ලිපිනය පිටපත් විය… යෙදුමෙන් පිටවන්න + බෙදාගන්න… + නමක් එකතු කරන්න + සබැඳියේ ලිපිනය බෙදාගන්න + බාහිර අතිරික්සුවකින් විවෘත කරන්න… + සබැඳිය පසුරුපුවරුවට පිටපත් කරන්න කෙටුම්පත + සිරැසිය පෙන්වන්න ජාලය පරිශීලක + පරිපාලක + තේමාව සහ වර්ණ භාෂාව + පද්ධතියේ භාෂාව + මුද්‍රණඅකුරේ ප්‍රමාණය සාමාන්‍ය + පෙරනිමි පෙරකලාසිය පෙරකලාසිය සබල කරන්න @@ -41,6 +69,14 @@ බලපත්‍රය යෙදුම උපාංගය + ඇන්ඩ්‍රොයිඩ් අනුවාදය: %1$s + උපාංගයේ නම: %1$s + කේතනාමය: %1$s + මූලාශ්‍රය ගන්න + යෙදුම පරිවර්තනය කරන්න! + යෙදුම බෙදාගන්න + ජීඑන්යූ ජීපීඑල්v3+ බලපත්‍රය + යූටියුබ් සබැඳිය පරිත්‍යාග diff --git a/app/src/main/res/values-th/strings.xml b/app/src/main/res/values-th/strings.xml new file mode 100644 index 00000000..43d88f4b --- /dev/null +++ b/app/src/main/res/values-th/strings.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + From 36bd1af0b9754b3ad52af316c0fc46f1a5b23527 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Wed, 13 Jul 2022 01:51:31 +0200 Subject: [PATCH 46/49] Translations: Add bulgarian --- app/src/main/res/values-bg/strings.xml | 24 ++++++++++++++++++++++++ crowdin.yml | 1 + 2 files changed, 25 insertions(+) create mode 100644 app/src/main/res/values-bg/strings.xml diff --git a/app/src/main/res/values-bg/strings.xml b/app/src/main/res/values-bg/strings.xml new file mode 100644 index 00000000..43d88f4b --- /dev/null +++ b/app/src/main/res/values-bg/strings.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/crowdin.yml b/crowdin.yml index b3830177..7f6c9896 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -64,5 +64,6 @@ files: eo: eo # Esperanto or: or # Odia/Oriya (India) hr: hr # Croatia + bg: bg # Bulgarian th: th # Thai translate_attributes: 0 From c2bea7bec04ce6a5de4f48feef58119991979c96 Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Thu, 8 Dec 2022 14:16:52 +0100 Subject: [PATCH 47/49] Crowdin add Estonian, Update translations (PR #297) --- app/src/main/res/values-et/strings.xml | 24 ++++++++++++++++++++++++ app/src/main/res/values-or/strings.xml | 2 +- crowdin.yml | 1 + 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 app/src/main/res/values-et/strings.xml diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml new file mode 100644 index 00000000..43d88f4b --- /dev/null +++ b/app/src/main/res/values-et/strings.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index 4411af7f..5c22a862 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -78,7 +78,7 @@ ଆକାଉଣ୍ଟ୍ ବଦଳାନ୍ତୁ ଏହା ସମସ୍ତ କୁକୀ ଏବଂ ଅଧିବେଶନ ଡାଟା ଲିଭାଇଦେବ। ଆପଣ ପ୍ରକୃତରେ ଆପଣଙ୍କ ଆକାଉଣ୍ଟ୍ ପରିବର୍ତ୍ତନ କରିବାକୁ ଚାହାଁନ୍ତି କି? - ବିବିଧ + ଵିଵିଧ ପୂର୍ଣ୍ଣ ପୁନଃସେଟ୍ ମୌଳିକ AdBlocker ସକ୍ଷମ କରନ୍ତୁ। ବିଜ୍ଞାପନଗୁଡ଼ିକ ଗ୍ରଥିତ ଦର୍ଶନରେ ଅନ୍ତର୍ଭୁକ୍ତ ହୋଇପାରେ ବିଜ୍ଞାପନଗୁଡ଼ିକୁ ଅବରୋଧ କରନ୍ତୁ diff --git a/crowdin.yml b/crowdin.yml index 7f6c9896..c4ffe7a5 100644 --- a/crowdin.yml +++ b/crowdin.yml @@ -65,5 +65,6 @@ files: or: or # Odia/Oriya (India) hr: hr # Croatia bg: bg # Bulgarian + et: et # Estonian th: th # Thai translate_attributes: 0 From c65aab3840e6f9ebb7291385792635950142970a Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sat, 28 Jan 2023 17:21:07 +0100 Subject: [PATCH 48/49] Update translations, project info --- Makefile | 64 ++++++++++++++--- README.md | 5 +- .../activity/MainActivity.java | 2 - .../opoc/util/AndroidSupportMeWrapper.java | 72 ------------------- .../net/gsantner/opoc/util/ContextUtils.java | 20 ------ app/src/main/res/values-af/strings.xml | 1 - app/src/main/res/values-ar/strings.xml | 1 - app/src/main/res/values-bs/strings.xml | 2 - app/src/main/res/values-ca/strings.xml | 2 - app/src/main/res/values-cs/strings.xml | 1 - app/src/main/res/values-da/strings.xml | 1 - app/src/main/res/values-de/strings.xml | 2 - app/src/main/res/values-es/strings.xml | 2 - app/src/main/res/values-fa/strings.xml | 1 - app/src/main/res/values-fr/strings.xml | 2 - app/src/main/res/values-gl/strings.xml | 2 - app/src/main/res/values-hi/strings.xml | 1 - app/src/main/res/values-hu/strings.xml | 1 - app/src/main/res/values-it/strings.xml | 2 - app/src/main/res/values-iw/strings.xml | 1 - app/src/main/res/values-ja/strings.xml | 2 - app/src/main/res/values-kab/strings.xml | 1 - app/src/main/res/values-ko/strings.xml | 1 - app/src/main/res/values-nb-rNO/strings.xml | 1 - app/src/main/res/values-nl/strings.xml | 1 - app/src/main/res/values-or/strings.xml | 1 - app/src/main/res/values-pl/strings.xml | 1 - app/src/main/res/values-pt-rBR/strings.xml | 2 - app/src/main/res/values-pt/strings.xml | 2 - app/src/main/res/values-ru/strings.xml | 2 - app/src/main/res/values-sc/strings.xml | 2 - app/src/main/res/values-si/strings.xml | 1 - app/src/main/res/values-sr-rRS/strings.xml | 1 - app/src/main/res/values-sr/strings.xml | 1 - app/src/main/res/values-sv/strings.xml | 2 - app/src/main/res/values-tr/strings.xml | 2 - app/src/main/res/values-uk/strings.xml | 2 - app/src/main/res/values-zh-rCN/strings.xml | 2 - app/src/main/res/values-zh-rTW/strings.xml | 2 - .../res/values/strings-not_translatable.xml | 7 -- app/src/main/res/values/strings.xml | 3 - metadata/de/full_description.txt | 7 +- metadata/en-US/full_description.txt | 5 +- 43 files changed, 57 insertions(+), 179 deletions(-) delete mode 100644 app/src/main/java/net/gsantner/opoc/util/AndroidSupportMeWrapper.java diff --git a/Makefile b/Makefile index 14eef72c..09b21c00 100644 --- a/Makefile +++ b/Makefile @@ -10,36 +10,47 @@ env-%: DIST_DIR = dist MOVE = mv -all: $(DIST_DIR) lint test build +all: $(DIST_DIR) spellcheck lint deptree test build aapt_dump_badging #################################################################################### $(DIST_DIR): mkdir -p ${DIST_DIR} -.NOTPARALLEL: gradle gradle-check-error +ANDROID_BUILD_TOOLS := $(shell test -n "$ANDROID_SDK_ROOT" && find "${ANDROID_SDK_ROOT}/build-tools" -iname "aapt" | sort -r | head -n1 | xargs dirname) +TOOL_SPELLCHECKING_ISPELL := $(shell command -v ispell 2> /dev/null) + +FLAVOR := $(or ${FLAVOR},${FLAVOR},Atest) + +.NOTPARALLEL: gradle gradle-analyze-log gradle: env-ANDROID_SDK_ROOT mkdir -p $(DIST_DIR)/log/ chmod +x gradlew ./gradlew --no-daemon --parallel --stacktrace $A 2>&1 | tee "$(DIST_DIR)/log/gradle.log" @echo "-----------------------------------------------------------------------------------" -gradle-check-error: +gradle-analyze-log: mv "$(DIST_DIR)/log/gradle.log" "$(DIST_DIR)/log/gradle$A.log" cat "$(DIST_DIR)/log/gradle$A.log" | grep "BUILD " | tail -n1 | grep -q "BUILD SUCCESSFUL in" +adb: env-ANDROID_SDK_ROOT + "${ANDROID_SDK_ROOT}/platform-tools/adb" $A 2>&1 | tee "$(DIST_DIR)/log/adb-$L.log" + +aapt: env-ANDROID_SDK_ROOT + "${ANDROID_BUILD_TOOLS}/aapt" $A 2>&1 | grep -v 'application-label-' | tee "$(DIST_DIR)/log/aapt$L.log" + build: rm -f $(DIST_DIR)/*.apk - $(MAKE) A="clean assembleFlavorAtest -x lint" gradle - find app -type f -iname '*.apk' | grep -v 'unsigned.apk' | xargs cp -R -t $(DIST_DIR)/ - $(MAKE) A="-build" gradle-check-error + $(MAKE) A="clean assembleFlavor$(FLAVOR) -x lint" gradle + find app -type f -newermt '-300 seconds' -iname '*.apk' -not -iname '*unsigned.apk' | xargs cp -R -t $(DIST_DIR)/ + $(MAKE) A="-build" gradle-analyze-log lint: rm -Rf $(DIST_DIR)/lint mkdir -p $(DIST_DIR)/lint/ $(MAKE) A="lintFlavorDefaultDebug" gradle - find app -type f -iname 'lint-results-*' | xargs cp -R -t $(DIST_DIR)/lint - $(MAKE) A="-lint" gradle-check-error + find app -type f -iname 'lint-results-*' | grep -v 'intermediates' | xargs cp -R -t $(DIST_DIR)/lint + $(MAKE) A="-lint" gradle-analyze-log test: rm -Rf $(DIST_DIR)/tests @@ -47,9 +58,42 @@ test: mkdir -p app/build/test-results/testFlavorDefaultDebugUnitTest && echo 'PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHRlc3RzdWl0ZSBuYW1lPSJkdW1teSIgdGVzdHM9IjEiIHNraXBwZWQ9IjAiIGZhaWx1cmVzPSIwIiBlcnJvcnM9IjAiIHRpbWVzdGFtcD0iMjAyMC0xMi0wOFQwMDowMDowMCIgaG9zdG5hbWU9ImxvY2FsaG9zdCIgdGltZT0iMC4wMSI+CiAgPHByb3BlcnRpZXMvPgogIDx0ZXN0Y2FzZSBuYW1lPSJkdW1teSIgY2xhc3NuYW1lPSJkdW1teSIgdGltZT0iMC4wMSIvPgogIDxzeXN0ZW0tb3V0PjwhW0NEQVRBW11dPjwvc3lzdGVtLW91dD4KICA8c3lzdGVtLWVycj48IVtDREFUQVtdXT48L3N5c3RlbS1lcnI+CjwvdGVzdHN1aXRlPgo=' | base64 -d > 'app/build/test-results/testFlavorDefaultDebugUnitTest/TEST-dummy.xml' find app -type d -iname 'testFlavorDefaultDebugUnitTest' | xargs cp -R -t $(DIST_DIR)/ mv ${DIST_DIR}/testFlavorDefaultDebugUnitTest $(DIST_DIR)/tests - $(MAKE) A="-test" gradle-check-error + $(MAKE) A="-test" gradle-analyze-log + +deptree: + $(MAKE) A="app:dependencies --configuration flavor$(FLAVOR)DebugRuntimeClasspath" gradle + $(MAKE) A="-dependency-tree" gradle-analyze-log clean: $(MAKE) A="clean" gradle - rm -Rf $(DIST_DIR) app/build app/flavor* + rm -Rf $(DIST_DIR) app/build app/flavor* .idea dist + find . -type f -iname "*.iml" -delete $(MAKE) $(DIST_DIR) + @echo "-----------------------------------------------------------------------------------" + +install: + $(MAKE) A="install -r $(DIST_DIR)/*.apk" L="install" adb + +run: + $(MAKE) A="shell monkey -p $$(aapt dump badging $(DIST_DIR)/*.apk | grep package: | sed 's@.* name=@@' | sed 's@ .*@@' | xargs | head -n1) -c android.intent.category.LAUNCHER 1" L="run" adb + +aapt_dump_badging: + $(MAKE) A="dump badging $(DIST_DIR)/*.apk" aapt + @echo "-----------------------------------------------------------------------------------" + +spellcheck: + mkdir -p "$(DIST_DIR)/lint/" +ifndef TOOL_SPELLCHECKING_ISPELL + @echo "Tool ispell (spellcheck) not found in PATH. Spellcheck skipped." > "$(DIST_DIR)/lint/stringsxml-spellcheck.txt" +else + @echo "Use ispell for spellchecking the original values/strings.xml" + find . -iname "strings.xml" -path "*/main*/values/*" | head -n1 | xargs cat \ + | grep "@@' | sed 's@@@' | sed 's@\\n@ @g' | sed 's@\\@@g' \ + | ispell -W3 -a | grep ^\& | sed 's@[0-9]@@g' | sort | uniq | cut -d, -f1-4 \ + | sed 's@^..@- @' | column -t -s: \ + > "$(DIST_DIR)/lint/stringsxml-spellcheck.txt" + @echo "\nPotential words with bad spelling:" +endif + @cat "$(DIST_DIR)/lint/stringsxml-spellcheck.txt" + @echo "-----------------------------------------------------------------------------------" + diff --git a/README.md b/README.md index 74db9a84..c0faf4c3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ [![GitHub releases](https://img.shields.io/github/tag/gsantner/dandelion.svg)](https://github.com/gsantner/dandelion/releases) [![GitHub downloads](https://img.shields.io/github/downloads/gsantner/dandelion/total.svg?logo=github&logoColor=lime)](https://github.com/gsantner/dandelion/releases) [![Translate on Crowdin](https://img.shields.io/badge/translate-crowdin-green.svg)](https://crowdin.com/project/diaspora-for-android/invite) -[![Donate - say thanks](https://img.shields.io/badge/donate-say%20thanks-red.svg)](https://gsantner.net/page/supportme.html?project=dandelion&source=readme) [![Chat on Matrix](https://img.shields.io/badge/chat-matrix-blue.svg)](https://matrix.to/#/#dandelion:matrix.org) [![GitHub CI](https://github.com/gsantner/dandelion/workflows/CI/badge.svg)](https://github.com/gsantner/dandelion/actions) [![Codacy code quality](https://img.shields.io/codacy/grade/aff869c440bc48b7bd64680e97cbc453)](https://www.codacy.com/app/gsantner/dandelion) @@ -78,7 +77,5 @@ For more licensing informations, see [`3rd party licenses`](/app/src/main/res/ra ### Notice #### Maintainers -- gsantner ([GitHub](https://github.com/gsantner), [Web](https://gsantner.net/page/supportme.html?project=dandelion&source=gh_readme), [diaspora*](https://pod.geraspora.de/people/d1cbdd70095301341e834860008dbc6c)) - - Bitcoin: [1B9ZyYdQoY9BxMe9dRUEKaZbJWsbQqfXU5](https://gsantner.net/page/supportme.html?project=dandelion&source=gh_readme) +- gsantner ([GitHub](https://github.com/gsantner), [diaspora*](https://pod.geraspora.de/people/d1cbdd70095301341e834860008dbc6c)) - vanitasvitae ([GitHub](https://github.com/vanitasvitae), [diaspora*](https://pod.geraspora.de/people/bbd7af90fbec013213e34860008dbc6c)) - - Bitcoin: 1Ao3W6NaQv3xKppviB7RSFKjHo6PGd8RTy diff --git a/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java b/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java index 290cad2e..ba8af918 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java @@ -90,7 +90,6 @@ import com.github.dfa.diaspora_android.web.WebHelper; import com.github.dfa.diaspora_android.web.custom_tab.CustomTabActivityHelper; import net.gsantner.opoc.format.markdown.SimpleMarkdownParser; -import net.gsantner.opoc.util.AndroidSupportMeWrapper; import java.io.IOException; @@ -664,7 +663,6 @@ public class MainActivity extends ThemedActivity protected void onResume() { AppLog.v(this, "onResume()"); super.onResume(); - //new AndroidSupportMeWrapper(this).mainOnResume(); AppLog.v(this, "Register BroadcastReceivers"); LocalBroadcastManager.getInstance(this).registerReceiver(brSetTitle, new IntentFilter(ACTION_UPDATE_TITLE_FROM_URL)); LocalBroadcastManager.getInstance(this).registerReceiver(brOpenExternalLink, new IntentFilter(ACTION_OPEN_EXTERNAL_URL)); diff --git a/app/src/main/java/net/gsantner/opoc/util/AndroidSupportMeWrapper.java b/app/src/main/java/net/gsantner/opoc/util/AndroidSupportMeWrapper.java deleted file mode 100644 index 4807c96b..00000000 --- a/app/src/main/java/net/gsantner/opoc/util/AndroidSupportMeWrapper.java +++ /dev/null @@ -1,72 +0,0 @@ -/*####################################################### - * - * Maintained by Gregor Santner, 2018- - * https://gsantner.net/ - * - * License of this file: Apache 2.0 (Commercial upon request) - * https://www.apache.org/licenses/LICENSE-2.0 - * https://github.com/gsantner/opoc/#licensing - * -#########################################################*/ -package net.gsantner.opoc.util; - -import android.app.Activity; -import android.content.Context; -import android.content.SharedPreferences; -import android.support.v7.app.AlertDialog; - -import com.github.dfa.diaspora_android.R; - -import net.gsantner.opoc.preference.SharedPreferencesPropertyBackend; - -public class AndroidSupportMeWrapper extends ActivityUtils { - private LocalSettingsImpl _localSettingsImpl; - - public AndroidSupportMeWrapper(Activity activity) { - super(activity); - _localSettingsImpl = new LocalSettingsImpl(_context.getApplicationContext()); - } - - public void openPayPalDonationPage() { - String id = getPackageIdManifest(); - String url = "https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=TVV24QBGMN23C&source=self.gsantner.net%2F" + id; - openWebpageInExternalBrowser(url); - } - - - public void openGeneralDonatePage() { - openWebpageInExternalBrowser(_context.getString(R.string.app_donate_url)); - } - - public void mainOnResume() { - if (_localSettingsImpl.all14dRequest()) { - AlertDialog.Builder dialog = new AlertDialog.Builder(_context); - dialog.setTitle(R.string.donate_) - .setCancelable(false) - .setNegativeButton(R.string.close, (dialogInterface, i) -> dialogInterface.dismiss()) - .setPositiveButton("PayPal", (dialogInterface, i) -> { - openPayPalDonationPage(); - dialogInterface.dismiss(); - }) - .setNeutralButton(R.string.donate_, (dialogInterface, i) -> { - openGeneralDonatePage(); - dialogInterface.dismiss(); - }) - .setMessage(R.string.do_you_like_this_project_want_donate_to_keep_alive); - dialog.show(); - } - } - - private class LocalSettingsImpl extends SharedPreferencesPropertyBackend { - private final SharedPreferences _prefCache; - - public LocalSettingsImpl(Context _context) { - super(_context, "AndroidSupportMeWrapper.LocalSettingsImpl"); - _prefCache = _context.getSharedPreferences("cache", Context.MODE_PRIVATE); - } - - public boolean all14dRequest() { - return afterDaysTrue("all14dRequest", 31, 3); - } - } -} diff --git a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java index 58bc8009..5da4f165 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java @@ -365,26 +365,6 @@ public class ContextUtils { return bcbool("IS_FOSS_BUILD", false); } - /** - * Request a bitcoin donation with given details. - * All parameters are awaited as string resource ids - */ - public void showDonateBitcoinRequest(@StringRes final int srBitcoinId, @StringRes final int srBitcoinAmount, @StringRes final int srBitcoinMessage, @StringRes final int srAlternativeDonateUrl) { - if (!isGooglePlayBuild()) { - String btcUri = String.format("bitcoin:%s?amount=%s&label=%s&message=%s", - rstr(srBitcoinId), rstr(srBitcoinAmount), - rstr(srBitcoinMessage), rstr(srBitcoinMessage)); - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(btcUri)); - intent.addFlags(FLAG_ACTIVITY_NEW_TASK); - try { - _context.startActivity(intent); - } catch (ActivityNotFoundException e) { - openWebpageInExternalBrowser(rstr(srAlternativeDonateUrl)); - } - } - } - public String readTextfileFromRawRes(@RawRes int rawResId, String linePrefix, String linePostfix) { StringBuilder sb = new StringBuilder(); BufferedReader br = null; diff --git a/app/src/main/res/values-af/strings.xml b/app/src/main/res/values-af/strings.xml index 3956db71..4e4a8035 100644 --- a/app/src/main/res/values-af/strings.xml +++ b/app/src/main/res/values-af/strings.xml @@ -154,5 +154,4 @@ Youtube links Verander die tema van jou rekening Trek om te verfris - Skenk diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 19b6acfc..d09bf9c8 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -38,5 +38,4 @@ ترخيص المساهمون - تبرع diff --git a/app/src/main/res/values-bs/strings.xml b/app/src/main/res/values-bs/strings.xml index fd455277..51109f4f 100644 --- a/app/src/main/res/values-bs/strings.xml +++ b/app/src/main/res/values-bs/strings.xml @@ -38,6 +38,4 @@ O programu Saradnici - Doniraj - Sviđa li Vam se ovaj projekat? Želite li da napreduje a problemi budu otklonjeni?\n\nRazvijanje aplikacija i pisanje članaka o njima uzima puno vremena! Ako biste voljeli pomoći da projekat opstane, molimo Vas da razmislite o skromnoj donaciji!\n\nRad na ovom projektu odvija se u slobodno vrijeme, a program je besplatan i ne sadrži nikakav vid reklama! diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml index c91ed813..3ad40c44 100644 --- a/app/src/main/res/values-ca/strings.xml +++ b/app/src/main/res/values-ca/strings.xml @@ -206,6 +206,4 @@ diaspora*. Si voleu contribuir, endavant! Actualment som un equip molt petit, de Canvia el tema del vostre compte Feu lliscar per actualitzar S\'està lliscant cap avall a la part superior de la pàgina per actualitzar.\nCal que reinicieu l\'aplicació perquè els canvis tinguin efecte. - Fes un donatiu - Us agrada aquest projecte? Voleu que encara sigui millor i es solucionin els problemes?\n\nDesenvolupar aplicacions i escriure publicacions relacionades als blogs costa molt de temps! Si voleu ajudar perquè el projecte pugui continuar, considereu aportar una petita donació!\n\nAquest projecte es desenvolupa durant el temps lliure, completament gratis i sense publicitat! diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 9d1675a3..63534efb 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -200,5 +200,4 @@ Youtube odkazy Změňte téma vašeho účtu Pull osvěžit - Krátce diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 1c540912..6d783039 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -90,5 +90,4 @@ Udviklere Bidragsydere - Donér diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 518262ec..54bc3bbe 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -209,6 +209,4 @@ nachträglich erteilen. Öffne dafür: Systemeinstellungen - Apps - dandelion*. Thema des Accounts ändern Pull-To-Refresh In der Website von ganz oben nach unten ziehen um zu aktualisieren.\nDu musst die App neu starten damit die Änderungen wirksam werden. - Spenden - Gefällt dir dieses Projekt? Möchtest du, dass es verbessert wird und Probleme behoben werden?\n\nDie Entwicklung von Apps und das schreiben von relevanten Blog-Einträgen kostet viel Zeit! Wenn du helfen möchtest, so dass das Projekt weitergehen kann, ziehe bitte eine kleine Spende in Betracht!\n\nDieses Projekt wird in der Freizeit, völlig kostenlos und ohne jegliche Werbeeinblendungen entwickelt & angeboten! diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index bd46b3cc..603085a5 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -204,6 +204,4 @@ Cambiar el tema de tu cuenta Tirar para refrescar Deslizar hacia abajo la parte superior de la página para refrescar.\n Necesita reiniciar la aplicación para que los cambios surtan efecto. - Donar - ¿Te gusta este proyecto? ¿Quieres que se mejore y se corrijan problemas?\n\nEl desarrollo de aplicaciones y la escritura de entradas relacionadas del blog cuesta mucho tiempo. Si quieres ayudar a que el proyecto pueda continuar, por favor considera una pequeña donación!\n\nEste proyecto se desarrolla en tiempo de ocio, completamente gratis y sin publicidad! diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index c2c00825..f5cf3963 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -32,5 +32,4 @@ درباره مارکور همکاران - کمک مالی diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index bbdb4f36..b039f5c3 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -204,6 +204,4 @@ Changer le thème de votre compte Tirer vers le bas pour mettre à jour Tirez depuis le haut de la page vers le bas pour l\'actualiser.\nVous devez redémarrer l\'application pour que ces changements prennent effet. - Donner - Vous aimez ce projet ? Vous voulez participer à son amélioration et corriger ses problèmes ?\n\nDévelopper des applications et écrire les posts de blog correspondants demande beaucoup de temps ! Si vous voulez aider à la poursuite du projet, merci de considérer une petite donation.\n\nCe projet est développé sur du temps libre, complètement gratuitement et sans publicité ! diff --git a/app/src/main/res/values-gl/strings.xml b/app/src/main/res/values-gl/strings.xml index b6f49c8b..86bd9019 100644 --- a/app/src/main/res/values-gl/strings.xml +++ b/app/src/main/res/values-gl/strings.xml @@ -207,6 +207,4 @@ Cambiar o decorado da túa conta Tira para actualizar Tirar hacia abaixo na parte superior da páxina.\nDebes reiniciar a app para que os cambios se apliquen. - Doar - Gústache este proxecto? Queres que siga mellorando e resolvendo os problemas?\n\nDesenvolver aplicacións e escribir a documentación leva moito tempo! Se queres apoiar ao proxecto para que continúe, por favor, considera facer unha pequena doazón!\n\nEste proxecto desenvólvese no tempo libre, ofrécese libre e gratuitamente e sen publicidade! diff --git a/app/src/main/res/values-hi/strings.xml b/app/src/main/res/values-hi/strings.xml index 8b3f62d4..07facc0c 100644 --- a/app/src/main/res/values-hi/strings.xml +++ b/app/src/main/res/values-hi/strings.xml @@ -38,5 +38,4 @@ लाइसेंस योगदान कर्ता - दान करें diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index b51b1df7..36ef8efa 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -190,5 +190,4 @@ A következő könyvtárak vannak használatban: A LeafPicből merítettünk némi inspirációt és programkódot. Próbáld ki, ez is szabad szoftver! Tudj meg többet - Adományozás diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index ba09d501..8271dda5 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -210,6 +210,4 @@ Cambia il tema del tuo account Trascina per aggiornare Trascina dall\'alto al basso per aggiornare la pagina.\nDevi riavviare l\'app affinchè le modifiche abbiano effetto. - Dona - Ti piace questo progetto? Vuoi vederlo ancora migliore e con i problemi risolti?\n\nSviluppare applicazioni e documentarle sul blog costa un sacco di tempo! Se vuoi aiutare lo sviluppo del progetto, puoi fare una piccola donazione!\n\nQuesto progetto è sviluppato nel tempo libero, completamente gratis e senza alcuna pubblicità! diff --git a/app/src/main/res/values-iw/strings.xml b/app/src/main/res/values-iw/strings.xml index 148fe0aa..9626eba5 100644 --- a/app/src/main/res/values-iw/strings.xml +++ b/app/src/main/res/values-iw/strings.xml @@ -34,5 +34,4 @@ אודות תורמים - תרום diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 0cf49504..5c8c52ea 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -204,6 +204,4 @@ アカウントのテーマを変更 引き下げて更新 ページの上から下に引き下げて更新します。\n変更を反映するため、アプリを再起動する必要があります。 - 寄付 - このプロジェクトを気に入っていただけましたか? 改善したい、あるいは問題を修正したいですか?\n\nアプリの開発や、関連するブログの記事を書くに多くの時間がかかります! プロジェクトを進めるために、支援をしていただける場合は、少しの寄付をご検討ください!\n\nこのプロジェクトは余暇に開発していて、完全に無料で、広告はありません! diff --git a/app/src/main/res/values-kab/strings.xml b/app/src/main/res/values-kab/strings.xml index 798670f3..5d824099 100644 --- a/app/src/main/res/values-kab/strings.xml +++ b/app/src/main/res/values-kab/strings.xml @@ -200,5 +200,4 @@ Tinedlisin-agi ttwaseqdacent: Newwi kra n tiktiwin akked tengat si LeafPic. Duu ad ten-twaliḍ. D aseɣẓan ilellil! Ini-yid ugar - Mudd diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index f7d5740d..a7989702 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -193,5 +193,4 @@ LeafPic에서 약간의 영감을 받았으며, 코드들도 일부 차용했습니다. 한번 사용해보세요! 무료 소프트웨어 입니다! 더 자세히 보기 - 후원하기 diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index 5d3acae5..19084ead 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -37,5 +37,4 @@ Om Bidragsytere - Doner diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 11172034..41ef2f93 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -204,5 +204,4 @@ Wijzig het thema van uw account Trek om te vernieuwen Trek omlaag op de bovenkant van de pagina om te vernieuwen.\nU moet de app opnieuw opstarten om wijzigingen door te voeren. - Doneer diff --git a/app/src/main/res/values-or/strings.xml b/app/src/main/res/values-or/strings.xml index 5c22a862..91176dc2 100644 --- a/app/src/main/res/values-or/strings.xml +++ b/app/src/main/res/values-or/strings.xml @@ -115,5 +115,4 @@ YouTube ଲିଙ୍କଗୁଡ଼ିକ ଆପଣଙ୍କ ଆକାଉଣ୍ଟର ଥିମ୍ ପରିବର୍ତ୍ତନ କରନ୍ତୁ ସତେଜ କରିବାକୁ ଟାଣନ୍ତୁ - ଦାନ କରନ୍ତୁ diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 6276b52b..520b2632 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -203,5 +203,4 @@ Linki YouTube Zmień motyw konta Pociągnij aby odświeżyć - Wspomóż diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 4a7f49cb..682ddefd 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -174,6 +174,4 @@ Bibliotecas de Terceiros São usadas as seguintes bibliotecas: Conte-me mais - Doar - Você gosta deste projeto? Você quer que ele fica melhor e com problemas corrigidos?\n\nDesenvolver aplicativos e escrever postagens relacionado em blog custa muito tempo! Se você quiser ajudar na continuação do projeto, por favor considere uma pequena doação!\n\nEsse projeto é desenvolvido durante o tempo de lazer, totalmente gratuito e sem propagandas! diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index c4400b01..a0b80c09 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -202,6 +202,4 @@ Altera o tema da sua conta Puxar para atualizar Deslize de cima para baixo para recarregar.\nTem que reiniciar a aplicação para aplicar as alterações. - Donativos - Gosta deste projeto? Deseja ajudar a melhorar a aplicação e a corrigir erros?\n\nO desenvolvimento de aplicações custa-me imenso tempo! Se quiser ajudar a manter o projeto, por favor considere a hipótese de um donativo!\n\nEsta aplicação é desenvolvida durante o meu tempo livre, é completamente livre e não tem anúncios! diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 9eca992b..4aa33db5 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -204,6 +204,4 @@ Изменить тему вашей учётной записи Потяните для обновления Потяните вниз, чтобы обновить страницу.\nВам нужно перезапустить приложение, чтобы изменения вступили в силу. - Поддержать проект - Вам нравится этот проект? Вы хотите поддержать дальнейшие улучшения и исправления ошибок?\n\nРазработка приложений и написание связанных блогов занимает много времени! Если вы хотите помочь проекту продолжить, пожалуйста, рассмотрите возможность небольшого пожертвования!\n\nЭтот проект развивается в свободное время, полностью бесплатно и без рекламы! diff --git a/app/src/main/res/values-sc/strings.xml b/app/src/main/res/values-sc/strings.xml index ae43bce8..d16b663e 100644 --- a/app/src/main/res/values-sc/strings.xml +++ b/app/src/main/res/values-sc/strings.xml @@ -207,6 +207,4 @@ Muda su tema de su contu tuo Tira cara a bassu pro annoare Tira cara a bassu pro annoare sa pàgina.\nDepes torrare a allùghere s\'aplicatzione pro fàghere in modu chi sas modìficas tèngiant efetu. - Dona - T\'agradat custu progetu? Cheres chi bèngiat megioradu e chi sos problemas bèngiant isortos?\n\nS\'isvilupu de aplicatziones e s\'iscritura de publicatziones curreladas in sos blogs pigat unu muntone de tempus! Si cheres agiudare, pro fàghere in modu chi su progetu potzat sighire, pro praghere piga in cunsìderu s\'idea de fàghere una donatzione, fintzas si minore!\n\nCustu progetu est isvilupadu in su tempus lìberu, totu de badas e chene annùntzios publitzitàrios! diff --git a/app/src/main/res/values-si/strings.xml b/app/src/main/res/values-si/strings.xml index 2187f861..45159998 100644 --- a/app/src/main/res/values-si/strings.xml +++ b/app/src/main/res/values-si/strings.xml @@ -78,5 +78,4 @@ ජීඑන්යූ ජීපීඑල්v3+ බලපත්‍රය යූටියුබ් සබැඳිය - පරිත්‍යාග diff --git a/app/src/main/res/values-sr-rRS/strings.xml b/app/src/main/res/values-sr-rRS/strings.xml index 6d3bf4a2..422fd22e 100644 --- a/app/src/main/res/values-sr-rRS/strings.xml +++ b/app/src/main/res/values-sr-rRS/strings.xml @@ -35,5 +35,4 @@ Pomo\'nici Prikazi GNU GPLv3 licence Prikaz licence trecih lica - Doniraj diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index f85ef840..543f0196 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -37,5 +37,4 @@ Програмери Сарадници - Doniraj diff --git a/app/src/main/res/values-sv/strings.xml b/app/src/main/res/values-sv/strings.xml index 87f418b5..7c42e701 100644 --- a/app/src/main/res/values-sv/strings.xml +++ b/app/src/main/res/values-sv/strings.xml @@ -210,6 +210,4 @@ Ändra temat för ditt konto Dra för att uppdatera Dra ner på toppen av sidan för att uppdatera.\nDu måste starta om appen för att ändringarna ska träda i kraft. - Donera - Gillar du detta projektet? Vill du att det förbättras och att buggar åtgärdas snabbt?\n\nAtt utveckla appar och skriva relaterade blogginlägg tar mycket tid! Om du vill hjälpa till så att projektet kan fortgå så kan du överväga att ge en liten donation!\n\nDetta projektet utvecklas av volontärer på fritiden och är helt utan reklam! diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index dac3bb80..6c40a2c3 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -207,6 +207,4 @@ Hesabınızın temasını değiştirin Yenilemek için çek Yenilemek için sayfanın üst kısmından çekin\nDeğişikliklerin geçerli olması için uygulamayı yeniden başlat. - Bağış yap - Bu projeyi beğendiniz mi? Projenin iyileştirilmesini ve sorunların çözülmesini istiyor musunuz?\n\nUygulama geliştirmek ve onunla ilgili blog gönderileri yazmak çok zaman alıyor! Projenin devam edebilmesi için yardım etmek istiyorsanız, lütfen küçük bir bağış yapmayı düşünün!\n\nBu proje boş zamanlarımda, tamamen ücretsiz ve reklamsız olarak geliştirilmiştir! diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 30da2c28..19fb0794 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -210,6 +210,4 @@ Змінити тему вашого облікового запису Потягніть, щоб оновити Потягніть сторінку згори вниз, щоб оновити.\nВам потрібно перезавантажити застосунок, щоб зміни набрали сили. - Пожертвувати - Вам подобається цей проект? Бажаєте, щоб його покращували й виправляли помилки? \n\nРозробка застосунків та написання пов\'язаних статей у блозі займає багато часу! Якщо ви хочете допомогти цьому проекту розвиватися далі — зробіть маленьке пожертвування!\n\nЦей проект розроблений у вільний час, не містить реклами та є абсолютно безкоштовним! diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 2fd76705..d1b2cd37 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -210,6 +210,4 @@ 更改您的帐户的主题 下拉刷新 在页面顶部下拉刷新。\n您需要重新启动应用程序以使更改生效。 - 捐赠 - 你喜欢这个项目吗?你想要它得到改善并解决问题吗?\n\n开发应用并撰写相关博客文章需要花费大量时间!如果你想要帮助项目继续进行,请考虑小额捐赠!\n\n这个项目是在闲暇时间开发的,完全免费且没有任何广告! diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 7e9d0298..22866bc8 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -205,6 +205,4 @@ 修改帳號的佈景主題 下拉可更新 從頁面的上方下拉一下可以更新內容。\n這個設定修改後需要重啟應用程式才會生效。 - 贊助 - 喜歡這個專案嗎?希望它繼續改善,而且問題得到解決嗎?\n\n無論是開發應用程式,還是撰寫相關部落格文章,都需要很多時間!如果你想要幫助專案持續發展,請考慮給我們小額捐款!\n\n這個專案是在閒暇時間開發的,完全免費,並且沒有任何廣告! diff --git a/app/src/main/res/values/strings-not_translatable.xml b/app/src/main/res/values/strings-not_translatable.xml index b36f4c51..7f67ac27 100644 --- a/app/src/main/res/values/strings-not_translatable.xml +++ b/app/src/main/res/values/strings-not_translatable.xml @@ -13,9 +13,6 @@ Tor HTTP - @string/donate - - @string/new_post @string/search http @@ -40,10 +37,6 @@ not_implemented - @string/not_implemented - @string/not_implemented - @string/not_implemented - @string/not_implemented auto diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0a5905be..78bac4bc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -261,7 +261,4 @@ Pull to refresh Pulling down on top of page to refresh.\nYou need to restart the app for changes to take effect. - Donate - Do you like this project? Do you want that it gets improved and problems fixed?\n\nDeveloping apps and writing related blog posts costs a lot of time! If you want to help so that the project can go on, please consider a small donation!\n\nThis project is developed in leisure time, completely for free and without any advertisements! - diff --git a/metadata/de/full_description.txt b/metadata/de/full_description.txt index b723eddb..5813a487 100644 --- a/metadata/de/full_description.txt +++ b/metadata/de/full_description.txt @@ -19,10 +19,5 @@ Verbessere dein Netzwerk-Erlebnis durch nützliche Features: 🌍 Hinweis: Die App nutzt Androids WebView Komponente um Inhalte von diaspora* Pods in der mobilen Ansicht anzuzeigen. Für fehlende Features frage bitte auf dem diaspora* Bug Tracker. Weitere Informationen: -Projekt Blog | diaspora* FAQ +Project site | diaspora* FAQ -Unterstütze das Projekt: -Übersetze mit Stringlate | Nimm per Matrix and der Diskussion teil | Mitwirkende | Leitfaden zur Mitwirkung -| Unterstütze den Hauptentwickler diff --git a/metadata/en-US/full_description.txt b/metadata/en-US/full_description.txt index 6e6ba779..e1c445bd 100644 --- a/metadata/en-US/full_description.txt +++ b/metadata/en-US/full_description.txt @@ -19,7 +19,4 @@ It adds useful features to your networking experience: 🌍 Notice: The app uses the Android WebView component to display contents of diaspora* pods in the mobile view. For missing features and bugs in mobile view, ask at diaspora* bugtracker. More information: -Project Blog | diaspora* FAQ - -Support the project: -Translate using Stringlate | Join discussion on Matrix | Contribution information | Android Contribution Guide | Support main developer +Project site | diaspora* FAQ From 774c5bec59af7c0d04dee256e16f4ee05f8bcc8c Mon Sep 17 00:00:00 2001 From: Gregor Santner Date: Sat, 11 Feb 2023 03:07:41 +0100 Subject: [PATCH 49/49] Merge dandelion news and FAQ content all into markdown files in the dandelion repository --- .github/ISSUE_TEMPLATE.md | 3 - CHANGELOG.md | 3 +- CONTRIBUTORS.md | 3 +- NEWS.md | 96 +++++++++++++++++++ README.md | 4 +- .../data/DiasporaPodList.java | 2 +- .../data/DiasporaUserProfile.java | 2 +- .../DiasporaUserProfileChangedListener.java | 2 +- .../ui/PodSelectionDialog.java | 2 +- .../diaspora_android/util/AppSettings.java | 2 +- .../dfa/diaspora_android/web/WebHelper.java | 1 - .../opoc/activity/GsFragmentBase.java | 5 +- .../opoc/android/dummy/MenuItemDummy.java | 2 +- .../opoc/android/dummy/TextWatcherDummy.java | 2 +- .../format/markdown/SimpleMarkdownParser.java | 5 +- .../opoc/preference/PropertyBackend.java | 5 +- .../SharedPreferencesPropertyBackend.java | 5 +- .../nonsupport/LanguagePreference.java | 3 +- .../opoc/ui/SearchOrCustomTextDialog.java | 3 +- .../net/gsantner/opoc/util/ActivityUtils.java | 5 +- .../java/net/gsantner/opoc/util/AdBlock.java | 3 +- .../java/net/gsantner/opoc/util/Callback.java | 5 +- .../net/gsantner/opoc/util/ContextUtils.java | 5 +- .../net/gsantner/opoc/util/FileUtils.java | 5 +- .../net/gsantner/opoc/util/NetworkUtils.java | 5 +- .../gsantner/opoc/util/PermissionChecker.java | 5 +- .../net/gsantner/opoc/util/ShareUtil.java | 5 +- app/src/main/res/raw/maintainers.md | 2 +- build.gradle | 7 +- 29 files changed, 135 insertions(+), 62 deletions(-) create mode 100644 NEWS.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index afecfe1a..5ac91667 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -21,7 +21,4 @@ Description: What this is about, what happens and what is expected to happen. What needs to be done for it to happen. If a crash is happening a log is needed. Screenshots or demonstration videos are always helpful too. - - About logging: - https://gsantner.net/android-contribution-guide/?packageid=com.github.dfa.diaspora_android&name=dandelion&web=https://github.com/gsantner/dandelion#logcat --> diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c6c9d68..a5861d19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ### Recent changes -- See [Discussions](https://github.com/gsantner/dandelion/discussions), [Issues](https://github.com/gsantner/dandelion/issues) and [Project website](https://gsantner.net/) to see what is going on. +- See [Discussions](https://github.com/gsantner/dandelion/discussions), [Issues](https://github.com/gsantner/dandelion/issues) and [Project page](https://github.com/gsantner/dandelion#readme) to see what is going on. ### v1.4.0 - Add seconds to 'save picture' date format @@ -23,7 +23,6 @@ **New features:** - All new Aspects and Tags, using a searchable dialog -- A new home - project blog/page: **Fixed:** - Sometimes the Stream went white, which is due an still (>3 years) unfixed Android Support library bug. It should not occur very often anymore due less use of fragments. diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 2ab0dd4c..16e6a136 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,6 +1,5 @@ -* **[Gregor Santner](http://gsantner.net)**
~° Current developer of dandelion +* **[Gregor Santner](http://github.com/gsantner)**
~° Development of dandelion * **[Paul Schaub](https://github.com/vanitasvitae)**
~° Development of dandelion * **[Martín Vukovic](martinvukovic AT protonmail DOT com)**
~° Diaspora Native WebApp * **[Gaukler Faun](https://github.com/scoute-dich)**
~° Diaspora Native WebApp additions diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 00000000..6139d132 --- /dev/null +++ b/NEWS.md @@ -0,0 +1,96 @@ +# dandelion - News + +## General + +### Installation +You can install and update from [F-Droid](https://f-droid.org/repository/browse/?fdid=com.github.dfa.diaspora_android) or [GitHub](https://github.com/gsantner/dandelion/releases/latest). + +F-Droid is a store for free & open source apps. +The *.apk's available for download are signed by the F-Droid team and guaranteed to correspond to the (open source) source code of dandelion. +Generally this is the recommended way to install dandelion & keep it updated. + + +### Get informed +* Check the [project readme](https://github.com/gsantner/dandelion/tree/news#readme) for general project information. +* Check the [project news](https://github.com/gsantner/dandelion/blob/master/NEWS.md#readme) for more details on what is going on. +* Check the [project git history](https://github.com/gsantner/dandelion/commits/master) for most recent code changes. + +### The right place to ask +If you have questions or found an issue please head to the [dandelion project](https://github.com/gsantner/dandelion/issues/new/choose) and ask there. +[Search](https://github.com/gsantner/dandelion/issues?q=#js-issues-search) for same/similar and related issues/questions before, it might be already answered or resolved. + + +### Navigation +* [dandelion v1.2 - Add dandelior - Searchable Tags and Aspects](#dandelion-v12---add-dandelior---searchable-tags-and-aspects) +* [dandelion v0.1.2 - Aspekte, Pod wechseln](#dandelion-v012---aspekte-pod-wechseln) + + + + + + + + + +------------------------------------------------------------------------------------------------------------------------------------ + +------------------------------------------------------------------------------------------------------------------------------------ + +------------------------------------------------------------------------------------------------------------------------------------ + + +# dandelion\* v1.2 - Add dandelior\* - Searchable Tags and Aspects +_12. August 2018_ + +## dandelior\* is a rebranded version of dandelion\* +dandelior\* is based 100% on the same code and resources as dandelion\*. Its from the same code repository, just a different build flavor. +The main purpose of dandelior\* is the most requested feature till date - to support multiple accounts / another account at dandelion\*. + +- Added an (rebranded) flavor of dandelion: dandelior +- Only differenties in use are other (black) icon and AMOLED colors by default enabled +- Already available on F-Droid + +**New features:** +- All new Aspects and Tags, using a searchable dialog + +**Fixed:** +- Sometimes the Stream went white, which is due an still (3+ years) unfixed Android Support library bug. It should not occur very often anymore due less use of fragments. + +**Improved:** +- Various small tweaks +- Updated translation files + + + + + + + + + +------------------------------------------------------------------------------------------------------------------------------------ + +------------------------------------------------------------------------------------------------------------------------------------ + +------------------------------------------------------------------------------------------------------------------------------------ + + +# dandelion v0.1.2 - Aspekte, Pod wechseln +_05. Juni 2016_ + +In den letzten Tagen hat @gsantner viel Zeit in die inoffizielle diaspora\* Android App ([dandelion\*](https://github.com/gsantner/dandelion)) investiert. + +Dabei wurden unter anderem folgende Änderungen beigesteuert: + +- Allgemeines zur Usability +- Animationen für den Activity-Wechsel und Startup, WebView-Scroll-Top +- Podliste caching +- Aspekt-Liste und Aspekte hinzugefügt +- Verbessertes Sharing aus der App +- Material Progressbar +- Suche verbessert +- Collapsing top menu +- toolbar/actions/menu geändert, fab entfernt +- Refactoring layout & menu files, dialogs +- Überarbeitete Main,Splash,PodSelectionActivity +- Pod wechseln diff --git a/README.md b/README.md index c0faf4c3..a061ee60 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,9 @@ dandelion\* requires access to the Internet and to external storage to be able t ## Contributions The project is always open for contributions and accepts pull requests. -The project uses [AOSP Java Code Style](https://source.android.com/source/code-style#follow-field-naming-conventions), with one exception: private members are `_camelCase` instead of `mBigCamel`. You may use Android Studios _auto reformat feature_ before sending a PR. See [gsantner's android contribution guide](https://gsantner.net/android-contribution-guide/?packageid=com.github.dfa.diaspora_android&name=dandelion&web=https://github.com/gsantner/dandelion&source=readme#logcat) for more information. +The project uses [AOSP Java Code Style](https://source.android.com/source/code-style#follow-field-naming-conventions), with one exception: private members are `_camelCase` instead of `mBigCamel`. You may use Android Studios _auto reformat feature_ before sending a PR. -Translations can be contributed on GitHub or via [E-Mail](https://gsantner.net/#contact). You can use Stringlate ([![Translate - with Stringlate](https://img.shields.io/badge/stringlate-translate-green.svg)](https://lonamiwebs.github.io/stringlate/translate?git=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion.git)) to translate the project directly on your Android phone. It allows you to export as E-Mail attachement and to post on GitHub. +Translations can be contributed on GitHub. You can use Stringlate ([![Translate - with Stringlate](https://img.shields.io/badge/stringlate-translate-green.svg)](https://lonamiwebs.github.io/stringlate/translate?git=https%3A%2F%2Fgithub.com%2Fgsantner%2Fdandelion.git)) to translate the project directly on your Android phone. It allows you to export as E-Mail attachement and to post on GitHub. Join our Matrix channel and say hello! Don't be afraid to start talking. [![Chat - Matrix](https://img.shields.io/badge/chat-on%20matrix-blue.svg)](https://matrix.to/#/#dandelion:matrix.org) Note that the main project members are working on this project for free during leisure time, are mostly busy with their job/university/school, and may not react or start coding immediately. diff --git a/app/src/main/java/com/github/dfa/diaspora_android/data/DiasporaPodList.java b/app/src/main/java/com/github/dfa/diaspora_android/data/DiasporaPodList.java index e0fa9955..3052ea77 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/data/DiasporaPodList.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/data/DiasporaPodList.java @@ -13,7 +13,7 @@ import java.util.List; /** - * Created by gsantner (https://gsantner.net/ on 30.09.16. + * Created by gsantner (gsantner AT mailbox DOT org on 30.09.16. * DiasporaPodList - List container for DiasporaPod's, with methods to merge with other DiasporaPodLists * DiasporaPod - Data container for a Pod, can include N DiasporaPodUrl's * DiasporaPodUrl - A Url of an DiasporaPod diff --git a/app/src/main/java/com/github/dfa/diaspora_android/data/DiasporaUserProfile.java b/app/src/main/java/com/github/dfa/diaspora_android/data/DiasporaUserProfile.java index e54b351a..22efea59 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/data/DiasporaUserProfile.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/data/DiasporaUserProfile.java @@ -32,7 +32,7 @@ import org.json.JSONObject; /** * User profile - * Created by gsantner (https://gsantner.net/) on 24.03.16. Part of dandelion*. + * Created by gsantner (gsantner AT mailbox DOT org) on 24.03.16. Part of dandelion*. */ public class DiasporaUserProfile { private static final int MINIMUM_USERPROFILE_LOAD_TIMEDIFF = 5000; diff --git a/app/src/main/java/com/github/dfa/diaspora_android/listener/DiasporaUserProfileChangedListener.java b/app/src/main/java/com/github/dfa/diaspora_android/listener/DiasporaUserProfileChangedListener.java index 644612c4..dc1b67dc 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/listener/DiasporaUserProfileChangedListener.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/listener/DiasporaUserProfileChangedListener.java @@ -21,7 +21,7 @@ package com.github.dfa.diaspora_android.listener; import com.github.dfa.diaspora_android.data.DiasporaUserProfile; /** - * Created by gsantner (https://gsantner.net/) on 26.03.16. + * Created by gsantner (gsantner AT mailbox DOT org) on 26.03.16. * Interface that needs to be implemented by classes that listen for Profile related changes */ public interface DiasporaUserProfileChangedListener { diff --git a/app/src/main/java/com/github/dfa/diaspora_android/ui/PodSelectionDialog.java b/app/src/main/java/com/github/dfa/diaspora_android/ui/PodSelectionDialog.java index aa885038..abb31703 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/ui/PodSelectionDialog.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/ui/PodSelectionDialog.java @@ -37,7 +37,7 @@ import butterknife.OnItemSelected; /** * Dialog that helps the user configure a pod - * Created by gsantner (http://gsantner.net) on 06.10.16. + * Created by gsantner on 06.10.16. */ public class PodSelectionDialog extends ThemedAppCompatDialogFragment { public static final String TAG = "com.github.dfa.diaspora_android.ui.PodSelectionDialog"; diff --git a/app/src/main/java/com/github/dfa/diaspora_android/util/AppSettings.java b/app/src/main/java/com/github/dfa/diaspora_android/util/AppSettings.java index d1a48f03..1ced82bb 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/util/AppSettings.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/util/AppSettings.java @@ -37,7 +37,7 @@ import java.util.List; /** * Settings - * Created by gsantner (https://gsantner.net/) on 20.03.16. Part of dandelion*. + * Created by gsantner (gsantner AT mailbox DOT org) on 20.03.16. Part of dandelion*. */ @SuppressWarnings("ConstantConditions") public class AppSettings extends SharedPreferencesPropertyBackend { diff --git a/app/src/main/java/com/github/dfa/diaspora_android/web/WebHelper.java b/app/src/main/java/com/github/dfa/diaspora_android/web/WebHelper.java index 44cf8ad3..49d10340 100644 --- a/app/src/main/java/com/github/dfa/diaspora_android/web/WebHelper.java +++ b/app/src/main/java/com/github/dfa/diaspora_android/web/WebHelper.java @@ -32,7 +32,6 @@ import com.github.dfa.diaspora_android.activity.MainActivity; /** * Created by Gregor Santner on 07.08.16. - * http://gsantner.net */ public class WebHelper { diff --git a/app/src/main/java/net/gsantner/opoc/activity/GsFragmentBase.java b/app/src/main/java/net/gsantner/opoc/activity/GsFragmentBase.java index efaf4f77..479551d9 100644 --- a/app/src/main/java/net/gsantner/opoc/activity/GsFragmentBase.java +++ b/app/src/main/java/net/gsantner/opoc/activity/GsFragmentBase.java @@ -1,9 +1,8 @@ /*####################################################### * - * Maintained by Gregor Santner, 2017- - * https://gsantner.net/ + * Maintained 2017-2023 by Gregor Santner * - * License: Apache 2.0 / Commercial + * License: Apache 2.0 * https://github.com/gsantner/opoc/#licensing * https://www.apache.org/licenses/LICENSE-2.0 * diff --git a/app/src/main/java/net/gsantner/opoc/android/dummy/MenuItemDummy.java b/app/src/main/java/net/gsantner/opoc/android/dummy/MenuItemDummy.java index a222ab07..5d3b5f97 100644 --- a/app/src/main/java/net/gsantner/opoc/android/dummy/MenuItemDummy.java +++ b/app/src/main/java/net/gsantner/opoc/android/dummy/MenuItemDummy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Gregor Santner + * Maintained 2017-2023 by Gregor Santner * License: Creative Commons Zero (CC0 1.0) / Public Domain * http://creativecommons.org/publicdomain/zero/1.0/ * diff --git a/app/src/main/java/net/gsantner/opoc/android/dummy/TextWatcherDummy.java b/app/src/main/java/net/gsantner/opoc/android/dummy/TextWatcherDummy.java index a21bf1f3..e6a5ea94 100644 --- a/app/src/main/java/net/gsantner/opoc/android/dummy/TextWatcherDummy.java +++ b/app/src/main/java/net/gsantner/opoc/android/dummy/TextWatcherDummy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Gregor Santner + * Maintained 2017-2023 by Gregor Santner * License: Creative Commons Zero (CC0 1.0) / Public Domain * http://creativecommons.org/publicdomain/zero/1.0/ * diff --git a/app/src/main/java/net/gsantner/opoc/format/markdown/SimpleMarkdownParser.java b/app/src/main/java/net/gsantner/opoc/format/markdown/SimpleMarkdownParser.java index 91d666ce..ea117a8a 100644 --- a/app/src/main/java/net/gsantner/opoc/format/markdown/SimpleMarkdownParser.java +++ b/app/src/main/java/net/gsantner/opoc/format/markdown/SimpleMarkdownParser.java @@ -1,9 +1,8 @@ /*####################################################### * - * Maintained by Gregor Santner, 2018- - * https://gsantner.net/ + * Maintained 2018-2023 by Gregor Santner * - * License: Apache 2.0 / Commercial + * License: Apache 2.0 * https://github.com/gsantner/opoc/#licensing * https://www.apache.org/licenses/LICENSE-2.0 * diff --git a/app/src/main/java/net/gsantner/opoc/preference/PropertyBackend.java b/app/src/main/java/net/gsantner/opoc/preference/PropertyBackend.java index 0847021b..f96af499 100644 --- a/app/src/main/java/net/gsantner/opoc/preference/PropertyBackend.java +++ b/app/src/main/java/net/gsantner/opoc/preference/PropertyBackend.java @@ -1,9 +1,8 @@ /*####################################################### * - * Maintained by Gregor Santner, 2018- - * https://gsantner.net/ + * Maintained 2018-2023 by Gregor Santner * - * License: Apache 2.0 / Commercial + * License: Apache 2.0 * https://github.com/gsantner/opoc/#licensing * https://www.apache.org/licenses/LICENSE-2.0 * diff --git a/app/src/main/java/net/gsantner/opoc/preference/SharedPreferencesPropertyBackend.java b/app/src/main/java/net/gsantner/opoc/preference/SharedPreferencesPropertyBackend.java index 64e7596c..9f5c948c 100644 --- a/app/src/main/java/net/gsantner/opoc/preference/SharedPreferencesPropertyBackend.java +++ b/app/src/main/java/net/gsantner/opoc/preference/SharedPreferencesPropertyBackend.java @@ -1,9 +1,8 @@ /*####################################################### * - * Maintained by Gregor Santner, 2016- - * https://gsantner.net/ + * Maintained 2016-2023 by Gregor Santner * - * License: Apache 2.0 / Commercial + * License: Apache 2.0 * https://github.com/gsantner/opoc/#licensing * https://www.apache.org/licenses/LICENSE-2.0 * diff --git a/app/src/main/java/net/gsantner/opoc/preference/nonsupport/LanguagePreference.java b/app/src/main/java/net/gsantner/opoc/preference/nonsupport/LanguagePreference.java index 76284a11..04c3be4f 100644 --- a/app/src/main/java/net/gsantner/opoc/preference/nonsupport/LanguagePreference.java +++ b/app/src/main/java/net/gsantner/opoc/preference/nonsupport/LanguagePreference.java @@ -1,7 +1,6 @@ /*####################################################### * - * Maintained by Gregor Santner, 2017- - * https://gsantner.net/ + * Maintained 2017-2023 by Gregor Santner * * License: Apache 2.0 * https://github.com/gsantner/opoc/#licensing diff --git a/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java b/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java index 27197d2e..cc703f98 100644 --- a/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java +++ b/app/src/main/java/net/gsantner/opoc/ui/SearchOrCustomTextDialog.java @@ -1,7 +1,6 @@ /*####################################################### * - * Maintained by Gregor Santner, 2017- - * https://gsantner.net/ + * Maintained 2017-2023 by Gregor Santner * * License: Apache 2.0 * https://github.com/gsantner/opoc/#licensing diff --git a/app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java b/app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java index 08da999a..741b3b76 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/ActivityUtils.java @@ -1,9 +1,8 @@ /*####################################################### * - * Maintained by Gregor Santner, 2016- - * https://gsantner.net/ + * Maintained 2016-2023 by Gregor Santner * - * License of this file: Apache 2.0 (Commercial upon request) + * License of this file: Apache 2.0 * https://www.apache.org/licenses/LICENSE-2.0 * https://github.com/gsantner/opoc/#licensing * diff --git a/app/src/main/java/net/gsantner/opoc/util/AdBlock.java b/app/src/main/java/net/gsantner/opoc/util/AdBlock.java index 5045d0f2..c5c81678 100644 --- a/app/src/main/java/net/gsantner/opoc/util/AdBlock.java +++ b/app/src/main/java/net/gsantner/opoc/util/AdBlock.java @@ -1,7 +1,6 @@ /*####################################################### * - * Maintained by Gregor Santner, 2017- - * https://gsantner.net/ + * Maintained 2017-2023 by Gregor Santner * * License: Apache 2.0 * https://github.com/gsantner/opoc/#licensing diff --git a/app/src/main/java/net/gsantner/opoc/util/Callback.java b/app/src/main/java/net/gsantner/opoc/util/Callback.java index 640b5cce..012cb634 100644 --- a/app/src/main/java/net/gsantner/opoc/util/Callback.java +++ b/app/src/main/java/net/gsantner/opoc/util/Callback.java @@ -1,9 +1,8 @@ /*####################################################### * - * Maintained by Gregor Santner, 2018- - * https://gsantner.net/ + * Maintained 2018-2023 by Gregor Santner * - * License of this file: Apache 2.0 (Commercial upon request) + * License of this file: Apache 2.0 * https://www.apache.org/licenses/LICENSE-2.0 * https://github.com/gsantner/opoc/#licensing * diff --git a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java index 5da4f165..483461d8 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/ContextUtils.java @@ -1,9 +1,8 @@ /*####################################################### * - * Maintained by Gregor Santner, 2016- - * https://gsantner.net/ + * Maintained 2016-2023 by Gregor Santner * - * License of this file: Apache 2.0 (Commercial upon request) + * License of this file: Apache 2.0 * https://www.apache.org/licenses/LICENSE-2.0 * https://github.com/gsantner/opoc/#licensing * diff --git a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java index 130021ea..7dbd1658 100644 --- a/app/src/main/java/net/gsantner/opoc/util/FileUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/FileUtils.java @@ -1,9 +1,8 @@ /*####################################################### * - * Maintained by Gregor Santner, 2017- - * https://gsantner.net/ + * Maintained 2017-2023 by Gregor Santner * - * License of this file: Apache 2.0 (Commercial upon request) + * License of this file: Apache 2.0 * https://www.apache.org/licenses/LICENSE-2.0 * https://github.com/gsantner/opoc/#licensing * diff --git a/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java b/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java index 09d6795b..dc06674e 100644 --- a/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/NetworkUtils.java @@ -1,9 +1,8 @@ /*####################################################### * - * Maintained by Gregor Santner, 2017- - * https://gsantner.net/ + * Maintained 2017-2023 by Gregor Santner * - * License of this file: Apache 2.0 (Commercial upon request) + * License of this file: Apache 2.0 * https://www.apache.org/licenses/LICENSE-2.0 * https://github.com/gsantner/opoc/#licensing * diff --git a/app/src/main/java/net/gsantner/opoc/util/PermissionChecker.java b/app/src/main/java/net/gsantner/opoc/util/PermissionChecker.java index 6c0efd72..be156745 100644 --- a/app/src/main/java/net/gsantner/opoc/util/PermissionChecker.java +++ b/app/src/main/java/net/gsantner/opoc/util/PermissionChecker.java @@ -1,9 +1,8 @@ /*####################################################### * - * Maintained by Gregor Santner, 2017- - * https://gsantner.net/ + * Maintained 2017-2023 by Gregor Santner * - * License of this file: Apache 2.0 (Commercial upon request) + * License of this file: Apache 2.0 * https://www.apache.org/licenses/LICENSE-2.0 * https://github.com/gsantner/opoc/#licensing * diff --git a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java index 01bbd468..dc467500 100644 --- a/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java +++ b/app/src/main/java/net/gsantner/opoc/util/ShareUtil.java @@ -1,9 +1,8 @@ /*####################################################### * - * Maintained by Gregor Santner, 2017- - * https://gsantner.net/ + * Maintained 2017-2023 by Gregor Santner * - * License of this file: Apache 2.0 (Commercial upon request) + * License of this file: Apache 2.0 * https://www.apache.org/licenses/LICENSE-2.0 * https://github.com/gsantner/opoc/#licensing * diff --git a/app/src/main/res/raw/maintainers.md b/app/src/main/res/raw/maintainers.md index 999f1073..7b1bc7f9 100644 --- a/app/src/main/res/raw/maintainers.md +++ b/app/src/main/res/raw/maintainers.md @@ -1,5 +1,5 @@ * Gregor Santner (gsantner) -~° http://gsantner.net +~° https://github.com/gsantner * Paul Schaub (vanitasvitae) ~° https://github.com/vanitasvitae diff --git a/build.gradle b/build.gradle index d4722bf0..75a6ed58 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,7 @@ /*####################################################### * - * Maintained by Gregor Santner, 2017- - * https://gsantner.net/ - * - * License of this file: Apache 2.0 (Commercial upon request) - * https://www.apache.org/licenses/LICENSE-2.0 + * SPDX-FileCopyrightText: 2017-2023 Gregor Santner + * SPDX-License-Identifier: Unlicense OR CC0-1.0 * #########################################################*/ // Top-level build file where you can add configuration options common to all sub-projects/modules.