mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
Fixed: File does not close and crashes if reopened and closed again.
This commit is contained in:
@@ -134,7 +134,6 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
NavigationView.OnNavigationItemSelectedListener,
|
||||
DiagnosticClickListener,
|
||||
EditorFragment.FileOpenListener,
|
||||
EditorPagerAdapter.EditorStateListener,
|
||||
IDEHandler.Provider,
|
||||
EditorActivityProvider {
|
||||
|
||||
@@ -202,59 +201,29 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
setSupportActionBar (mBinding.editorToolbar);
|
||||
|
||||
getProjectFromIntent ();
|
||||
mPagerAdapter = new EditorPagerAdapter (getSupportFragmentManager (), this.mProject);
|
||||
|
||||
mPagerAdapter = new EditorPagerAdapter (this, this.mProject);
|
||||
mFileTreeFragment = FileTreeFragment.newInstance (this.mProject).setFileActionListener (this);
|
||||
mDaemonStatusFragment = new TextSheetFragment ().setTextSelectable (true);
|
||||
|
||||
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle (this, mBinding.editorDrawerLayout, mBinding.editorToolbar, R.string.app_name, R.string.app_name);
|
||||
mBinding.editorDrawerLayout.addDrawerListener (toggle);
|
||||
mBinding.startNav.setNavigationItemSelectedListener (this);
|
||||
toggle.syncState ();
|
||||
setupDrawerToggle ();
|
||||
loadFragment (mFileTreeFragment);
|
||||
|
||||
symbolInput = new SymbolInputView (this);
|
||||
mBinding.bottomSheet.textContainer.addView (symbolInput, 0, new ViewGroup.LayoutParams (-1, -2));
|
||||
|
||||
final var mediator = new TabLayoutMediator (mBinding.tabs,
|
||||
mBinding.editorViewPager,
|
||||
true,
|
||||
false, // Do NOT enable smooth scrolls. Doing so results in error. Any workaround or fix will be appreciated.
|
||||
(tab, position) -> tab.setText (mPagerAdapter.getEditorTitle (position)));
|
||||
mBinding.editorViewPager.setUserInputEnabled (false);
|
||||
mBinding.editorViewPager.setOffscreenPageLimit (9);
|
||||
mBinding.editorViewPager.setAdapter (mPagerAdapter);
|
||||
mBinding.tabs.setupWithViewPager (mBinding.editorViewPager);
|
||||
mBinding.tabs.addOnTabSelectedListener (this);
|
||||
|
||||
bottomSheetTabAdapter = new EditorBottomSheetTabAdapter (this);
|
||||
mBinding.bottomSheet.pager.setAdapter (bottomSheetTabAdapter);
|
||||
|
||||
final var mediator = new TabLayoutMediator (mBinding.bottomSheet.tabs,
|
||||
mBinding.bottomSheet.pager,
|
||||
true,
|
||||
true,
|
||||
(tab, position) -> tab.setText (bottomSheetTabAdapter.getTitle (position)));
|
||||
mediator.attach ();
|
||||
mBinding.bottomSheet.pager.setUserInputEnabled (false);
|
||||
mBinding.bottomSheet.pager.setOffscreenPageLimit (bottomSheetTabAdapter.getItemCount () - 1); // DO not remove any views
|
||||
|
||||
//noinspection rawtypes
|
||||
mEditorBottomSheet = (EditorBottomSheetBehavior) EditorBottomSheetBehavior.from (mBinding.bottomSheet.getRoot ());
|
||||
mEditorBottomSheet.setBinding (mBinding.bottomSheet);
|
||||
mEditorBottomSheet.addBottomSheetCallback (new BottomSheetBehavior.BottomSheetCallback () {
|
||||
@Override
|
||||
public void onStateChanged (@NonNull View bottomSheet, int newState) {
|
||||
mBinding.bottomSheet.textContainer.setVisibility (newState == BottomSheetBehavior.STATE_EXPANDED ? View.INVISIBLE : View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlide (@NonNull View bottomSheet, float slideOffset) {
|
||||
mBinding.bottomSheet.textContainer.setAlpha (1f - slideOffset);
|
||||
}
|
||||
});
|
||||
|
||||
if (!getApp ().getPrefManager ().getBoolean (KEY_BOTTOM_SHEET_SHOWN) && mEditorBottomSheet.getState ()!= BottomSheetBehavior.STATE_EXPANDED) {
|
||||
mEditorBottomSheet.setState (BottomSheetBehavior.STATE_EXPANDED);
|
||||
|
||||
new Handler (Looper.getMainLooper ()).postDelayed (() -> {
|
||||
mEditorBottomSheet.setState (BottomSheetBehavior.STATE_COLLAPSED);
|
||||
getApp ().getPrefManager ().putBoolean (KEY_BOTTOM_SHEET_SHOWN, true);
|
||||
}, 1500);
|
||||
}
|
||||
setupEditorBottomSheet ();
|
||||
|
||||
createQuickActions ();
|
||||
|
||||
@@ -274,6 +243,52 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
mUIDesignerLauncher = registerForActivityResult (new ActivityResultContracts.StartActivityForResult (), this::onGetUIDesignerResult);
|
||||
}
|
||||
|
||||
private void setupDrawerToggle () {
|
||||
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle (this, mBinding.editorDrawerLayout, mBinding.editorToolbar, R.string.app_name, R.string.app_name);
|
||||
mBinding.editorDrawerLayout.addDrawerListener (toggle);
|
||||
mBinding.startNav.setNavigationItemSelectedListener (this);
|
||||
toggle.syncState ();
|
||||
}
|
||||
|
||||
private void setupEditorBottomSheet () {
|
||||
bottomSheetTabAdapter = new EditorBottomSheetTabAdapter (this);
|
||||
mBinding.bottomSheet.pager.setAdapter (bottomSheetTabAdapter);
|
||||
|
||||
final var mediator = new TabLayoutMediator (mBinding.bottomSheet.tabs,
|
||||
mBinding.bottomSheet.pager,
|
||||
true,
|
||||
true,
|
||||
(tab, position) -> tab.setText (bottomSheetTabAdapter.getTitle (position)));
|
||||
|
||||
mediator.attach ();
|
||||
mBinding.bottomSheet.pager.setUserInputEnabled (false);
|
||||
mBinding.bottomSheet.pager.setOffscreenPageLimit (bottomSheetTabAdapter.getItemCount () - 1); // DO not remove any views
|
||||
|
||||
//noinspection rawtypes
|
||||
mEditorBottomSheet = (EditorBottomSheetBehavior) EditorBottomSheetBehavior.from (mBinding.bottomSheet.getRoot ());
|
||||
mEditorBottomSheet.setBinding (mBinding.bottomSheet);
|
||||
mEditorBottomSheet.addBottomSheetCallback (new BottomSheetBehavior.BottomSheetCallback () {
|
||||
@Override
|
||||
public void onStateChanged (@NonNull View bottomSheet, int newState) {
|
||||
mBinding.bottomSheet.textContainer.setVisibility (newState == BottomSheetBehavior.STATE_EXPANDED ? View.INVISIBLE : View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlide (@NonNull View bottomSheet, float slideOffset) {
|
||||
mBinding.bottomSheet.textContainer.setAlpha (1f - slideOffset);
|
||||
}
|
||||
});
|
||||
|
||||
if (!getApp ().getPrefManager ().getBoolean (KEY_BOTTOM_SHEET_SHOWN) && mEditorBottomSheet.getState () != BottomSheetBehavior.STATE_EXPANDED) {
|
||||
mEditorBottomSheet.setState (BottomSheetBehavior.STATE_EXPANDED);
|
||||
|
||||
new Handler (Looper.getMainLooper ()).postDelayed (() -> {
|
||||
mEditorBottomSheet.setState (BottomSheetBehavior.STATE_COLLAPSED);
|
||||
getApp ().getPrefManager ().putBoolean (KEY_BOTTOM_SHEET_SHOWN, true);
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed () {
|
||||
if (mBinding.getRoot ().isDrawerOpen (GravityCompat.END)) {
|
||||
@@ -495,20 +510,6 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
return mIDEProject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void editorStateChanged () {
|
||||
for (int i = 0; i < mBinding.tabs.getTabCount (); i++) {
|
||||
try {
|
||||
final var tab = mBinding.tabs.getTabAt (i);
|
||||
if (tab != null) {
|
||||
tab.setText (mPagerAdapter.getPageTitle (i));
|
||||
}
|
||||
} catch (Throwable th) {
|
||||
th.printStackTrace ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleSearchResults (Map<File, List<SearchResult>> results) {
|
||||
setSearchResultAdapter (new com.itsaky.androidide.adapters.SearchListAdapter (results, file -> {
|
||||
openFile (file);
|
||||
@@ -519,7 +520,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
}));
|
||||
|
||||
showSearchResults ();
|
||||
|
||||
|
||||
if (mSearchingProgress != null && mSearchingProgress.isShowing ()) {
|
||||
mSearchingProgress.dismiss ();
|
||||
}
|
||||
@@ -538,7 +539,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
}
|
||||
|
||||
public void showDaemonStatus () {
|
||||
ShellServer shell = getApp ().newShell (t -> getDaemonStatusFragment ().append (t.toString ()));
|
||||
ShellServer shell = getApp ().newShell (t -> getDaemonStatusFragment ().append (t));
|
||||
shell.bgAppend (String.format ("echo '%s'", getString (R.string.msg_getting_daemom_status)));
|
||||
shell.bgAppend (String.format ("cd '%s' && sh gradlew --status", mProject.getProjectPath ()));
|
||||
if (!getDaemonStatusFragment ().isShowing ()) {
|
||||
@@ -635,12 +636,12 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
final int width = view.getWidth ();
|
||||
view.getWindowVisibleDisplayFrame (r);
|
||||
if (r.width () != width) {
|
||||
|
||||
|
||||
// Will be true when the view is going out of screen to left
|
||||
if (initialX < r.left) {
|
||||
view.setX (SizeUtils.dp2px (8)); // an offset of 8dp from the left edge of screen
|
||||
}
|
||||
|
||||
|
||||
// Will be true when the view is going out of screen to right
|
||||
if (initialX + width > r.right) {
|
||||
view.setX (r.right - SizeUtils.dp2px (8) - width); // position to the right but leaving 8dp space from the right edge of screen
|
||||
@@ -666,11 +667,11 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
@Override
|
||||
public void
|
||||
onTabSelected (@NonNull TabLayout.Tab tab) {
|
||||
EditorFragment current = mPagerAdapter.getFrag (tab.getPosition ());
|
||||
if (current != null && current.getFile () != null) {
|
||||
mCurrentFragment = current;
|
||||
mCurrentFile = current.getFile ();
|
||||
refreshSymbolInput (current);
|
||||
final var opened = mPagerAdapter.getOpenedFile (tab.getPosition ());
|
||||
if (opened != null && opened.file != null && opened.fragment != null) {
|
||||
mCurrentFragment = opened.fragment;
|
||||
mCurrentFile = opened.file;
|
||||
refreshSymbolInput (mCurrentFragment);
|
||||
}
|
||||
|
||||
invalidateOptionsMenu ();
|
||||
@@ -678,11 +679,13 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
|
||||
@Override
|
||||
public void onTabUnselected (@NonNull TabLayout.Tab tab) {
|
||||
EditorFragment frag = mPagerAdapter.getFrag (tab.getPosition ());
|
||||
if (frag == null) {
|
||||
final var opened = mPagerAdapter.getOpenedFile (tab.getPosition ());
|
||||
if (opened == null) {
|
||||
return;
|
||||
}
|
||||
boolean isGradle = frag.isModified () && frag.getFile ().getName ().endsWith (EditorFragment.EXT_GRADLE);
|
||||
|
||||
final var frag = opened.fragment;
|
||||
boolean isGradle = frag.isModified () && opened.file.getName ().endsWith (EditorFragment.EXT_GRADLE);
|
||||
frag.save ();
|
||||
if (isGradle) {
|
||||
notifySyncNeeded ();
|
||||
@@ -875,47 +878,34 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
}
|
||||
|
||||
public void closeFile (int index, boolean selectOther) {
|
||||
mBinding.tabs.removeOnTabSelectedListener (this);
|
||||
// mBinding.tabs.removeOnTabSelectedListener (this);
|
||||
mPagerAdapter.closeFileAt (index);
|
||||
// mBinding.tabs.addOnTabSelectedListener (this);
|
||||
|
||||
int pos = index;
|
||||
final List<Fragment> frags = mPagerAdapter.getFragments ();
|
||||
final List<File> files = mPagerAdapter.getOpenedFiles ();
|
||||
|
||||
final EditorFragment editorFragment = mPagerAdapter.getFrag (index);
|
||||
|
||||
frags.remove (index);
|
||||
files.remove (index);
|
||||
|
||||
if (editorFragment != null && editorFragment.getEditor () != null) {
|
||||
editorFragment.getEditor ().close ();
|
||||
}
|
||||
|
||||
mPagerAdapter = new EditorPagerAdapter (getSupportFragmentManager (), mProject, frags, files);
|
||||
mBinding.editorViewPager.setAdapter (mPagerAdapter);
|
||||
mBinding.tabs.setupWithViewPager (mBinding.editorViewPager);
|
||||
mBinding.tabs.addOnTabSelectedListener (this);
|
||||
|
||||
if (selectOther) {
|
||||
if (pos < 0 || pos >= frags.size ()) {
|
||||
int i = pos - 1;
|
||||
if (i >= 0 && i < frags.size ()) {
|
||||
pos = i;
|
||||
} else {
|
||||
i = pos + 1;
|
||||
if (i >= 0 && i < frags.size ()) {
|
||||
pos = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
mBinding.editorViewPager.setCurrentItem (pos, false);
|
||||
}
|
||||
|
||||
if (mPagerAdapter.getCount () <= 0) {
|
||||
if (mPagerAdapter.getItemCount () <= 0) {
|
||||
mCurrentFragment = null;
|
||||
mCurrentFile = null;
|
||||
}
|
||||
|
||||
invalidateOptionsMenu ();
|
||||
|
||||
if (mPagerAdapter.getItemCount () == 0 &&
|
||||
(mBinding.editorViewPager.getChildCount () != 0 || mBinding.tabs.getChildCount () != 0)) {
|
||||
// TODO Find out why this happens
|
||||
// Mostly for java files...
|
||||
mBinding.editorViewPager.removeAllViews ();
|
||||
mBinding.tabs.removeAllViews ();
|
||||
}
|
||||
}
|
||||
|
||||
public void closeAll () {
|
||||
mBinding.tabs.removeOnTabSelectedListener (this);
|
||||
mPagerAdapter.closeAllFiles ();
|
||||
mBinding.tabs.addOnTabSelectedListener (this);
|
||||
}
|
||||
|
||||
public void closeOthers () {
|
||||
mPagerAdapter.closeOthers (mBinding.tabs.getSelectedTabPosition ());
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////
|
||||
@@ -926,14 +916,14 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
private void onGetUIDesignerResult (@NonNull ActivityResult result) {
|
||||
if (mCurrentFragment != null && mCurrentFragment.getEditor () != null && result.getResultCode () == RESULT_OK) {
|
||||
final var data = result.getData ();
|
||||
if (data != null) {
|
||||
if (data != null && data.hasExtra (DesignerActivity.KEY_GENERATED_CODE)) {
|
||||
final var code = data.getStringExtra (DesignerActivity.KEY_GENERATED_CODE);
|
||||
mCurrentFragment.getEditor ().setText (code);
|
||||
saveAll ();
|
||||
} else {
|
||||
final var msg = getString (R.string.msg_invalid_designer_result);
|
||||
getApp ().toast (msg, Toaster.Type.ERROR);
|
||||
LOG.error (msg, "Data returned by UI Designer is null");
|
||||
LOG.error (msg, "Data returned by UI Designer is null or is invalid.");
|
||||
}
|
||||
} else {
|
||||
LOG.error ("UI Designer returned an invalid result code.", "Result code: " + result.getResultCode ());
|
||||
@@ -1057,6 +1047,10 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
}
|
||||
|
||||
private void refreshSymbolInput (@NonNull EditorFragment frag) {
|
||||
if (frag.getEditor () == null || frag.getFile () == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
symbolInput.bindEditor (frag.getEditor ());
|
||||
symbolInput.setSymbols (Symbols.forFile (frag.getFile ()));
|
||||
}
|
||||
@@ -1085,7 +1079,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
LSP.shutdownAll ();
|
||||
|
||||
getApp ().stopAllDaemons ();
|
||||
|
||||
|
||||
if (manualFinish) {
|
||||
finish ();
|
||||
}
|
||||
@@ -1163,7 +1157,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
if (str == null || str.trim ().isEmpty ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
extensionList.add (str);
|
||||
}
|
||||
} else {
|
||||
@@ -1233,29 +1227,5 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
});
|
||||
}
|
||||
|
||||
private void closeAll () {
|
||||
mBinding.tabs.removeOnTabSelectedListener (this);
|
||||
|
||||
mPagerAdapter = new EditorPagerAdapter (getSupportFragmentManager (), mProject);
|
||||
mBinding.editorViewPager.setAdapter (mPagerAdapter);
|
||||
mBinding.tabs.setupWithViewPager (mBinding.editorViewPager);
|
||||
mBinding.tabs.addOnTabSelectedListener (this);
|
||||
}
|
||||
|
||||
private void closeOthers () {
|
||||
final EditorFragment frag = mPagerAdapter.getFrag (mBinding.tabs.getSelectedTabPosition ());
|
||||
final File file = mPagerAdapter.getOpenedFiles ().get (mBinding.tabs.getSelectedTabPosition ());
|
||||
try {
|
||||
frag.save ();
|
||||
} catch (Throwable th) {
|
||||
LOG.error ("Failed to save file: " + file, th);
|
||||
}
|
||||
mPagerAdapter = new EditorPagerAdapter (getSupportFragmentManager (), mProject);
|
||||
mBinding.editorViewPager.setAdapter (mPagerAdapter);
|
||||
mBinding.tabs.setupWithViewPager (mBinding.editorViewPager);
|
||||
mBinding.tabs.addOnTabSelectedListener (this);
|
||||
openFile (file);
|
||||
}
|
||||
|
||||
private static final Logger LOG = Logger.instance ("EditorActivity");
|
||||
}
|
||||
|
||||
@@ -1,186 +1,274 @@
|
||||
/************************************************************************************
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.adapters;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
|
||||
import com.itsaky.androidide.fragments.EditorFragment;
|
||||
import com.itsaky.androidide.project.AndroidProject;
|
||||
import com.itsaky.androidide.models.SaveResult;
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
|
||||
import org.eclipse.lsp4j.Range;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class EditorPagerAdapter extends FragmentStatePagerAdapter implements EditorFragment.ModificationStateListener {
|
||||
public class EditorPagerAdapter extends FragmentStateAdapter implements EditorFragment.ModificationStateListener {
|
||||
|
||||
private ArrayList<File> mOpenedFiles;
|
||||
private ArrayList<Fragment> mFragments;
|
||||
private AndroidProject project;
|
||||
private final AndroidProject project;
|
||||
private final List<OpenedFile> mFiles;
|
||||
|
||||
private EditorStateListener mEditorStateListener;
|
||||
private static final Logger LOG = Logger.instance ("EditorPagerAdapter");
|
||||
|
||||
private static final Logger LOG = Logger.instance("EditorPagerAdapter");
|
||||
|
||||
public EditorPagerAdapter(FragmentManager manager, AndroidProject project) {
|
||||
super(manager);
|
||||
this.project = project;
|
||||
this.mOpenedFiles = new ArrayList<>();
|
||||
this.mFragments = new ArrayList<>();
|
||||
}
|
||||
|
||||
public EditorPagerAdapter(FragmentManager manager, AndroidProject project, List<Fragment> fragments, List<File> files) {
|
||||
super(manager);
|
||||
this.project = project;
|
||||
this.mOpenedFiles = new ArrayList<>();
|
||||
this.mFragments = new ArrayList<>();
|
||||
|
||||
mOpenedFiles.addAll(files);
|
||||
mFragments.addAll(fragments);
|
||||
}
|
||||
|
||||
public EditorPagerAdapter setEditorStateListener (EditorStateListener listener) {
|
||||
this.mEditorStateListener = listener;
|
||||
return this;
|
||||
public EditorPagerAdapter (FragmentActivity activity, AndroidProject project) {
|
||||
super (activity);
|
||||
this.project = project;
|
||||
this.mFiles = new ArrayList<> ();
|
||||
}
|
||||
|
||||
public int findIndexOfEditorByFile(File file) {
|
||||
for (int i=0;i < mFragments.size();i++) {
|
||||
Fragment frag = mFragments.get(i);
|
||||
if (!(frag instanceof EditorFragment))
|
||||
continue;
|
||||
|
||||
EditorFragment editor = (EditorFragment) frag;
|
||||
if (editor.getFile() != null && editor.getFile().getAbsolutePath().equals(file.getAbsolutePath()))
|
||||
return i;
|
||||
|
||||
public int findIndexOfEditorByFile (File file) {
|
||||
if (file == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < this.mFiles.size (); i++) {
|
||||
final var opened = mFiles.get (i);
|
||||
if (opened.file.equals (file)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public EditorFragment findEditorByFile(File file) {
|
||||
int index = findIndexOfEditorByFile(file);
|
||||
if (index != -1)
|
||||
return getFrag(index);
|
||||
|
||||
public EditorFragment findEditorByFile (File file) {
|
||||
int index = findIndexOfEditorByFile (file);
|
||||
if (index != -1) {
|
||||
return getFrag (index);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public int openFile(File file, org.eclipse.lsp4j.Range selection, EditorFragment.FileOpenListener listener) {
|
||||
int openedFileIndex = -1;
|
||||
for (int i=0;i < mOpenedFiles.size();i++) {
|
||||
File f = mOpenedFiles.get(i);
|
||||
if (f.getAbsolutePath().equals(file.getAbsolutePath())) {
|
||||
openedFileIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int openFile (File file, Range selection, EditorFragment.FileOpenListener listener) {
|
||||
int openedFileIndex = -1;
|
||||
for (int i = 0; i < mFiles.size (); i++) {
|
||||
final var f = mFiles.get (i);
|
||||
if (f.file.getAbsolutePath ().equals (file.getAbsolutePath ())) {
|
||||
openedFileIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (openedFileIndex == -1) {
|
||||
mFragments.add(EditorFragment
|
||||
.newInstance(file, project, selection)
|
||||
.setFileOpenListener(listener)
|
||||
.setModificationStateListener(this));
|
||||
mOpenedFiles.add(file);
|
||||
notifyDataSetChanged();
|
||||
return mFragments.size() - 1;
|
||||
} else return openedFileIndex;
|
||||
}
|
||||
|
||||
public SaveResult saveAll() {
|
||||
SaveResult result = new SaveResult();
|
||||
for (int i=0;i < mFragments.size();i++) {
|
||||
save(i, result);
|
||||
final var position = mFiles.size ();
|
||||
final var fragment = EditorFragment
|
||||
.newInstance (file, project, selection)
|
||||
.setFileOpenListener (listener)
|
||||
.setModificationStateListener (this);
|
||||
|
||||
mFiles.add (new OpenedFile (file, fragment));
|
||||
notifyDataSetChanged ();
|
||||
return position;
|
||||
} else {
|
||||
return openedFileIndex;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the editor that have opened the given file.
|
||||
* Does nothing if the file is not opened.
|
||||
*
|
||||
* @param file The file to close.
|
||||
* @return The index of the editor that was closed. -1 if no files were closed.
|
||||
*/
|
||||
public int closeFile (File file) {
|
||||
final var index = findIndexOfEditorByFile (file);
|
||||
if (index == -1) {
|
||||
LOG.error ("File is not opened. File: " + file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
closeFileAt (index);
|
||||
return index;
|
||||
}
|
||||
|
||||
public void save(int index, SaveResult result) {
|
||||
if (index >= 0 && index < mFragments.size()) {
|
||||
EditorFragment frag = getFrag(index);
|
||||
if (frag == null || frag.getFile() == null) {
|
||||
|
||||
/**
|
||||
* Close the file at the given index. Does nothing if the index is invalid.
|
||||
* @param index The index of file to close.
|
||||
*/
|
||||
public void closeFileAt (int index) {
|
||||
if (index < 0 || index >= getItemCount ()) {
|
||||
LOG.error ("Invalid file index. Cannot close any files");
|
||||
return;
|
||||
}
|
||||
|
||||
// Save the file before closing
|
||||
var opened = mFiles.get (index);
|
||||
opened.fragment.save ();
|
||||
opened.fragment.getEditor ().close (); // Send 'textDocument/didClose' to language servers.
|
||||
opened = null;
|
||||
|
||||
mFiles.remove (index);
|
||||
notifyDataSetChanged ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all the opened files.
|
||||
* @see #closeFileAt(int)
|
||||
*/
|
||||
public void closeAllFiles () {
|
||||
// Close all files one by one
|
||||
// This will make sure that we save all the files and send 'textDocument/didClose' to language servers.
|
||||
for (int i = 0; i < getItemCount (); i++) {
|
||||
closeFileAt (i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all the files except the file at the given index.
|
||||
* @param index The index of the file that should not be closed.
|
||||
*/
|
||||
public void closeOthers (int index) {
|
||||
for (int i = 0; i < getItemCount (); i++) {
|
||||
if (i != index) {
|
||||
closeFileAt (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SaveResult saveAll () {
|
||||
SaveResult result = new SaveResult ();
|
||||
for (int i = 0; i < mFiles.size (); i++) {
|
||||
save (i, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void save (int index, SaveResult result) {
|
||||
if (index >= 0 && index < mFiles.size ()) {
|
||||
EditorFragment frag = getFrag (index);
|
||||
if (frag == null || frag.getFile () == null) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Must be called before frag.save()
|
||||
* Otherwise, it'll always return false
|
||||
*/
|
||||
final boolean modified = frag.isModified();
|
||||
// Must be called before frag.save()
|
||||
// Otherwise, it'll always return false
|
||||
final boolean modified = frag.isModified ();
|
||||
|
||||
frag.save();
|
||||
frag.save ();
|
||||
|
||||
final boolean isGradle = frag.getFile().getName().endsWith(EditorFragment.EXT_GRADLE);
|
||||
final boolean isXml = frag.getFile().getName().endsWith(EditorFragment.EXT_XML);
|
||||
final boolean isGradle = frag.getFile ().getName ().endsWith (EditorFragment.EXT_GRADLE);
|
||||
final boolean isXml = frag.getFile ().getName ().endsWith (EditorFragment.EXT_XML);
|
||||
|
||||
if (!result.gradleSaved) {
|
||||
result.gradleSaved = modified && isGradle;
|
||||
}
|
||||
|
||||
|
||||
if (!result.xmlSaved) {
|
||||
result.xmlSaved = modified && isXml;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public EditorFragment getFrag(int index) {
|
||||
return (EditorFragment) getItem(index);
|
||||
}
|
||||
|
||||
public List<Fragment> getFragments() {
|
||||
return mFragments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified(EditorFragment editor) {
|
||||
if(mEditorStateListener != null)
|
||||
mEditorStateListener.editorStateChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaved(EditorFragment editor) {
|
||||
if(mEditorStateListener != null)
|
||||
mEditorStateListener.editorStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public List<File> getOpenedFiles() {
|
||||
return mOpenedFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fragment getItem(int p1) {
|
||||
return p1 < 0 || p1 >= mFragments.size() ? null : mFragments.get(p1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mFragments.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
return getFrag(position).getTabTitle();
|
||||
}
|
||||
public EditorFragment getFrag (int index) {
|
||||
return mFiles.get (index).fragment;
|
||||
}
|
||||
|
||||
public static interface EditorStateListener {
|
||||
void editorStateChanged();
|
||||
public String getEditorTitle (int index) {
|
||||
return mFiles.get (index).file.getName ();
|
||||
}
|
||||
|
||||
public List<OpenedFile> getFiles () {
|
||||
return mFiles;
|
||||
}
|
||||
|
||||
public OpenedFile getOpenedFile (int index) {
|
||||
return mFiles.get (index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onModified (EditorFragment editor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaved (EditorFragment editor) {
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment (int position) {
|
||||
return getFrag (position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount () {
|
||||
return mFiles.size ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId (int position) {
|
||||
return mFiles.get (position).hashCode ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsItem (long itemId) {
|
||||
for (final var file : mFiles) {
|
||||
if (itemId == file.hashCode ()) { // see getItemId(int)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class OpenedFile {
|
||||
|
||||
public final File file;
|
||||
public final EditorFragment fragment;
|
||||
|
||||
private OpenedFile (File file, EditorFragment fragment) {
|
||||
this.file = file;
|
||||
this.fragment = fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass () != o.getClass ()) {
|
||||
return false;
|
||||
}
|
||||
OpenedFile that = (OpenedFile) o;
|
||||
return Objects.equals (file, that.file) && Objects.equals (fragment, that.fragment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode () {
|
||||
return Objects.hash (file, fragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +81,7 @@ public class StudioApp extends BaseApplication {
|
||||
if(this.uncaughtExceptionHandler != null) {
|
||||
this.uncaughtExceptionHandler.uncaughtException(thread, th);
|
||||
}
|
||||
System.exit (1);
|
||||
} catch (Throwable error) {
|
||||
LOG.error ("Unable to show crash handler activity", error);
|
||||
}
|
||||
|
||||
@@ -5,22 +5,23 @@
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
**************************************************************************************/
|
||||
package com.itsaky.androidide.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.blankj.utilcode.util.FileIOUtils;
|
||||
import com.blankj.utilcode.util.SizeUtils;
|
||||
import com.itsaky.androidide.adapters.CompletionListAdapter;
|
||||
@@ -38,15 +39,18 @@ import com.itsaky.androidide.tasks.TaskExecutor;
|
||||
import com.itsaky.androidide.tasks.callables.ReadFileTask;
|
||||
import com.itsaky.androidide.utils.LSPUtils;
|
||||
import com.itsaky.androidide.utils.TypefaceUtils;
|
||||
|
||||
import io.github.rosemoe.editor.interfaces.EditorEventListener;
|
||||
import io.github.rosemoe.editor.langs.EmptyLanguage;
|
||||
import io.github.rosemoe.editor.widget.CodeEditor;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.eclipse.lsp4j.Diagnostic;
|
||||
@@ -54,16 +58,16 @@ import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
|
||||
public class EditorFragment extends BaseFragment implements EditorEventListener {
|
||||
|
||||
public FragmentEditorBinding mBinding;
|
||||
private File mFile;
|
||||
private boolean isRead = false;
|
||||
private boolean isModified = false;
|
||||
private boolean isFirstCreate = false;
|
||||
|
||||
|
||||
public FragmentEditorBinding mBinding;
|
||||
private File mFile;
|
||||
private boolean isRead = false;
|
||||
private boolean isModified = false;
|
||||
private boolean isFirstCreate = false;
|
||||
|
||||
private ModificationStateListener mModificationStateListener;
|
||||
private FileOpenListener mOpenListener;
|
||||
private static AndroidProject mProject;
|
||||
private static AndroidProject mProject;
|
||||
|
||||
public static final String KEY_FILE_PATH = "file_path";
|
||||
public static final String KEY_PROJECT = "project";
|
||||
@@ -72,371 +76,401 @@ public class EditorFragment extends BaseFragment implements EditorEventListener
|
||||
public static final String KEY_COLUMN_START = "col_start";
|
||||
public static final String KEY_COLUMN_END = "col_end";
|
||||
|
||||
public static final String EXT_JAVA = ".java";
|
||||
public static final String EXT_XML = ".xml";
|
||||
public static final String EXT_HTML = ".html";
|
||||
public static final String EXT_GRADLE = ".gradle";
|
||||
public static final String EXT_GROOVY = ".groovy";
|
||||
public static final String EXT_KOTLIN = ".kt";
|
||||
public static final String EXT_JSON = ".json";
|
||||
public static final String EXT_JAVA = ".java";
|
||||
public static final String EXT_XML = ".xml";
|
||||
public static final String EXT_HTML = ".html";
|
||||
public static final String EXT_GRADLE = ".gradle";
|
||||
public static final String EXT_GROOVY = ".groovy";
|
||||
public static final String EXT_KOTLIN = ".kt";
|
||||
public static final String EXT_JSON = ".json";
|
||||
|
||||
public EditorFragment setModificationStateListener(ModificationStateListener listener) {
|
||||
public EditorFragment setModificationStateListener (ModificationStateListener listener) {
|
||||
this.mModificationStateListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getTabTitle() {
|
||||
if(getFile() != null) {
|
||||
String title = getFile().getName();
|
||||
if(isModified())
|
||||
public String getTabTitle () {
|
||||
if (getFile () != null) {
|
||||
String title = getFile ().getName ();
|
||||
if (isModified ()) {
|
||||
title += "*";
|
||||
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public FragmentEditorBinding getBinding() {
|
||||
public FragmentEditorBinding getBinding () {
|
||||
return mBinding;
|
||||
}
|
||||
|
||||
public static EditorFragment newInstance(File file, AndroidProject project, Range selection) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KEY_FILE_PATH, file.getAbsolutePath());
|
||||
bundle.putInt(KEY_LINE_START, selection.getStart().getLine());
|
||||
bundle.putInt(KEY_LINE_END, selection.getEnd().getLine());
|
||||
bundle.putInt(KEY_COLUMN_START, selection.getStart().getCharacter());
|
||||
bundle.putInt(KEY_COLUMN_END, selection.getEnd().getCharacter());
|
||||
bundle.putParcelable(KEY_PROJECT, project);
|
||||
EditorFragment frag = new EditorFragment();
|
||||
frag.setArguments(bundle);
|
||||
return frag;
|
||||
}
|
||||
public static EditorFragment newInstance (File file, AndroidProject project, Range selection) {
|
||||
Bundle bundle = new Bundle ();
|
||||
bundle.putString (KEY_FILE_PATH, file.getAbsolutePath ());
|
||||
bundle.putInt (KEY_LINE_START, selection.getStart ().getLine ());
|
||||
bundle.putInt (KEY_LINE_END, selection.getEnd ().getLine ());
|
||||
bundle.putInt (KEY_COLUMN_START, selection.getStart ().getCharacter ());
|
||||
bundle.putInt (KEY_COLUMN_END, selection.getEnd ().getCharacter ());
|
||||
bundle.putParcelable (KEY_PROJECT, project);
|
||||
EditorFragment frag = new EditorFragment ();
|
||||
frag.setArguments (bundle);
|
||||
return frag;
|
||||
}
|
||||
|
||||
public EditorFragment setFileOpenListener(FileOpenListener openListener) {
|
||||
public EditorFragment setFileOpenListener (FileOpenListener openListener) {
|
||||
this.mOpenListener = openListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CodeEditor getEditor() {
|
||||
public CodeEditor getEditor () {
|
||||
if (mBinding == null) {
|
||||
return null;
|
||||
}
|
||||
return mBinding.editor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
isFirstCreate = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
save();
|
||||
super.onSaveInstanceState(outState);
|
||||
public void onCreate (Bundle savedInstanceState) {
|
||||
super.onCreate (savedInstanceState);
|
||||
isFirstCreate = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
mBinding = FragmentEditorBinding.inflate(inflater, container, false);
|
||||
return mBinding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
if (getActivity() == null || getArguments() == null || !getArguments().containsKey(KEY_FILE_PATH) || !getArguments().containsKey(KEY_PROJECT)) return;
|
||||
mFile = new File(getArguments().getString(KEY_FILE_PATH));
|
||||
mProject = getArguments().getParcelable(KEY_PROJECT);
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState (Bundle outState) {
|
||||
save ();
|
||||
super.onSaveInstanceState (outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
mBinding = FragmentEditorBinding.inflate (inflater, container, false);
|
||||
return mBinding.getRoot ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated (View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated (view, savedInstanceState);
|
||||
if (getActivity () == null || getArguments () == null || !getArguments ().containsKey (KEY_FILE_PATH) || !getArguments ().containsKey (KEY_PROJECT)) {
|
||||
return;
|
||||
}
|
||||
mFile = new File (getArguments ().getString (KEY_FILE_PATH));
|
||||
mProject = getArguments ().getParcelable (KEY_PROJECT);
|
||||
|
||||
mBinding.editor.setOverScrollEnabled(false);
|
||||
mBinding.editor.setTypefaceText(TypefaceUtils.jetbrainsMono());
|
||||
mBinding.editor.setTextActionMode(CodeEditor.TextActionMode.ACTION_MODE);
|
||||
mBinding.editor.setHighlightCurrentBlock(true);
|
||||
mBinding.editor.setEventListener(this);
|
||||
mBinding.editor.setAutoCompletionOnComposing(true);
|
||||
mBinding.editor.setAutoCompletionItemAdapter(new CompletionListAdapter());
|
||||
mBinding.editor.setLineColorsEnabled(true);
|
||||
mBinding.editor.setDividerWidth(SizeUtils.dp2px(1));
|
||||
mBinding.editor.setOverScrollEnabled (false);
|
||||
mBinding.editor.setTypefaceText (TypefaceUtils.jetbrainsMono ());
|
||||
mBinding.editor.setTextActionMode (CodeEditor.TextActionMode.ACTION_MODE);
|
||||
mBinding.editor.setHighlightCurrentBlock (true);
|
||||
mBinding.editor.setEventListener (this);
|
||||
mBinding.editor.setAutoCompletionOnComposing (true);
|
||||
mBinding.editor.setAutoCompletionItemAdapter (new CompletionListAdapter ());
|
||||
mBinding.editor.setLineColorsEnabled (true);
|
||||
mBinding.editor.setDividerWidth (SizeUtils.dp2px (1));
|
||||
|
||||
mBinding.diagnosticTextContainer.setVisibility(View.GONE);
|
||||
mBinding.diagnosticTextContainer.setVisibility (View.GONE);
|
||||
|
||||
configureEditorIfNeeded();
|
||||
|
||||
final Range range = fromArgs(getArguments());
|
||||
new TaskExecutor().executeAsync(new ReadFileTask(mFile), result -> {
|
||||
mBinding.editor.setText(result);
|
||||
postRead();
|
||||
mBinding.editor.post(() -> {
|
||||
if(LSPUtils.isEqual(range.getStart(), range.getEnd())) {
|
||||
getEditor().setSelection(range.getStart().getLine(), range.getStart().getCharacter());
|
||||
configureEditorIfNeeded ();
|
||||
|
||||
final Range range = fromArgs (getArguments ());
|
||||
new TaskExecutor ().executeAsync (new ReadFileTask (mFile), result -> {
|
||||
mBinding.editor.setText (result);
|
||||
postRead ();
|
||||
mBinding.editor.post (() -> {
|
||||
if (LSPUtils.isEqual (range.getStart (), range.getEnd ())) {
|
||||
getEditor ().setSelection (range.getStart ().getLine (), range.getStart ().getCharacter ());
|
||||
} else {
|
||||
getEditor().setSelectionRegion(range.getStart().getLine(), range.getStart().getCharacter(), range.getEnd().getLine(), range.getEnd().getCharacter());
|
||||
getEditor ().setSelectionRegion (range.getStart ().getLine (), range.getStart ().getCharacter (), range.getEnd ().getLine (), range.getEnd ().getCharacter ());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private Range fromArgs(Bundle args) {
|
||||
if(!(args.containsKey(KEY_LINE_START)
|
||||
&& args.containsKey(KEY_COLUMN_START)
|
||||
&& args.containsKey(KEY_LINE_END)
|
||||
&& args.containsKey(KEY_COLUMN_END)))
|
||||
});
|
||||
}
|
||||
|
||||
private Range fromArgs (Bundle args) {
|
||||
if (!(args.containsKey (KEY_LINE_START)
|
||||
&& args.containsKey (KEY_COLUMN_START)
|
||||
&& args.containsKey (KEY_LINE_END)
|
||||
&& args.containsKey (KEY_COLUMN_END))) {
|
||||
return LSPUtils.Range_ofZero;
|
||||
|
||||
return new Range(
|
||||
new Position(
|
||||
args.getInt(KEY_LINE_START),
|
||||
args.getInt(KEY_COLUMN_START)),
|
||||
new Position(
|
||||
args.getInt(KEY_LINE_END),
|
||||
args.getInt(KEY_COLUMN_END)
|
||||
}
|
||||
|
||||
return new Range (
|
||||
new Position (
|
||||
args.getInt (KEY_LINE_START),
|
||||
args.getInt (KEY_COLUMN_START)),
|
||||
new Position (
|
||||
args.getInt (KEY_LINE_END),
|
||||
args.getInt (KEY_COLUMN_END)
|
||||
));
|
||||
}
|
||||
|
||||
public void setDiagnostics(List<Diagnostic> diags) {
|
||||
if(diags == null && mBinding.editor != null) {
|
||||
mBinding.editor.getEditorLanguage().getAnalyzer().updateDiagnostics(new HashMap<Integer, Map<Integer, Diagnostic>>());
|
||||
public void setDiagnostics (List<Diagnostic> diags) {
|
||||
if (diags == null && mBinding.editor != null) {
|
||||
mBinding.editor.getEditorLanguage ().getAnalyzer ().updateDiagnostics (new HashMap<Integer, Map<Integer, Diagnostic>> ());
|
||||
return;
|
||||
}
|
||||
if(mBinding.editor != null) {
|
||||
Map<Integer, Map<Integer, Diagnostic>> map = new HashMap<>();
|
||||
for(int i=0;i<diags.size();i++) {
|
||||
final Diagnostic d = diags.get(i);
|
||||
if(d == null) continue;
|
||||
final Range range = d.getRange();
|
||||
final int line = range.getStart().getLine();
|
||||
final int column = range.getStart().getCharacter();
|
||||
Map<Integer, Diagnostic> mappedByColumn = map.get(line);
|
||||
if(mappedByColumn == null) {
|
||||
mappedByColumn = new HashMap<>();
|
||||
if (mBinding.editor != null) {
|
||||
Map<Integer, Map<Integer, Diagnostic>> map = new HashMap<> ();
|
||||
for (int i = 0; i < diags.size (); i++) {
|
||||
final Diagnostic d = diags.get (i);
|
||||
if (d == null) {
|
||||
continue;
|
||||
}
|
||||
mappedByColumn.put(column, d);
|
||||
map.put(line, mappedByColumn);
|
||||
final Range range = d.getRange ();
|
||||
final int line = range.getStart ().getLine ();
|
||||
final int column = range.getStart ().getCharacter ();
|
||||
Map<Integer, Diagnostic> mappedByColumn = map.get (line);
|
||||
if (mappedByColumn == null) {
|
||||
mappedByColumn = new HashMap<> ();
|
||||
}
|
||||
mappedByColumn.put (column, d);
|
||||
map.put (line, mappedByColumn);
|
||||
}
|
||||
mBinding.editor.getEditorLanguage().getAnalyzer().updateDiagnostics(map);
|
||||
mBinding.editor.getEditorLanguage ().getAnalyzer ().updateDiagnostics (map);
|
||||
}
|
||||
}
|
||||
|
||||
private void configureEditorIfNeeded() {
|
||||
boolean sizeChanged = isFirstCreate || ConstantsBridge.EDITORPREF_SIZE_CHANGED;
|
||||
boolean flagsChanged = isFirstCreate || ConstantsBridge.EDITORPREF_FLAGS_CHANGED;
|
||||
boolean drawHexChanged = isFirstCreate || ConstantsBridge.EDITORPREF_DRAW_HEX_CHANGED;
|
||||
final PreferenceManager prefs = getStudioActivity().getApp().getPrefManager();
|
||||
if(sizeChanged) {
|
||||
float textSize = prefs.getFloat(PreferenceManager.KEY_EDITOR_FONT_SIZE);
|
||||
if(textSize < 6 || textSize > 32)
|
||||
textSize = 14;
|
||||
mBinding.editor.setTextSize(textSize);
|
||||
ConstantsBridge.EDITORPREF_SIZE_CHANGED = false;
|
||||
}
|
||||
|
||||
if(flagsChanged) {
|
||||
int flags = 0;
|
||||
if(prefs.getBoolean(PreferenceManager.KEY_EDITORFLAG_WS_LEADING, true))
|
||||
flags |= CodeEditor.FLAG_DRAW_WHITESPACE_LEADING;
|
||||
if(prefs.getBoolean(PreferenceManager.KEY_EDITORFLAG_WS_TRAILING, false))
|
||||
flags |= CodeEditor.FLAG_DRAW_WHITESPACE_TRAILING;
|
||||
if(prefs.getBoolean(PreferenceManager.KEY_EDITORFLAG_WS_INNER, true))
|
||||
flags |= CodeEditor.FLAG_DRAW_WHITESPACE_INNER;
|
||||
if(prefs.getBoolean(PreferenceManager.KEY_EDITORFLAG_WS_EMPTY_LINE, true))
|
||||
flags |= CodeEditor.FLAG_DRAW_WHITESPACE_FOR_EMPTY_LINE;
|
||||
if(prefs.getBoolean(PreferenceManager.KEY_EDITORFLAG_LINE_BREAK, true))
|
||||
flags |= CodeEditor.FLAG_DRAW_LINE_SEPARATOR;
|
||||
|
||||
mBinding.editor.setNonPrintablePaintingFlags(flags);
|
||||
ConstantsBridge.EDITORPREF_FLAGS_CHANGED = false;
|
||||
}
|
||||
|
||||
if(drawHexChanged) {
|
||||
mBinding.editor.setLineColorsEnabled(prefs.getBoolean(PreferenceManager.KEY_EDITOR_DRAW_HEX, true));
|
||||
ConstantsBridge.EDITORPREF_DRAW_HEX_CHANGED = false;
|
||||
}
|
||||
|
||||
isFirstCreate = false;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return mBinding.editor.getText().toString();
|
||||
}
|
||||
|
||||
public boolean isModified() {
|
||||
return isModified;
|
||||
}
|
||||
|
||||
public void undo() {
|
||||
if(mBinding.editor.canUndo())
|
||||
mBinding.editor.undo();
|
||||
}
|
||||
|
||||
public void redo() {
|
||||
if(mBinding.editor.canRedo())
|
||||
mBinding.editor.redo();
|
||||
}
|
||||
|
||||
public void findDefinition() {
|
||||
mBinding.editor.findDefinition();
|
||||
}
|
||||
|
||||
public void findReferences() {
|
||||
mBinding.editor.findReferences();
|
||||
private void configureEditorIfNeeded () {
|
||||
boolean sizeChanged = isFirstCreate || ConstantsBridge.EDITORPREF_SIZE_CHANGED;
|
||||
boolean flagsChanged = isFirstCreate || ConstantsBridge.EDITORPREF_FLAGS_CHANGED;
|
||||
boolean drawHexChanged = isFirstCreate || ConstantsBridge.EDITORPREF_DRAW_HEX_CHANGED;
|
||||
final PreferenceManager prefs = getStudioActivity ().getApp ().getPrefManager ();
|
||||
if (sizeChanged) {
|
||||
float textSize = prefs.getFloat (PreferenceManager.KEY_EDITOR_FONT_SIZE);
|
||||
if (textSize < 6 || textSize > 32) {
|
||||
textSize = 14;
|
||||
}
|
||||
mBinding.editor.setTextSize (textSize);
|
||||
ConstantsBridge.EDITORPREF_SIZE_CHANGED = false;
|
||||
}
|
||||
|
||||
if (flagsChanged) {
|
||||
int flags = 0;
|
||||
if (prefs.getBoolean (PreferenceManager.KEY_EDITORFLAG_WS_LEADING, true)) {
|
||||
flags |= CodeEditor.FLAG_DRAW_WHITESPACE_LEADING;
|
||||
}
|
||||
if (prefs.getBoolean (PreferenceManager.KEY_EDITORFLAG_WS_TRAILING, false)) {
|
||||
flags |= CodeEditor.FLAG_DRAW_WHITESPACE_TRAILING;
|
||||
}
|
||||
if (prefs.getBoolean (PreferenceManager.KEY_EDITORFLAG_WS_INNER, true)) {
|
||||
flags |= CodeEditor.FLAG_DRAW_WHITESPACE_INNER;
|
||||
}
|
||||
if (prefs.getBoolean (PreferenceManager.KEY_EDITORFLAG_WS_EMPTY_LINE, true)) {
|
||||
flags |= CodeEditor.FLAG_DRAW_WHITESPACE_FOR_EMPTY_LINE;
|
||||
}
|
||||
if (prefs.getBoolean (PreferenceManager.KEY_EDITORFLAG_LINE_BREAK, true)) {
|
||||
flags |= CodeEditor.FLAG_DRAW_LINE_SEPARATOR;
|
||||
}
|
||||
|
||||
mBinding.editor.setNonPrintablePaintingFlags (flags);
|
||||
ConstantsBridge.EDITORPREF_FLAGS_CHANGED = false;
|
||||
}
|
||||
|
||||
if (drawHexChanged) {
|
||||
mBinding.editor.setLineColorsEnabled (prefs.getBoolean (PreferenceManager.KEY_EDITOR_DRAW_HEX, true));
|
||||
ConstantsBridge.EDITORPREF_DRAW_HEX_CHANGED = false;
|
||||
}
|
||||
|
||||
isFirstCreate = false;
|
||||
}
|
||||
|
||||
public void commentLine() {
|
||||
mBinding.editor.commentLine();
|
||||
public String getText () {
|
||||
return mBinding.editor.getText ().toString ();
|
||||
}
|
||||
|
||||
public void uncommentLine() {
|
||||
mBinding.editor.uncommentLine();
|
||||
public boolean isModified () {
|
||||
return isModified;
|
||||
}
|
||||
|
||||
public void beginSearch() {
|
||||
mBinding.editor.beginSearchMode();
|
||||
public void undo () {
|
||||
if (mBinding.editor.canUndo ()) {
|
||||
mBinding.editor.undo ();
|
||||
}
|
||||
}
|
||||
|
||||
public void save() {
|
||||
if(mFile == null || mBinding == null || mBinding.editor == null || mBinding.editor.getText() == null) return;
|
||||
final String text = mBinding.editor.getText().toString();
|
||||
final boolean wrote = FileIOUtils.writeFileFromString(mFile, text);
|
||||
notifySaved(wrote, text);
|
||||
isModified = false;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return mFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
configureEditorIfNeeded();
|
||||
}
|
||||
|
||||
private void postRead() {
|
||||
if (mFile.isFile() && mFile.getName().endsWith(EXT_JAVA)) {
|
||||
mBinding.editor.setEditorLanguage(new JavaLanguage(getFile()));
|
||||
} else if (mFile.isFile() && mFile.getName().endsWith(EXT_XML)) {
|
||||
mBinding.editor.setEditorLanguage(new XMLLanguage(getFile()));
|
||||
} else if (mFile.isFile() && mFile.getName().endsWith(EXT_GRADLE)) {
|
||||
mBinding.editor.setEditorLanguage(new GroovyLanguage(getFile()));
|
||||
} else {
|
||||
mBinding.editor.setEditorLanguage(new EmptyLanguage());
|
||||
}
|
||||
public void redo () {
|
||||
if (mBinding.editor.canRedo ()) {
|
||||
mBinding.editor.redo ();
|
||||
}
|
||||
}
|
||||
|
||||
public void findDefinition () {
|
||||
mBinding.editor.findDefinition ();
|
||||
}
|
||||
|
||||
public void findReferences () {
|
||||
mBinding.editor.findReferences ();
|
||||
}
|
||||
|
||||
public void commentLine () {
|
||||
mBinding.editor.commentLine ();
|
||||
}
|
||||
|
||||
public void uncommentLine () {
|
||||
mBinding.editor.uncommentLine ();
|
||||
}
|
||||
|
||||
public void beginSearch () {
|
||||
mBinding.editor.beginSearchMode ();
|
||||
}
|
||||
|
||||
public void save () {
|
||||
if (mFile == null || mBinding == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String text = mBinding.editor.getText ().toString ();
|
||||
final boolean wrote = FileIOUtils.writeFileFromString (mFile, text);
|
||||
notifySaved (wrote, text);
|
||||
isModified = false;
|
||||
}
|
||||
|
||||
public File getFile () {
|
||||
return mFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume () {
|
||||
super.onResume ();
|
||||
configureEditorIfNeeded ();
|
||||
}
|
||||
|
||||
private void postRead () {
|
||||
if (mFile.isFile () && mFile.getName ().endsWith (EXT_JAVA)) {
|
||||
mBinding.editor.setEditorLanguage (new JavaLanguage (getFile ()));
|
||||
} else if (mFile.isFile () && mFile.getName ().endsWith (EXT_XML)) {
|
||||
mBinding.editor.setEditorLanguage (new XMLLanguage (getFile ()));
|
||||
} else if (mFile.isFile () && mFile.getName ().endsWith (EXT_GRADLE)) {
|
||||
mBinding.editor.setEditorLanguage (new GroovyLanguage (getFile ()));
|
||||
} else {
|
||||
mBinding.editor.setEditorLanguage (new EmptyLanguage ());
|
||||
}
|
||||
|
||||
// File must be set only after setting the language
|
||||
// This will make sure that textDocument/didOpen is sent
|
||||
mBinding.editor.setFile(getFile());
|
||||
mBinding.editor.setFile (getFile ());
|
||||
|
||||
mBinding.editor.setColorScheme(new SchemeAndroidIDE());
|
||||
isRead = true;
|
||||
if(mOpenListener != null)
|
||||
mOpenListener.onOpenSuccessful(getFile(), getText());
|
||||
}
|
||||
|
||||
private void closeCurrentTag(String text, int line, int col) {
|
||||
mBinding.editor.setColorScheme (new SchemeAndroidIDE ());
|
||||
isRead = true;
|
||||
if (mOpenListener != null) {
|
||||
mOpenListener.onOpenSuccessful (getFile (), getText ());
|
||||
}
|
||||
}
|
||||
|
||||
private void closeCurrentTag (String text, int line, int col) {
|
||||
try {
|
||||
XMLLexer lexer = new XMLLexer(CharStreams.fromReader(new StringReader(text)));
|
||||
XMLLexer lexer = new XMLLexer (CharStreams.fromReader (new StringReader (text)));
|
||||
Token token;
|
||||
boolean wasSlash = false, wasOpen = false;
|
||||
ArrayList<String> currentNames = new ArrayList<>();
|
||||
while (((token = lexer.nextToken()) != null && token.getType() != token.EOF)) {
|
||||
final int type = token.getType();
|
||||
if(type == XMLLexer.OPEN) {
|
||||
ArrayList<String> currentNames = new ArrayList<> ();
|
||||
while (((token = lexer.nextToken ()) != null && token.getType () != token.EOF)) {
|
||||
final int type = token.getType ();
|
||||
if (type == XMLLexer.OPEN) {
|
||||
wasOpen = true;
|
||||
} else if(type == XMLLexer.Name) {
|
||||
if(wasOpen && wasSlash && currentNames.size() > 0) {
|
||||
currentNames.remove(0);
|
||||
} else if(wasOpen){
|
||||
currentNames.add(0, token.getText());
|
||||
} else if (type == XMLLexer.Name) {
|
||||
if (wasOpen && wasSlash && currentNames.size () > 0) {
|
||||
currentNames.remove (0);
|
||||
} else if (wasOpen) {
|
||||
currentNames.add (0, token.getText ());
|
||||
wasOpen = false;
|
||||
}
|
||||
} else if(type == XMLLexer.OPEN_SLASH) {
|
||||
int l = token.getLine() - 1;
|
||||
int c = token.getCharPositionInLine();
|
||||
if(l == line && c == col) {
|
||||
} else if (type == XMLLexer.OPEN_SLASH) {
|
||||
int l = token.getLine () - 1;
|
||||
int c = token.getCharPositionInLine ();
|
||||
if (l == line && c == col) {
|
||||
break;
|
||||
} else if(currentNames.size() > 0)
|
||||
currentNames.remove(0);
|
||||
} else if(type == XMLLexer.SLASH_CLOSE
|
||||
|| type == XMLLexer.SPECIAL_CLOSE) {
|
||||
if(currentNames.size() > 0 && token.getText().trim().endsWith("/>"))
|
||||
currentNames.remove(0);
|
||||
} else if(type == XMLLexer.SLASH) {
|
||||
} else if (currentNames.size () > 0) {
|
||||
currentNames.remove (0);
|
||||
}
|
||||
} else if (type == XMLLexer.SLASH_CLOSE
|
||||
|| type == XMLLexer.SPECIAL_CLOSE) {
|
||||
if (currentNames.size () > 0 && token.getText ().trim ().endsWith ("/>")) {
|
||||
currentNames.remove (0);
|
||||
}
|
||||
} else if (type == XMLLexer.SLASH) {
|
||||
wasSlash = true;
|
||||
} else wasOpen = wasSlash = false;
|
||||
} else {
|
||||
wasOpen = wasSlash = false;
|
||||
}
|
||||
}
|
||||
if(currentNames.size() > 0) {
|
||||
mBinding.editor.getText().insert(line, col + 2, currentNames.get(0));
|
||||
if (currentNames.size () > 0) {
|
||||
mBinding.editor.getText ().insert (line, col + 2, currentNames.get (0));
|
||||
}
|
||||
} catch (Throwable th) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onRequestFormat(CodeEditor editor, boolean async) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFormatFail(CodeEditor editor, Throwable cause) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFormatSucceed(CodeEditor editor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewTextSet(CodeEditor editor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetSelection(int startLine, int startCol, int endLine, int endCol) {
|
||||
|
||||
} catch (Throwable th) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterDelete(CodeEditor editor, CharSequence content, int startLine, int startColumn, int endLine, int endColumn, CharSequence deletedContent) {
|
||||
isModified = true;
|
||||
notifyModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterInsert(CodeEditor editor, CharSequence content, int startLine, int startColumn, int endLine, int endColumn, CharSequence insertedContent) {
|
||||
isModified = true;
|
||||
@Override
|
||||
public boolean onRequestFormat (CodeEditor editor, boolean async) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFormatFail (CodeEditor editor, Throwable cause) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFormatSucceed (CodeEditor editor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewTextSet (CodeEditor editor) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSetSelection (int startLine, int startCol, int endLine, int endCol) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterDelete (CodeEditor editor, CharSequence content, int startLine, int startColumn, int endLine, int endColumn, CharSequence deletedContent) {
|
||||
isModified = true;
|
||||
notifyModified ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterInsert (CodeEditor editor, CharSequence content, int startLine, int startColumn, int endLine, int endColumn, CharSequence insertedContent) {
|
||||
isModified = true;
|
||||
|
||||
if(getFile() != null && getFile().getName().endsWith(EXT_XML)) {
|
||||
if (getFile () != null && getFile ().getName ().endsWith (EXT_XML)) {
|
||||
boolean isOpen = false;
|
||||
try {
|
||||
isOpen = editor.getText().charAt(editor.getCursor().getLeft() - 2) == '<';
|
||||
} catch (Throwable th) {}
|
||||
if(isOpen && insertedContent.toString().equals("/")) {
|
||||
closeCurrentTag(editor.getText().toString(), endLine, endColumn);
|
||||
isOpen = editor.getText ().charAt (editor.getCursor ().getLeft () - 2) == '<';
|
||||
} catch (Throwable th) {
|
||||
// ignored
|
||||
}
|
||||
if (isOpen && insertedContent.toString ().equals ("/")) {
|
||||
closeCurrentTag (editor.getText ().toString (), endLine, endColumn);
|
||||
}
|
||||
}
|
||||
|
||||
notifyModified();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeReplace(CodeEditor editor, CharSequence content) {
|
||||
}
|
||||
notifyModified ();
|
||||
}
|
||||
|
||||
private void notifySaved(boolean wrote, String text) {
|
||||
mBinding.editor.didSave();
|
||||
@Override
|
||||
public void beforeReplace (CodeEditor editor, CharSequence content) {
|
||||
}
|
||||
|
||||
private void notifySaved (boolean wrote, String text) {
|
||||
mBinding.editor.didSave ();
|
||||
|
||||
if(mModificationStateListener != null)
|
||||
mModificationStateListener.onSaved(this);
|
||||
if (mModificationStateListener != null) {
|
||||
mModificationStateListener.onSaved (this);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyModified() {
|
||||
if(mModificationStateListener != null)
|
||||
mModificationStateListener.onModified(this);
|
||||
private void notifyModified () {
|
||||
if (mModificationStateListener != null) {
|
||||
mModificationStateListener.onModified (this);
|
||||
}
|
||||
}
|
||||
|
||||
public static interface FileOpenListener {
|
||||
void onOpenSuccessful(File file, String text);
|
||||
public interface FileOpenListener {
|
||||
void onOpenSuccessful (File file, String text);
|
||||
}
|
||||
|
||||
public static interface ModificationStateListener {
|
||||
void onModified(EditorFragment editor);
|
||||
void onSaved(EditorFragment editor);
|
||||
public interface ModificationStateListener {
|
||||
void onModified (EditorFragment editor);
|
||||
|
||||
void onSaved (EditorFragment editor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ import com.blankj.utilcode.util.ClipboardUtils;
|
||||
import com.blankj.utilcode.util.FileIOUtils;
|
||||
import com.blankj.utilcode.util.FileUtils;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.itsaky.androidide.EditorActivity;
|
||||
import com.itsaky.androidide.R;
|
||||
import com.itsaky.androidide.adapters.viewholders.FileTreeViewHolder;
|
||||
import com.itsaky.androidide.databinding.LayoutCreateFileJavaBinding;
|
||||
@@ -299,7 +298,7 @@ public class FileOptionsHandler extends IDEHandler implements OptionsListFragmen
|
||||
}
|
||||
EditorFragment frag = activity().getPagerAdapter().findEditorByFile(f);
|
||||
if(frag != null) {
|
||||
activity().closeFile(activity().getPagerAdapter().getFragments().indexOf(frag));
|
||||
activity().closeFile(activity().getPagerAdapter().getFiles ().indexOf(frag));
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
/************************************************************************************
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
**************************************************************************************/
|
||||
package com.itsaky.androidide.views;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
/**
|
||||
Copied from StackOverflow
|
||||
@see https://stackoverflow.com/a/47143096
|
||||
*/
|
||||
|
||||
public class NonSwipableViewPager extends ViewPager
|
||||
{
|
||||
public NonSwipableViewPager(Context ctx)
|
||||
{
|
||||
super(ctx);
|
||||
}
|
||||
|
||||
public NonSwipableViewPager(Context context, AttributeSet attrs)
|
||||
{
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -50,12 +50,11 @@
|
||||
app:tabIndicatorHeight="@dimen/file_tab_height"
|
||||
app:tabTextAppearance="@style/AppTheme.TabLayout.Title"
|
||||
app:tabSelectedTextColor="@color/primaryTextColor"
|
||||
app:tabMode="scrollable"
|
||||
app:tabGravity="fill"/>
|
||||
app:tabMode="scrollable" />
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<com.itsaky.androidide.views.NonSwipableViewPager
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/editor_viewPager"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_width="match_parent"
|
||||
|
||||
Reference in New Issue
Block a user