diff --git a/app/build.gradle b/app/build.gradle index acd7bf3355..bb4e528e1c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,8 +25,8 @@ android { defaultConfig { resValue "string", "manifest_package_id", "net.gsantner.markor" applicationId "net.gsantner.markor" - versionName "2.13.0" - versionCode 155 + versionName "2.13.1" + versionCode 156 multiDexEnabled true minSdkVersion rootProject.ext.version_minSdk diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentActivity.java b/app/src/main/java/net/gsantner/markor/activity/DocumentActivity.java index fd563564b9..4dfc8bc2ed 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentActivity.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentActivity.java @@ -16,6 +16,7 @@ import android.os.Build; import android.os.Bundle; import android.text.Html; +import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; @@ -95,8 +96,8 @@ private static void launch( intent = new Intent(activity, DocumentActivity.class); if (!(activity instanceof DocumentActivity) && - Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && - as.isMultiWindowEnabled() + Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && + as.isMultiWindowEnabled() ) { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); } @@ -254,7 +255,8 @@ public boolean dispatchTouchEvent(MotionEvent event) { } try { return super.dispatchTouchEvent(event); - } catch (IndexOutOfBoundsException ignored) { + } catch (Exception e) { + Log.e(getClass().getName(), "Error in super.dispatchTouchEvent: " + e); return false; } } diff --git a/app/src/main/java/net/gsantner/markor/activity/DocumentShareIntoFragment.java b/app/src/main/java/net/gsantner/markor/activity/DocumentShareIntoFragment.java index 4a688fbb7e..73c1a3e480 100644 --- a/app/src/main/java/net/gsantner/markor/activity/DocumentShareIntoFragment.java +++ b/app/src/main/java/net/gsantner/markor/activity/DocumentShareIntoFragment.java @@ -375,7 +375,7 @@ private String formatShare(final String shared) { } // Put the shared text in the right place - parts.add(1, shared); + parts.add(parts.isEmpty() ? 0 : 1, shared); return TextUtils.join("", parts); } diff --git a/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java b/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java index 39a452ecfa..f29d2eed17 100644 --- a/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java +++ b/app/src/main/java/net/gsantner/markor/frontend/textview/HighlightingEditor.java @@ -18,10 +18,12 @@ import android.text.Layout; import android.text.TextWatcher; import android.util.AttributeSet; +import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityEvent; +import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; @@ -37,6 +39,7 @@ import java.util.Objects; import java.util.concurrent.ExecutorService; +import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -118,6 +121,13 @@ public boolean onPreDraw() { @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); + try { + super.onDraw(canvas); + } catch (Exception e) { + // Hinder drawing from crashing the app + Log.e(getClass().getName(), "HighlightingEdtior onDraw->super.onDraw crash" + e); + Toast.makeText(getContext(), e.toString(), Toast.LENGTH_SHORT).show(); + } } // Highlighting @@ -173,7 +183,10 @@ public void recomputeHighlighting() { */ private void recomputeHighlightingAsync() { if (runHighlight(true)) { - executor.execute(this::_recomputeHighlightingWorker); + try { + executor.execute(this::_recomputeHighlightingWorker); + } catch (RejectedExecutionException ignored) { + } } } @@ -262,14 +275,12 @@ public boolean bringPointIntoView(int i) { private int rowStart(final int y) { final Layout layout = getLayout(); - final int line = layout.getLineForVertical(y); - return layout.getLineStart(line); + return layout == null ? 0 : layout.getLineStart(layout.getLineForVertical(y)); } private int rowEnd(final int y) { final Layout layout = getLayout(); - final int line = layout.getLineForVertical(y); - return layout.getLineEnd(line); + return layout == null ? 0 : layout.getLineEnd(layout.getLineForVertical(y)); } // Text-Casing @@ -371,7 +382,12 @@ public boolean onTextContextMenuItem(int id) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && id == android.R.id.paste) { id = android.R.id.pasteAsPlainText; } - return super.onTextContextMenuItem(id); + try { + // i.e. DeadSystemRuntimeException can happen here + return super.onTextContextMenuItem(id); + } catch (Exception ignored) { + return true; + } } // Accessibility code is blocked during rapid update events diff --git a/app/src/main/java/net/gsantner/markor/model/AppSettings.java b/app/src/main/java/net/gsantner/markor/model/AppSettings.java index 7c83c5095f..f354681012 100644 --- a/app/src/main/java/net/gsantner/markor/model/AppSettings.java +++ b/app/src/main/java/net/gsantner/markor/model/AppSettings.java @@ -855,7 +855,7 @@ public boolean isExperimentalFeaturesEnabled() { } public boolean isHighlightBiggerHeadings() { - return getBool(R.string.pref_key__editor_markdown_bigger_headings_2, false); + return getBool(R.string.pref_key__editor_markdown_bigger_headings_3, false); } public String getViewModeLinkColor() { diff --git a/app/src/main/java/net/gsantner/opoc/frontend/filebrowser/GsFileBrowserListAdapter.java b/app/src/main/java/net/gsantner/opoc/frontend/filebrowser/GsFileBrowserListAdapter.java index d0b030c9fc..8cccb29124 100644 --- a/app/src/main/java/net/gsantner/opoc/frontend/filebrowser/GsFileBrowserListAdapter.java +++ b/app/src/main/java/net/gsantner/opoc/frontend/filebrowser/GsFileBrowserListAdapter.java @@ -151,7 +151,7 @@ public Map getVirtualFolders() { } for (final File file : ContextCompat.getExternalFilesDirs(_context, null)) { - if (file == null || file.getParentFile() == null) { + if (file == null || (file != null && file.getParentFile() == null)) { continue; } final File remap = new File(VIRTUAL_STORAGE_ROOT, "AppData (" + file.getParentFile().toString().replace("/", "-").substring(1) + ")"); diff --git a/app/src/main/java/net/gsantner/opoc/frontend/textview/TextViewUndoRedo.java b/app/src/main/java/net/gsantner/opoc/frontend/textview/TextViewUndoRedo.java index 9a4f6c254b..f90325092f 100644 --- a/app/src/main/java/net/gsantner/opoc/frontend/textview/TextViewUndoRedo.java +++ b/app/src/main/java/net/gsantner/opoc/frontend/textview/TextViewUndoRedo.java @@ -43,7 +43,9 @@ public void onClick(View v) { import android.text.Selection; import android.text.TextWatcher; import android.text.style.UnderlineSpan; +import android.util.Log; import android.widget.TextView; +import android.widget.Toast; import net.gsantner.markor.frontend.textview.TextViewUtils; @@ -150,8 +152,10 @@ public void undo() { mIsUndoOrRedo = true; try { text.replace(start, end, edit.before); - } catch (Exception ex){ + } catch (Exception ex) { // In case a undo would crash the app, don't do it instead + Log.e(getClass().getName(), "undo() Error in text.replace" + ex); + Toast.makeText(mTextView.getContext(), "undo() Error in text.replace" + ex, Toast.LENGTH_LONG).show(); return; } mIsUndoOrRedo = false; diff --git a/app/src/main/java/net/gsantner/opoc/util/GsContextUtils.java b/app/src/main/java/net/gsantner/opoc/util/GsContextUtils.java index c243af4224..7bff4dad0c 100644 --- a/app/src/main/java/net/gsantner/opoc/util/GsContextUtils.java +++ b/app/src/main/java/net/gsantner/opoc/util/GsContextUtils.java @@ -1861,7 +1861,7 @@ public void extractResultFromActivityResult(final Activity context, final int re if (resultCode == Activity.RESULT_OK && intent != null && intent.getData() != null) { final Uri uri = intent.getData(); final String uriPath = uri.getPath(); - final String ext = uriPath.substring(uriPath.lastIndexOf(".")); + final String ext = uriPath == null || !uriPath.contains(".") ? "" : uriPath.substring(uriPath.lastIndexOf(".")); final String datestr = new SimpleDateFormat("yyyy-MM-dd'T'HH-mm-ss", Locale.ENGLISH).format(new Date()); final File temp = new File(context.getCacheDir(), datestr + ext); GsFileUtils.copyUriToFile(context, uri, temp); @@ -2743,12 +2743,12 @@ public void dialogFullWidth(AlertDialog dialog, boolean fullWidth, boolean showK } public static void windowAspectRatio( - final Window window, - final DisplayMetrics displayMetrics, - float portraitWidthRatio, - float portraitHeightRatio, - float landscapeWidthRatio, - float landscapeHeightRatio + final Window window, + final DisplayMetrics displayMetrics, + float portraitWidthRatio, + float portraitHeightRatio, + float landscapeWidthRatio, + float landscapeHeightRatio ) { if (window == null) { return; diff --git a/app/src/main/res/values/string-not_translatable.xml b/app/src/main/res/values/string-not_translatable.xml index b94b958639..1c54aad0aa 100644 --- a/app/src/main/res/values/string-not_translatable.xml +++ b/app/src/main/res/values/string-not_translatable.xml @@ -180,7 +180,7 @@ work. If not, see . pref_key__editor_disable_spelling_red_underline pref_key__highlight_code_monospace_font pref_key__highlight_code_block_disabled - pref_key__editor_markdown_bigger_headings_2 + pref_key__editor_markdown_bigger_headings_3 pref_key__editor_unordered_list_character pref_key__recent_documents pref_key__popular_documents diff --git a/app/src/main/res/xml/preferences_master.xml b/app/src/main/res/xml/preferences_master.xml index 8fc6e6e26d..dbc0522597 100644 --- a/app/src/main/res/xml/preferences_master.xml +++ b/app/src/main/res/xml/preferences_master.xml @@ -340,7 +340,7 @@ diff --git a/metadata/en-US/full_description.txt b/metadata/en-US/full_description.txt index b4221a5c9c..7266c8c513 100644 --- a/metadata/en-US/full_description.txt +++ b/metadata/en-US/full_description.txt @@ -17,9 +17,9 @@ 👌 No ads or unnecessary permissions 🌎 Language selection -- use other language than on the system -💡 Unlike other office suites (like LibreOffice) or to-do apps (like Wunderlist), Markor has one streamlined text editor with no other editing UI. Markor shows how powerful and expressive simple text can be. View, edit, manipulate and convert plaintext! +💡 Unlike other office suites (like LibreOffice) or to-do apps (like Wunderlist), Markor has one streamlined text editor with no other editing UI. Markor shows how powerful and expressive simple text can be. View, edit, manipulate and convert plaintext! -🔃 Markor works with sync apps, but they have to do syncing respectively. Sync clients known to work in combination include BitTorrent Sync, Dropbox, FolderSync, OwnCloud, NextCloud, Seafile, Syncthing, Syncopoli +🔃 Markor works with sync apps, but they have to do syncing respectively. Sync clients known to work in combination include BitTorrent Sync, Dropbox, FolderSync, OwnCloud, NextCloud, Seafile, Syncthing, Syncopoli 👀 These apps may also be in your interest if you like Markor: OneNote, EverNote, Google Keep, Wunderlist, Read-It-Later, Pocket, Epsilon Notes, iA Writer, Todoist, Shaarli, Wallabag, Simple Notes, Simpletask, Share to clipboard, NextCloud Bookmarks, Easy Open Link