diff --git a/app/src/main/java/com/itsaky/androidide/EditorActivity.java b/app/src/main/java/com/itsaky/androidide/EditorActivity.java index 7f7a57829..597547249 100755 --- a/app/src/main/java/com/itsaky/androidide/EditorActivity.java +++ b/app/src/main/java/com/itsaky/androidide/EditorActivity.java @@ -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> 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 frags = mPagerAdapter.getFragments (); - final List 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"); } diff --git a/app/src/main/java/com/itsaky/androidide/adapters/EditorPagerAdapter.java b/app/src/main/java/com/itsaky/androidide/adapters/EditorPagerAdapter.java index 74e35a593..4ff1e8571 100755 --- a/app/src/main/java/com/itsaky/androidide/adapters/EditorPagerAdapter.java +++ b/app/src/main/java/com/itsaky/androidide/adapters/EditorPagerAdapter.java @@ -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 . * -**************************************************************************************/ - + */ 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 mOpenedFiles; - private ArrayList mFragments; - private AndroidProject project; + private final AndroidProject project; + private final List 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 fragments, List 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 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 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 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); + } } } diff --git a/app/src/main/java/com/itsaky/androidide/app/StudioApp.java b/app/src/main/java/com/itsaky/androidide/app/StudioApp.java index ab70727a5..f6abb832d 100755 --- a/app/src/main/java/com/itsaky/androidide/app/StudioApp.java +++ b/app/src/main/java/com/itsaky/androidide/app/StudioApp.java @@ -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); } diff --git a/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java index 9b6792bb3..af8742851 100755 --- a/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java +++ b/app/src/main/java/com/itsaky/androidide/fragments/EditorFragment.java @@ -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 . * -**************************************************************************************/ + **************************************************************************************/ 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 diags) { - if(diags == null && mBinding.editor != null) { - mBinding.editor.getEditorLanguage().getAnalyzer().updateDiagnostics(new HashMap>()); + public void setDiagnostics (List diags) { + if (diags == null && mBinding.editor != null) { + mBinding.editor.getEditorLanguage ().getAnalyzer ().updateDiagnostics (new HashMap> ()); return; } - if(mBinding.editor != null) { - Map> map = new HashMap<>(); - for(int i=0;i mappedByColumn = map.get(line); - if(mappedByColumn == null) { - mappedByColumn = new HashMap<>(); + if (mBinding.editor != null) { + Map> 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 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 currentNames = new ArrayList<>(); - while (((token = lexer.nextToken()) != null && token.getType() != token.EOF)) { - final int type = token.getType(); - if(type == XMLLexer.OPEN) { + ArrayList 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); } } diff --git a/app/src/main/java/com/itsaky/androidide/handlers/FileOptionsHandler.java b/app/src/main/java/com/itsaky/androidide/handlers/FileOptionsHandler.java index bca266586..48872a6cf 100755 --- a/app/src/main/java/com/itsaky/androidide/handlers/FileOptionsHandler.java +++ b/app/src/main/java/com/itsaky/androidide/handlers/FileOptionsHandler.java @@ -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)); } } }) diff --git a/app/src/main/java/com/itsaky/androidide/views/NonSwipableViewPager.java b/app/src/main/java/com/itsaky/androidide/views/NonSwipableViewPager.java deleted file mode 100755 index 1df313972..000000000 --- a/app/src/main/java/com/itsaky/androidide/views/NonSwipableViewPager.java +++ /dev/null @@ -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 . - * -**************************************************************************************/ -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; - } -} diff --git a/app/src/main/res/layout/activity_editor.xml b/app/src/main/res/layout/activity_editor.xml index d6dd548ed..7823af778 100755 --- a/app/src/main/res/layout/activity_editor.xml +++ b/app/src/main/res/layout/activity_editor.xml @@ -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" /> -