Skip to content

Commit ccb2c6a

Browse files
harshad1gsantner
andauthored
Improve text rendering performance, closes #2478, closes #2515 (#2509)
* Invisible instead of gone * Fixes * tweaks * Fixed states * Tweak to wrap state * Fixed scroll to cursor * File search perf and all files * Window options * Fixes, using compat * Reverted changes to file search * Undo file loads * Improving layout further * Fix dialog title * Switching to -1, pulling fixes * Fixed issues with last line * reformat code --------- Co-authored-by: Gregor Santner <[email protected]>
1 parent 9ce07cd commit ccb2c6a

20 files changed

+168
-161
lines changed

app/src/main/java/net/gsantner/markor/activity/DocumentActivity.java

+2-4
Original file line numberDiff line numberDiff line change
@@ -198,12 +198,10 @@ private void handleLaunchingIntent(final Intent intent) {
198198
final Document doc = new Document(file);
199199
Integer startLine = null;
200200
if (intent.hasExtra(Document.EXTRA_FILE_LINE_NUMBER)) {
201-
startLine = intent.getIntExtra(Document.EXTRA_FILE_LINE_NUMBER, Document.EXTRA_FILE_LINE_NUMBER_LAST);
201+
startLine = intent.getIntExtra(Document.EXTRA_FILE_LINE_NUMBER, -1);
202202
} else if (intentData != null) {
203203
final String line = intentData.getQueryParameter("line");
204-
if (line != null) {
205-
startLine = GsTextUtils.tryParseInt(line, -1);
206-
}
204+
startLine = GsTextUtils.tryParseInt(line, -1);
207205
}
208206

209207
// Start in a specific mode if required. Otherwise let the fragment decide

app/src/main/java/net/gsantner/markor/activity/DocumentEditAndViewFragment.java

+52-70
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import android.annotation.SuppressLint;
1111
import android.app.Activity;
1212
import android.content.Context;
13-
import android.content.Intent;
1413
import android.graphics.Bitmap;
1514
import android.graphics.Color;
1615
import android.graphics.Typeface;
@@ -33,7 +32,6 @@
3332
import android.webkit.JavascriptInterface;
3433
import android.webkit.WebSettings;
3534
import android.webkit.WebView;
36-
import android.widget.FrameLayout;
3735
import android.widget.HorizontalScrollView;
3836
import android.widget.SearchView;
3937
import android.widget.Toast;
@@ -93,11 +91,11 @@ public static DocumentEditAndViewFragment newInstance(final @NonNull Document do
9391
private HighlightingEditor _hlEditor;
9492
private WebView _webView;
9593
private MarkorWebViewClient _webViewClient;
96-
private FrameLayout _editorHolder;
94+
private ViewGroup _editorHolder;
9795
private ViewGroup _textActionsBar;
9896

99-
private DraggableScrollbarScrollView _primaryScrollView;
100-
private HorizontalScrollView _hsView;
97+
private DraggableScrollbarScrollView _verticalScrollView;
98+
private HorizontalScrollView _horizontalScrollView;
10199
private LineNumbersTextView _lineNumbersView;
102100
private SearchView _menuSearchViewForViewMode;
103101
private Document _document;
@@ -108,7 +106,6 @@ public static DocumentEditAndViewFragment newInstance(final @NonNull Document do
108106
private boolean _isPreviewVisible;
109107
private boolean _nextConvertToPrintMode = false;
110108

111-
112109
public DocumentEditAndViewFragment() {
113110
super();
114111
}
@@ -139,10 +136,10 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
139136
_editorHolder = view.findViewById(R.id.document__fragment__edit__editor_holder);
140137
_textActionsBar = view.findViewById(R.id.document__fragment__edit__text_actions_bar);
141138
_webView = view.findViewById(R.id.document__fragment_view_webview);
142-
_primaryScrollView = view.findViewById(R.id.document__fragment__edit__content_editor__scrolling_parent);
139+
_verticalScrollView = view.findViewById(R.id.document__fragment__edit__content_editor__scrolling_parent);
143140
_lineNumbersView = view.findViewById(R.id.document__fragment__edit__line_numbers_view);
144-
145141
_cu = new MarkorContextUtils(activity);
142+
_editTextUndoRedoHelper = new TextViewUndoRedo();
146143

147144
// Using `if (_document != null)` everywhere is dangerous
148145
// It may cause reads or writes to _silently fail_
@@ -203,7 +200,7 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
203200
setViewModeVisibility(startInPreview, false);
204201
}
205202

206-
// Configure the editor. Doing so after load helps prevent some errors
203+
// Configure the editor
207204
// ---------------------------------------------------------
208205
_hlEditor.setLineSpacing(0, _appSettings.getEditorLineSpacing());
209206
_hlEditor.setTextSize(TypedValue.COMPLEX_UNIT_SP, _appSettings.getDocumentFontSize(_document.path));
@@ -213,23 +210,19 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
213210
_hlEditor.setGravity(_appSettings.isEditorStartEditingInCenter() ? Gravity.CENTER : Gravity.NO_GRAVITY);
214211
_hlEditor.setHighlightingEnabled(_appSettings.getDocumentHighlightState(_document.path, _hlEditor.getText()));
215212
_hlEditor.setAutoFormatEnabled(_appSettings.getDocumentAutoFormatEnabled(_document.path));
213+
_hlEditor.setSaveInstanceState(false); // We will reload from disk
214+
_hlEditor.setOverScrollMode(View.OVER_SCROLL_ALWAYS);
216215
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
217216
// Do not need to send contents to accessibility
218217
_hlEditor.setImportantForAccessibility(View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS);
219218
}
220219

221220
// Various settings
222-
setHorizontalScrollMode(isDisplayedAtMainActivity() || _appSettings.getDocumentWrapState(_document.path));
221+
setWrapState(isDisplayedAtMainActivity() || _appSettings.getDocumentWrapState(_document.path));
223222
updateMenuToggleStates(0);
224-
// ---------------------------------------------------------
225223

226-
_hlEditor.setSaveInstanceState(false); // We will reload from disk
227-
_document.resetChangeTracking(); // Force next reload
228-
loadDocument();
229-
// If not set the undo-redo helper by loadDocument, set it here
230-
if (_editTextUndoRedoHelper == null) {
231-
_editTextUndoRedoHelper = new TextViewUndoRedo(_hlEditor);
232-
}
224+
// ---------------------------------------------------------
225+
_document.resetChangeTracking(); // Force next reload in onResume
233226

234227
final Runnable debounced = TextViewUtils.makeDebounced(500, () -> {
235228
checkTextChangeState();
@@ -263,27 +256,30 @@ public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
263256
@Override
264257
protected void onFragmentFirstTimeVisible() {
265258
final Bundle args = getArguments();
266-
267259
int startPos = _appSettings.getLastEditPosition(_document.path, _hlEditor.length());
268260
if (args != null && args.containsKey(Document.EXTRA_FILE_LINE_NUMBER)) {
269261
final int lno = args.getInt(Document.EXTRA_FILE_LINE_NUMBER);
270262
if (lno >= 0) {
271263
startPos = TextViewUtils.getIndexFromLineOffset(_hlEditor.getText(), lno, 0);
272-
} else if (lno == Document.EXTRA_FILE_LINE_NUMBER_LAST) {
264+
} else {
273265
startPos = _hlEditor.length();
274266
}
275267
}
276268

277-
_primaryScrollView.invalidate();
278-
// Can affect layout so run before setting scroll position
279-
_hlEditor.recomputeHighlighting();
269+
_hlEditor.recomputeHighlighting(); // Run before setting scroll position
280270
TextViewUtils.setSelectionAndShow(_hlEditor, startPos);
271+
272+
_editorHolder.invalidate();
273+
_editorHolder.post(() -> _hlEditor.setMinHeight(_editorHolder.getHeight()));
281274
}
282275

283276
@Override
284277
public void onResume() {
285-
loadDocument();
286278
_webView.onResume();
279+
loadDocument();
280+
if (_editTextUndoRedoHelper != null && _editTextUndoRedoHelper.getTextView() != _hlEditor) {
281+
_editTextUndoRedoHelper.setTextView(_hlEditor);
282+
}
287283
super.onResume();
288284
}
289285

@@ -438,31 +434,15 @@ public boolean loadDocument() {
438434
}
439435

440436
if (!_document.isContentSame(_hlEditor.getText())) {
441-
442-
final int[] sel = TextViewUtils.getSelection(_hlEditor);
443-
sel[0] = Math.min(sel[0], content.length());
444-
sel[1] = Math.min(sel[1], content.length());
445-
446-
if (_editTextUndoRedoHelper != null) {
447-
_editTextUndoRedoHelper.disconnect();
448-
_editTextUndoRedoHelper.clearHistory();
449-
}
450-
451-
_hlEditor.withAutoFormatDisabled(() -> _hlEditor.setText(content));
452-
453-
if (_editTextUndoRedoHelper == null) {
454-
_editTextUndoRedoHelper = new TextViewUndoRedo(_hlEditor);
455-
} else {
456-
_editTextUndoRedoHelper.setTextView(_hlEditor);
457-
}
458-
459-
TextViewUtils.setSelectionAndShow(_hlEditor, sel);
437+
_hlEditor.withAutoFormatDisabled(() -> _hlEditor.setTextKeepState(content));
460438
}
439+
461440
checkTextChangeState();
462441

463442
if (_isPreviewVisible) {
464443
updateViewModeText();
465444
}
445+
466446
return true;
467447
}
468448
return false;
@@ -558,12 +538,12 @@ public boolean onOptionsItemSelected(@NonNull final MenuItem item) {
558538
setViewModeVisibility(true);
559539
Toast.makeText(activity, R.string.please_wait, Toast.LENGTH_LONG).show();
560540
_webView.postDelayed(() -> {
561-
if (item.getItemId() == R.id.action_share_pdf) {
541+
if (itemId == R.id.action_share_pdf) {
562542
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
563543
_cu.printOrCreatePdfFromWebview(_webView, _document, getTextString().contains("beamer\n"));
564544
}
565545
} else {
566-
Bitmap bmp = _cu.getBitmapFromWebView(_webView, item.getItemId() == R.id.action_share_image);
546+
Bitmap bmp = _cu.getBitmapFromWebView(_webView, itemId == R.id.action_share_image);
567547
_cu.shareImage(getContext(), bmp, null);
568548
}
569549
}, 7000);
@@ -619,7 +599,7 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) {
619599
case R.id.action_wrap_words: {
620600
final boolean newState = !isWrapped();
621601
_appSettings.setDocumentWrapState(_document.path, newState);
622-
setHorizontalScrollMode(newState);
602+
setWrapState(newState);
623603
updateMenuToggleStates(0);
624604
return true;
625605
}
@@ -659,10 +639,7 @@ public void onFsViewerConfig(GsFileBrowserOptions.Options dopt) {
659639
}
660640
case R.id.action_show_file_browser: {
661641
// Delay because I want menu to close before we open the file browser
662-
_hlEditor.postDelayed(() -> {
663-
final Intent intent = new Intent(activity, MainActivity.class).putExtra(Document.EXTRA_FILE, _document.file);
664-
GsContextUtils.instance.animateToActivity(activity, intent, false, null);
665-
}, 250);
642+
_hlEditor.postDelayed(() -> MainActivity.launch(activity, _document.file, false), 250);
666643
return true;
667644
}
668645
case R.id.action_toggle_case:
@@ -765,34 +742,39 @@ private void updateMenuToggleStates(final int selectedFormatActionId) {
765742
}
766743

767744
private boolean isWrapped() {
768-
return _hsView == null || (_hlEditor.getParent() == _editorHolder);
745+
return _horizontalScrollView == null || (_hlEditor.getParent() != _horizontalScrollView);
769746
}
770747

771-
private void setHorizontalScrollMode(final boolean wrap) {
748+
private void makeHorizontalScrollView() {
749+
if (_horizontalScrollView != null) {
750+
return;
751+
}
752+
753+
_horizontalScrollView = new HorizontalScrollView(getContext());
754+
_horizontalScrollView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
755+
_horizontalScrollView.setFillViewport(true);
756+
}
757+
758+
private void setWrapState(final boolean wrap) {
772759
final Context context = getContext();
773760
if (context != null && _hlEditor != null && isWrapped() != wrap) {
774761
final int[] sel = TextViewUtils.getSelection(_hlEditor);
775-
final boolean hlEnabled = _hlEditor.getHighlightingEnabled();
776-
_hlEditor.setHighlightingEnabled(false);
762+
final boolean hlEnabled = _hlEditor.setHighlightingEnabled(false);
777763

778-
_editorHolder.removeAllViews();
779-
if (_hsView != null) {
780-
_hsView.removeAllViews();
781-
}
782-
if (!wrap) {
783-
if (_hsView == null) {
784-
_hsView = new HorizontalScrollView(context);
785-
_hsView.setFillViewport(true);
786-
}
787-
_hsView.addView(_hlEditor);
788-
_editorHolder.addView(_hsView);
764+
makeHorizontalScrollView();
765+
766+
if (wrap) {
767+
_horizontalScrollView.removeView(_hlEditor);
768+
_editorHolder.removeView(_horizontalScrollView);
769+
_editorHolder.addView(_hlEditor, 1);
789770
} else {
790-
_editorHolder.addView(_hlEditor);
771+
_editorHolder.removeView(_hlEditor);
772+
_horizontalScrollView.addView(_hlEditor);
773+
_editorHolder.addView(_horizontalScrollView, 1);
791774
}
792775

793776
_hlEditor.setHighlightingEnabled(hlEnabled);
794-
// Run after layout() of immediate parent completes
795-
(wrap ? _editorHolder : _hsView).post(() -> TextViewUtils.setSelectionAndShow(_hlEditor, sel));
777+
_editorHolder.post(() -> TextViewUtils.setSelectionAndShow(_hlEditor, sel));
796778
}
797779
}
798780

@@ -890,10 +872,10 @@ public void setViewModeVisibility(boolean show, final boolean animate) {
890872
_cu.showSoftKeyboard(activity, false, _hlEditor);
891873
_hlEditor.clearFocus();
892874
_hlEditor.postDelayed(() -> _cu.showSoftKeyboard(activity, false, _hlEditor), 300);
893-
GsContextUtils.fadeInOut(_webView, _primaryScrollView, animate);
875+
GsContextUtils.fadeInOut(_webView, _verticalScrollView, animate);
894876
} else {
895877
_webViewClient.setRestoreScrollY(_webView.getScrollY());
896-
GsContextUtils.fadeInOut(_primaryScrollView, _webView, animate);
878+
GsContextUtils.fadeInOut(_verticalScrollView, _webView, animate);
897879
}
898880

899881
_nextConvertToPrintMode = false;

app/src/main/java/net/gsantner/markor/activity/MainActivity.java

+13-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
package net.gsantner.markor.activity;
1010

1111
import android.annotation.SuppressLint;
12+
import android.app.Activity;
1213
import android.app.ActivityManager;
1314
import android.content.Intent;
1415
import android.graphics.Color;
@@ -43,6 +44,7 @@
4344
import net.gsantner.opoc.frontend.filebrowser.GsFileBrowserFragment;
4445
import net.gsantner.opoc.frontend.filebrowser.GsFileBrowserListAdapter;
4546
import net.gsantner.opoc.frontend.filebrowser.GsFileBrowserOptions;
47+
import net.gsantner.opoc.util.GsContextUtils;
4648

4749
import java.io.File;
4850
import java.io.IOException;
@@ -200,6 +202,15 @@ protected void onNewIntent(final Intent intent) {
200202
}
201203
}
202204

205+
public static void launch(final Activity activity, final File file, final boolean finishfromActivity) {
206+
if (activity != null && file != null) {
207+
final Intent intent = new Intent(activity, MainActivity.class);
208+
intent.putExtra(Document.EXTRA_FILE, file);
209+
// intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
210+
GsContextUtils.instance.animateToActivity(activity, intent, finishfromActivity, null);
211+
}
212+
}
213+
203214
private void optShowRate() {
204215
try {
205216
new com.pixplicity.generate.Rate.Builder(this)
@@ -455,9 +466,9 @@ public Fragment createFragment(final int pos) {
455466
final GsFragmentBase<?, ?> frag;
456467
final int id = tabIdFromPos(pos);
457468
if (id == R.id.nav_quicknote) {
458-
frag = _quicknote = DocumentEditAndViewFragment.newInstance(new Document(_appSettings.getQuickNoteFile()), Document.EXTRA_FILE_LINE_NUMBER_LAST, false);
469+
frag = _quicknote = DocumentEditAndViewFragment.newInstance(new Document(_appSettings.getQuickNoteFile()), -1, false);
459470
} else if (id == R.id.nav_todo) {
460-
frag = _todo = DocumentEditAndViewFragment.newInstance(new Document(_appSettings.getTodoFile()), Document.EXTRA_FILE_LINE_NUMBER_LAST, false);
471+
frag = _todo = DocumentEditAndViewFragment.newInstance(new Document(_appSettings.getTodoFile()), -1, false);
461472
} else if (id == R.id.nav_more) {
462473
frag = _more = MoreFragment.newInstance();
463474
} else {

app/src/main/java/net/gsantner/markor/activity/openeditor/OpenEditorQuickNoteActivity.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,11 @@
1111

1212
import androidx.annotation.Nullable;
1313

14-
import net.gsantner.markor.model.Document;
15-
1614
public class OpenEditorQuickNoteActivity extends OpenEditorActivity {
1715

1816
@Override
1917
protected void onCreate(@Nullable Bundle savedInstanceState) {
2018
super.onCreate(savedInstanceState);
21-
openEditorForFile(_appSettings.getQuickNoteFile(), Document.EXTRA_FILE_LINE_NUMBER_LAST);
19+
openEditorForFile(_appSettings.getQuickNoteFile(), -1);
2220
}
2321
}

app/src/main/java/net/gsantner/markor/activity/openeditor/OpenEditorTodoActivity.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,11 @@
1111

1212
import androidx.annotation.Nullable;
1313

14-
import net.gsantner.markor.model.Document;
15-
1614
public class OpenEditorTodoActivity extends OpenEditorActivity {
1715

1816
@Override
1917
protected void onCreate(@Nullable Bundle savedInstanceState) {
2018
super.onCreate(savedInstanceState);
21-
openEditorForFile(_appSettings.getTodoFile(), Document.EXTRA_FILE_LINE_NUMBER_LAST);
19+
openEditorForFile(_appSettings.getTodoFile(), -1);
2220
}
2321
}

app/src/main/java/net/gsantner/markor/format/ActionButtonBase.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import android.text.Editable;
1818
import android.text.Selection;
1919
import android.text.Spannable;
20+
import android.text.SpannableStringBuilder;
2021
import android.text.TextUtils;
2122
import android.view.HapticFeedbackConstants;
2223
import android.view.KeyEvent;
@@ -887,7 +888,10 @@ public static void moveLineSelectionBy1(final HighlightingEditor hlEditor, final
887888
final int[][] offsets = TextViewUtils.getLineOffsetFromIndex(text, sel);
888889

889890
hlEditor.withAutoFormatDisabled(() -> {
890-
final String newPair = String.format("%s\n%s", isUp ? lines : altLine, isUp ? altLine : lines);
891+
final SpannableStringBuilder newPair = new SpannableStringBuilder()
892+
.append(isUp ? lines : altLine)
893+
.append("\n")
894+
.append(isUp ? altLine : lines);
891895
text.replace(Math.min(lineSel[0], altSel[0]), Math.max(lineSel[1], altSel[1]), newPair);
892896
});
893897

0 commit comments

Comments
 (0)