diff --git a/app/src/main/java/com/amaze/filemanager/ui/activities/texteditor/TextEditorActivity.java b/app/src/main/java/com/amaze/filemanager/ui/activities/texteditor/TextEditorActivity.java index f3bebaf489..295a309a79 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/activities/texteditor/TextEditorActivity.java +++ b/app/src/main/java/com/amaze/filemanager/ui/activities/texteditor/TextEditorActivity.java @@ -49,34 +49,30 @@ import com.amaze.filemanager.utils.Utils; import com.google.android.material.snackbar.Snackbar; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.ObjectAnimator; import android.content.Context; -import android.graphics.Color; import android.graphics.Typeface; import android.net.Uri; -import android.os.Build; import android.os.Bundle; import android.text.Editable; import android.text.Spanned; import android.text.TextWatcher; import android.text.style.BackgroundColorSpan; -import android.util.DisplayMetrics; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.view.ViewAnimationUtils; -import android.view.animation.AccelerateDecelerateInterpolator; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; -import android.widget.RelativeLayout; import android.widget.ScrollView; import android.widget.Toast; import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; import androidx.appcompat.widget.AppCompatEditText; import androidx.appcompat.widget.AppCompatImageButton; +import androidx.constraintlayout.widget.ConstraintLayout; import androidx.lifecycle.ViewModelProvider; public class TextEditorActivity extends ThemedActivity @@ -95,13 +91,14 @@ public class TextEditorActivity extends ThemedActivity private static final String KEY_ORIGINAL_TEXT = "original"; private static final String KEY_MONOFONT = "monofont"; - private RelativeLayout searchViewLayout; + private ConstraintLayout searchViewLayout; public AppCompatImageButton upButton; public AppCompatImageButton downButton; - public AppCompatImageButton closeButton; private Snackbar loadingSnackbar; + private TextEditorActivityViewModel viewModel; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -109,16 +106,15 @@ public void onCreate(Bundle savedInstanceState) { toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); - final TextEditorActivityViewModel viewModel = - new ViewModelProvider(this).get(TextEditorActivityViewModel.class); + viewModel = new ViewModelProvider(this).get(TextEditorActivityViewModel.class); + + searchViewLayout = findViewById(R.id.textEditorSearchBar); - searchViewLayout = findViewById(R.id.searchview); searchViewLayout.setBackgroundColor(getPrimary()); - searchEditText = searchViewLayout.findViewById(R.id.search_box); - upButton = searchViewLayout.findViewById(R.id.prev); - downButton = searchViewLayout.findViewById(R.id.next); - closeButton = searchViewLayout.findViewById(R.id.close); + searchEditText = searchViewLayout.findViewById(R.id.textEditorSearchBox); + upButton = searchViewLayout.findViewById(R.id.textEditorSearchPrevButton); + downButton = searchViewLayout.findViewById(R.id.textEditorSearchNextButton); searchEditText.addTextChangedListener(this); @@ -126,14 +122,9 @@ public void onCreate(Bundle savedInstanceState) { // upButton.setEnabled(false); downButton.setOnClickListener(this); // downButton.setEnabled(false); - closeButton.setOnClickListener(this); - - boolean useNewStack = getBoolean(PREFERENCE_TEXTEDITOR_NEWSTACK); - getSupportActionBar().setDisplayHomeAsUpEnabled(!useNewStack); - - mainTextView = findViewById(R.id.fname); - scrollView = findViewById(R.id.editscroll); + mainTextView = findViewById(R.id.textEditorMainEditText); + scrollView = findViewById(R.id.textEditorScrollView); final Uri uri = getIntent().getData(); if (uri != null) { @@ -144,14 +135,23 @@ public void onCreate(Bundle savedInstanceState) { return; } - getSupportActionBar().setTitle(viewModel.getFile().name); + ActionBar actionBar = getSupportActionBar(); + + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(!getBoolean(PREFERENCE_TEXTEDITOR_NEWSTACK)); + actionBar.setTitle(viewModel.getFile().name); + } mainTextView.addTextChangedListener(this); if (getAppTheme().equals(AppTheme.DARK)) { - mainTextView.setBackgroundColor(Utils.getColor(this, R.color.holo_dark_background)); + mainTextView.setBackgroundColor(Utils.getColor(this, R.color.holo_dark_action_mode)); + mainTextView.setTextColor(Utils.getColor(this, R.color.primary_white)); } else if (getAppTheme().equals(AppTheme.BLACK)) { mainTextView.setBackgroundColor(Utils.getColor(this, android.R.color.black)); + mainTextView.setTextColor(Utils.getColor(this, R.color.primary_white)); + } else { + mainTextView.setTextColor(Utils.getColor(this, R.color.primary_grey_900)); } if (mainTextView.getTypeface() == null) { @@ -172,16 +172,17 @@ public void onCreate(Bundle savedInstanceState) { } else { load(this); } - initStatusBarResources(findViewById(R.id.texteditor)); + initStatusBarResources(findViewById(R.id.textEditorRootView)); } @Override - protected void onSaveInstanceState(Bundle outState) { + protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); final TextEditorActivityViewModel viewModel = new ViewModelProvider(this).get(TextEditorActivityViewModel.class); - outState.putString(KEY_MODIFIED_TEXT, mainTextView.getText().toString()); + outState.putString( + KEY_MODIFIED_TEXT, mainTextView.getText() != null ? mainTextView.getText().toString() : ""); outState.putInt(KEY_INDEX, mainTextView.getScrollY()); outState.putString(KEY_ORIGINAL_TEXT, viewModel.getOriginal()); outState.putBoolean(KEY_MONOFONT, inputTypefaceMono.equals(mainTextView.getTypeface())); @@ -193,6 +194,7 @@ private void checkUnsavedChanges() { if (viewModel.getOriginal() != null && mainTextView.isShown() + && mainTextView.getText() != null && !viewModel.getOriginal().equals(mainTextView.getText().toString())) { new MaterialDialog.Builder(this) .title(R.string.unsaved_changes) @@ -293,10 +295,13 @@ public boolean onOptionsItemSelected(MenuItem item) { break; case R.id.save: // Make sure EditText is visible before saving! - saveFile(this, mainTextView.getText().toString()); + if (mainTextView.getText() != null) { + saveFile(this, mainTextView.getText().toString()); + } break; case R.id.details: if (editableFileAbstraction.scheme.equals(FILE) + && editableFileAbstraction.hybridFileParcelable.getFile() != null && editableFileAbstraction.hybridFileParcelable.getFile().exists()) { GeneralDialogCreation.showPropertiesDialogWithoutPermissions( editableFileAbstraction.hybridFileParcelable, this, getAppTheme()); @@ -316,7 +321,7 @@ public boolean onOptionsItemSelected(MenuItem item) { case R.id.openwith: if (editableFileAbstraction.scheme.equals(FILE)) { File currentFile = editableFileAbstraction.hybridFileParcelable.getFile(); - if (currentFile.exists()) { + if (currentFile != null && currentFile.exists()) { boolean useNewStack = getBoolean(PREFERENCE_TEXTEDITOR_NEWSTACK); FileUtils.openWith(currentFile, this, useNewStack); } else { @@ -355,7 +360,8 @@ public void onDestroy() { @Override public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { // condition to check if callback is called in search editText - if (searchEditText != null && charSequence.hashCode() == searchEditText.getText().hashCode()) { + if (searchEditText.getText() != null + && charSequence.hashCode() == searchEditText.getText().hashCode()) { final TextEditorActivityViewModel viewModel = new ViewModelProvider(this).get(TextEditorActivityViewModel.class); @@ -371,7 +377,8 @@ public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) @Override public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { - if (charSequence.hashCode() == mainTextView.getText().hashCode()) { + if (mainTextView.getText() != null + && charSequence.hashCode() == mainTextView.getText().hashCode()) { final TextEditorActivityViewModel viewModel = new ViewModelProvider(this).get(TextEditorActivityViewModel.class); final Timer oldTimer = viewModel.getTimer(); @@ -400,11 +407,12 @@ public void run() { new ViewModelProvider(textEditorActivity).get(TextEditorActivityViewModel.class); modified = - !textEditorActivity - .mainTextView - .getText() - .toString() - .equals(viewModel.getOriginal()); + textEditorActivity.mainTextView.getText() != null + && !textEditorActivity + .mainTextView + .getText() + .toString() + .equals(viewModel.getOriginal()); if (viewModel.getModified() != modified) { viewModel.setModified(modified); invalidateOptionsMenu(); @@ -420,7 +428,8 @@ public void run() { @Override public void afterTextChanged(Editable editable) { // searchBox callback block - if (searchEditText != null && editable.hashCode() == searchEditText.getText().hashCode()) { + if (searchEditText.getText() != null + && editable.hashCode() == searchEditText.getText().hashCode()) { final WeakReference textEditorActivityWR = new WeakReference<>(this); final OnProgressUpdate onProgressUpdate = @@ -429,7 +438,7 @@ public void afterTextChanged(Editable editable) { if (textEditorActivity == null) { return; } - textEditorActivity.unhighlightSearchResult(index); + textEditorActivity.colorSearchResult(index, getPrimary()); }; final OnAsyncTaskFinished> onAsyncTaskFinished = @@ -445,7 +454,7 @@ public void afterTextChanged(Editable editable) { viewModel.setSearchResultIndices(data); for (SearchResultIndex searchResultIndex : data) { - textEditorActivity.unhighlightSearchResult(searchResultIndex); + textEditorActivity.colorSearchResult(searchResultIndex, getPrimary()); } if (data.size() != 0) { @@ -460,6 +469,8 @@ public void afterTextChanged(Editable editable) { } }; + if (mainTextView.getText() == null) return; + searchTextTask = new SearchTextTask( mainTextView.getText().toString(), @@ -470,77 +481,60 @@ public void afterTextChanged(Editable editable) { } } - /** show search view with a circular reveal animation */ private void revealSearchView() { - int startRadius = 4; - int endRadius = Math.max(searchViewLayout.getWidth(), searchViewLayout.getHeight()); - DisplayMetrics metrics = new DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics(metrics); + searchViewLayout.setVisibility(View.VISIBLE); - // hardcoded and completely random - int cx = metrics.widthPixels - 160; - int cy = toolbar.getBottom(); - Animator animator; + Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_in_top); - // FIXME: 2016/11/18 ViewAnimationUtils Compatibility - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - animator = - ViewAnimationUtils.createCircularReveal(searchViewLayout, cx, cy, startRadius, endRadius); - else animator = ObjectAnimator.ofFloat(searchViewLayout, "alpha", 0f, 1f); + animation.setAnimationListener( + new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) {} - animator.setInterpolator(new AccelerateDecelerateInterpolator()); - animator.setDuration(600); - searchViewLayout.setVisibility(View.VISIBLE); - searchEditText.setText(""); - animator.start(); - animator.addListener( - new AnimatorListenerAdapter() { @Override - public void onAnimationEnd(Animator animation) { + public void onAnimationEnd(Animation animation) { + searchEditText.requestFocus(); - InputMethodManager imm = - (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); - imm.showSoftInput(searchEditText, InputMethodManager.SHOW_IMPLICIT); + + ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)) + .showSoftInput(searchEditText, InputMethodManager.SHOW_IMPLICIT); } + + @Override + public void onAnimationRepeat(Animation animation) {} }); + + searchViewLayout.startAnimation(animation); } - /** hide search view with a circular reveal animation */ private void hideSearchView() { - int endRadius = 4; - int startRadius = Math.max(searchViewLayout.getWidth(), searchViewLayout.getHeight()); - DisplayMetrics metrics = new DisplayMetrics(); - getWindowManager().getDefaultDisplay().getMetrics(metrics); + Animation animation = AnimationUtils.loadAnimation(this, R.anim.fade_out_top); - // hardcoded and completely random - int cx = metrics.widthPixels - 160; - int cy = toolbar.getBottom(); - - Animator animator; - // FIXME: 2016/11/18 ViewAnimationUtils Compatibility - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - animator = - ViewAnimationUtils.createCircularReveal(searchViewLayout, cx, cy, startRadius, endRadius); - } else { - animator = ObjectAnimator.ofFloat(searchViewLayout, "alpha", 0f, 1f); - } + animation.setAnimationListener( + new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) {} - animator.setInterpolator(new AccelerateDecelerateInterpolator()); - animator.setDuration(600); - animator.start(); - animator.addListener( - new AnimatorListenerAdapter() { @Override - public void onAnimationEnd(Animator animation) { + public void onAnimationEnd(Animation animation) { + searchViewLayout.setVisibility(View.GONE); - InputMethodManager inputMethodManager = - (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); - inputMethodManager.hideSoftInputFromWindow( - searchEditText.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY); + + cleanSpans(viewModel); + searchEditText.setText(""); + + ((InputMethodManager) getSystemService(INPUT_METHOD_SERVICE)) + .hideSoftInputFromWindow( + searchEditText.getWindowToken(), InputMethodManager.HIDE_IMPLICIT_ONLY); } + + @Override + public void onAnimationRepeat(Animation animation) {} }); + + searchViewLayout.startAnimation(animation); } @Override @@ -549,7 +543,7 @@ public void onClick(View v) { new ViewModelProvider(this).get(TextEditorActivityViewModel.class); switch (v.getId()) { - case R.id.prev: + case R.id.textEditorSearchPrevButton: // upButton if (viewModel.getCurrent() > 0) { unhighlightCurrentSearchResult(viewModel); @@ -560,7 +554,7 @@ public void onClick(View v) { highlightCurrentSearchResult(viewModel); } break; - case R.id.next: + case R.id.textEditorSearchNextButton: // downButton if (viewModel.getCurrent() < viewModel.getSearchResultIndices().size() - 1) { unhighlightCurrentSearchResult(viewModel); @@ -570,11 +564,6 @@ public void onClick(View v) { highlightCurrentSearchResult(viewModel); } break; - case R.id.close: - // closeButton - findViewById(R.id.searchview).setVisibility(View.GONE); - cleanSpans(viewModel); - break; default: throw new IllegalStateException(); } @@ -586,14 +575,16 @@ private void unhighlightCurrentSearchResult(final TextEditorActivityViewModel vi } SearchResultIndex resultIndex = viewModel.getSearchResultIndices().get(viewModel.getCurrent()); - unhighlightSearchResult(resultIndex); + colorSearchResult(resultIndex, getPrimary()); } private void highlightCurrentSearchResult(final TextEditorActivityViewModel viewModel) { SearchResultIndex keyValueNew = viewModel.getSearchResultIndices().get(viewModel.getCurrent()); - colorSearchResult(keyValueNew, Utils.getColor(this, R.color.search_text_highlight)); + colorSearchResult(keyValueNew, getAccent()); // scrolling to the highlighted element + if (getSupportActionBar() != null) return; + scrollView.scrollTo( 0, (Integer) keyValueNew.getLineNumber() @@ -602,18 +593,9 @@ private void highlightCurrentSearchResult(final TextEditorActivityViewModel view - getSupportActionBar().getHeight()); } - private void unhighlightSearchResult(SearchResultIndex resultIndex) { - @ColorInt int color; - if (getAppTheme().equals(AppTheme.LIGHT)) { - color = Color.YELLOW; - } else { - color = Color.LTGRAY; - } - - colorSearchResult(resultIndex, color); - } - private void colorSearchResult(SearchResultIndex resultIndex, @ColorInt int color) { + if (mainTextView.getText() == null) return; + mainTextView .getText() .setSpan( @@ -630,6 +612,8 @@ private void cleanSpans(TextEditorActivityViewModel viewModel) { viewModel.setLine(0); // clearing textView spans + if (mainTextView.getText() == null) return; + BackgroundColorSpan[] colorSpans = mainTextView.getText().getSpans(0, mainTextView.length(), BackgroundColorSpan.class); for (BackgroundColorSpan colorSpan : colorSpans) { diff --git a/app/src/main/res/anim/fade_in_top.xml b/app/src/main/res/anim/fade_in_top.xml index ab46231f5e..2677abcec8 100644 --- a/app/src/main/res/anim/fade_in_top.xml +++ b/app/src/main/res/anim/fade_in_top.xml @@ -1,13 +1,15 @@ + android:interpolator="@android:interpolator/decelerate_cubic" + android:shareInterpolator="true"> + android:duration="200" + android:fromXDelta="0%" + android:fromYDelta="-50%" + android:toXDelta="0%" + android:toYDelta="0%" /> + android:toAlpha="1" /> \ No newline at end of file diff --git a/app/src/main/res/anim/fade_out_top.xml b/app/src/main/res/anim/fade_out_top.xml new file mode 100644 index 0000000000..814163e4d9 --- /dev/null +++ b/app/src/main/res/anim/fade_out_top.xml @@ -0,0 +1,15 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/actionmode_textviewer.xml b/app/src/main/res/layout/actionmode_textviewer.xml deleted file mode 100644 index 7a7c84ae0d..0000000000 --- a/app/src/main/res/layout/actionmode_textviewer.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/search.xml b/app/src/main/res/layout/search.xml index 2d3ec8df10..22adfcb697 100644 --- a/app/src/main/res/layout/search.xml +++ b/app/src/main/res/layout/search.xml @@ -16,49 +16,50 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . --> - - + android:orientation="vertical"> - + + - + android:layout_height="?actionBarSize" /> + + + - + + + android:lineSpacingExtra="1dp" + android:padding="16dp" + android:textSize="14sp" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/text_editor_search_bar.xml b/app/src/main/res/layout/text_editor_search_bar.xml new file mode 100644 index 0000000000..fc8989bdc1 --- /dev/null +++ b/app/src/main/res/layout/text_editor_search_bar.xml @@ -0,0 +1,52 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index a76ae45d01..0d246815be 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -25,7 +25,6 @@ #575757 #484848 #50575757 - #FF9632 #f2f2f2 diff --git a/app/src/test/java/com/amaze/filemanager/ui/activities/TextEditorActivityTest.java b/app/src/test/java/com/amaze/filemanager/ui/activities/TextEditorActivityTest.java index 4137809960..3209d48ad1 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/activities/TextEditorActivityTest.java +++ b/app/src/test/java/com/amaze/filemanager/ui/activities/TextEditorActivityTest.java @@ -104,7 +104,7 @@ private void generateActivity(Intent intent) { Robolectric.buildActivity(TextEditorActivity.class, intent).create().start().visible(); TextEditorActivity activity = controller.get(); - text = activity.findViewById(R.id.fname); + text = activity.findViewById(R.id.textEditorMainEditText); activity.onDestroy(); }