diff --git a/.idea/misc.xml b/.idea/misc.xml
index 4fa9ac7c9..301599295 100755
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -10,8 +10,13 @@
-
+
+
+
+
+
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 69b3f5506..9bd4da35f 100755
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,89 +1,91 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+ tools:ignore="UnusedAttribute,MediaCapabilities">
+
+
+
-
-
-
+
-
-
-
-
+
+
-
-
-
-
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:windowSoftInputMode="adjustResize">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/itsaky/androidide/EditorActivity.java b/app/src/main/java/com/itsaky/androidide/EditorActivity.java
index 10ee3df3e..0b39aeedf 100755
--- a/app/src/main/java/com/itsaky/androidide/EditorActivity.java
+++ b/app/src/main/java/com/itsaky/androidide/EditorActivity.java
@@ -44,8 +44,6 @@ import androidx.appcompat.view.menu.MenuBuilder;
import androidx.core.content.ContextCompat;
import androidx.core.view.GravityCompat;
import androidx.fragment.app.Fragment;
-import androidx.recyclerview.widget.LinearLayoutManager;
-import androidx.recyclerview.widget.RecyclerView;
import androidx.transition.Slide;
import androidx.transition.TransitionManager;
@@ -54,20 +52,24 @@ import com.blankj.utilcode.util.IntentUtils;
import com.blankj.utilcode.util.KeyboardUtils;
import com.blankj.utilcode.util.SizeUtils;
import com.blankj.utilcode.util.ThreadUtils;
+import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.navigation.NavigationView;
import com.google.android.material.tabs.TabLayout;
-import com.google.android.material.transition.MaterialContainerTransform;
+import com.google.android.material.tabs.TabLayoutMediator;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.itsaky.androidide.adapters.DiagnosticsAdapter;
+import com.itsaky.androidide.adapters.EditorBottomSheetTabAdapter;
import com.itsaky.androidide.adapters.EditorPagerAdapter;
+import com.itsaky.androidide.adapters.SearchListAdapter;
import com.itsaky.androidide.app.StudioActivity;
import com.itsaky.androidide.databinding.ActivityEditorBinding;
import com.itsaky.androidide.databinding.LayoutDiagnosticInfoBinding;
import com.itsaky.androidide.databinding.LayoutSearchProjectBinding;
import com.itsaky.androidide.fragments.EditorFragment;
import com.itsaky.androidide.fragments.FileTreeFragment;
+import com.itsaky.androidide.fragments.SearchResultFragment;
import com.itsaky.androidide.fragments.sheets.OptionsListFragment;
import com.itsaky.androidide.fragments.sheets.ProgressSheet;
import com.itsaky.androidide.fragments.sheets.TextSheetFragment;
@@ -76,38 +78,39 @@ import com.itsaky.androidide.handlers.FileOptionsHandler;
import com.itsaky.androidide.handlers.IDEHandler;
import com.itsaky.androidide.interfaces.DiagnosticClickListener;
import com.itsaky.androidide.interfaces.EditorActivityProvider;
-import com.itsaky.androidide.language.logs.LogLanguageImpl;
+import com.itsaky.androidide.lsp.IDELanguageClientImpl;
import com.itsaky.androidide.lsp.LSP;
import com.itsaky.androidide.lsp.LSPProvider;
import com.itsaky.androidide.managers.PreferenceManager;
-import com.itsaky.androidide.project.AndroidProject;
import com.itsaky.androidide.models.DiagnosticGroup;
import com.itsaky.androidide.models.LogLine;
import com.itsaky.androidide.models.SaveResult;
import com.itsaky.androidide.models.SearchResult;
import com.itsaky.androidide.models.SheetOption;
+import com.itsaky.androidide.project.AndroidProject;
import com.itsaky.androidide.project.IDEProject;
import com.itsaky.androidide.services.LogReceiver;
import com.itsaky.androidide.services.builder.IDEService;
import com.itsaky.androidide.shell.ShellServer;
-import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE;
import com.itsaky.androidide.tasks.TaskExecutor;
import com.itsaky.androidide.utils.DialogUtils;
-import com.itsaky.inflater.ILayoutInflater;
+import com.itsaky.androidide.utils.EditorBottomSheetBehavior;
import com.itsaky.androidide.utils.LSPUtils;
import com.itsaky.androidide.utils.Logger;
import com.itsaky.androidide.utils.RecursiveFileSearcher;
import com.itsaky.androidide.utils.Symbols;
-import com.itsaky.androidide.utils.TransformUtils;
-import com.itsaky.androidide.utils.TypefaceUtils;
import com.itsaky.androidide.views.MaterialBanner;
import com.itsaky.androidide.views.SymbolInputView;
+import com.itsaky.inflater.ILayoutInflater;
import com.itsaky.lsp.services.IDELanguageServer;
import com.itsaky.toaster.Toaster;
import com.unnamed.b.atv.model.TreeNode;
-import io.github.rosemoe.editor.langs.EmptyLanguage;
-import io.github.rosemoe.editor.widget.CodeEditor;
+import org.eclipse.lsp4j.Diagnostic;
+import org.eclipse.lsp4j.DidChangeConfigurationParams;
+import org.eclipse.lsp4j.InitializeResult;
+import org.eclipse.lsp4j.Position;
+import org.jetbrains.annotations.Contract;
import java.io.File;
import java.util.ArrayList;
@@ -119,17 +122,10 @@ import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
+import io.github.rosemoe.editor.widget.CodeEditor;
import me.piruin.quickaction.ActionItem;
import me.piruin.quickaction.QuickAction;
-import org.eclipse.lsp4j.Diagnostic;
-import org.eclipse.lsp4j.DidChangeConfigurationParams;
-import org.eclipse.lsp4j.InitializeResult;
-import org.eclipse.lsp4j.Position;
-import org.jetbrains.annotations.Contract;
-
-import com.itsaky.androidide.lsp.IDELanguageClientImpl;
-
public class EditorActivity extends StudioActivity implements FileTreeFragment.FileActionListener,
TabLayout.OnTabSelectedListener,
NavigationView.OnNavigationItemSelectedListener,
@@ -142,14 +138,11 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
private ActivityEditorBinding mBinding;
private LayoutDiagnosticInfoBinding mDiagnosticInfoBinding;
private EditorPagerAdapter mPagerAdapter;
+ private EditorBottomSheetTabAdapter bottomSheetTabAdapter;
private FileTreeFragment mFileTreeFragment;
private EditorFragment mCurrentFragment;
public static File mCurrentFile;
private TreeNode mLastHeld;
- private CodeEditor buildView;
- private CodeEditor logView;
- private RecyclerView diagnosticList;
- private RecyclerView searchResultList;
private SymbolInputView symbolInput;
private AndroidProject mProject;
@@ -158,14 +151,15 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
private BuildServiceHandler mBuildServiceHandler;
private FileOptionsHandler mFileOptionsHandler;
- private LogLanguageImpl mLogLanguageImpl;
-
private QuickAction mTabCloseAction;
private TextSheetFragment mDaemonStatusFragment;
private OptionsListFragment mFileOptionsFragment;
private ProgressSheet mSearchingProgress;
private AlertDialog mFindInProjectDialog;
+ @SuppressWarnings("rawtypes")
+ private EditorBottomSheetBehavior mEditorBottomSheet;
+
private static final String TAG_FILE_OPTIONS_FRAGMENT = "file_options_fragment";
private static final org.eclipse.lsp4j.Range Range_ofZero = new org.eclipse.lsp4j.Range (new Position (0, 0), new Position (0, 0));
@@ -198,7 +192,6 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
R.id.menuEditor_lintRelease
};
-
@Override
protected View bindLayout () {
mBinding = ActivityEditorBinding.inflate (getLayoutInflater ());
@@ -222,13 +215,38 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
loadFragment (mFileTreeFragment);
symbolInput = new SymbolInputView (this);
- mBinding.inputContainer.addView (symbolInput, 0, new ViewGroup.LayoutParams (-1, -2));
+ mBinding.bottomSheet.textContainer.addView (symbolInput, 0, new ViewGroup.LayoutParams (-1, -2));
mBinding.editorViewPager.setOffscreenPageLimit (9);
mBinding.editorViewPager.setAdapter (mPagerAdapter);
mBinding.tabs.setupWithViewPager (mBinding.editorViewPager);
mBinding.tabs.addOnTabSelectedListener (this);
- mBinding.fabView.setOnClickListener (v -> showViewOptions ());
+
+ 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);
+
+ //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);
+ }
+ });
createQuickActions ();
@@ -256,18 +274,10 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
mBinding.getRoot ().closeDrawer (GravityCompat.START);
} else if (getDaemonStatusFragment ().isShowing ()) {
getDaemonStatusFragment ().dismiss ();
- } else if (mBinding.buildContainer.getVisibility () == View.VISIBLE) {
- hideBuildResult ();
- } else if (mBinding.logContainer.getVisibility () == View.VISIBLE) {
- hideLogResult ();
- } else if (mBinding.viewOptionsCard.getVisibility () == View.VISIBLE) {
- hideViewOptions ();
- } else if (mBinding.diagContainer.getVisibility () == View.VISIBLE) {
- hideDiagnostics ();
- } else if (mBinding.searchResultsContainer.getVisibility () == View.VISIBLE) {
- hideSearchResults ();
} else if (mFileOptionsFragment != null && mFileOptionsFragment.isShowing ()) {
mFileOptionsFragment.dismiss ();
+ } else if (mEditorBottomSheet.getState () == BottomSheetBehavior.STATE_EXPANDED) {
+ mEditorBottomSheet.setState (BottomSheetBehavior.STATE_COLLAPSED);
} else {
confirmProjectClose ();
}
@@ -492,17 +502,14 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
}
public void handleSearchResults (Map> results) {
- getSearchResultList ().setAdapter (new com.itsaky.androidide.adapters.SearchListAdapter (results, file -> {
+ setSearchResultAdapter (new com.itsaky.androidide.adapters.SearchListAdapter (results, file -> {
openFile (file);
- hideSearchResults ();
hideViewOptions ();
}, match -> {
openFileAndSelect (match.file, match);
- hideSearchResults ();
hideViewOptions ();
}));
- mBinding.transformScrim.setVisibility (View.VISIBLE);
- mBinding.fabView.setVisibility (View.GONE);
+
showSearchResults ();
if (mSearchingProgress != null && mSearchingProgress.isShowing ()) {
@@ -511,8 +518,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
}
public void appendApkLog (LogLine line) {
- getLogLanguage ().addLine (line);
- appendLogOut (line.toString ());
+ bottomSheetTabAdapter.getLogFragment ().appendLog (line);
}
public void setIDEProject (IDEProject project) {
@@ -520,31 +526,10 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
}
public void appendBuildOut (final String str) {
- runOnUiThread (() -> {
- String strFinal = str.endsWith ("\n") ? str : str.concat ("\n");
- getBuildView (true).getText ().append (strFinal);
- });
- }
-
- public void appendLogOut (final String str) {
- runOnUiThread (() -> {
- String strFinal = str.endsWith ("\n") ? str : str.concat ("\n");
- getLogView (true).getText ().append (strFinal);
- });
- }
-
- public void showFiles () {
- if (mBinding.viewOptionsCard.getVisibility () == View.VISIBLE) {
- hideViewOptions ();
- }
-
- mBinding.getRoot ().openDrawer (GravityCompat.END, true);
+ bottomSheetTabAdapter.getBuildOutputFragment ().appendOutput (str);
}
public void showDaemonStatus () {
- if (mBinding.viewOptionsCard.getVisibility () == View.VISIBLE) {
- hideViewOptions ();
- }
ShellServer shell = getApp ().newShell (t -> getDaemonStatusFragment ().append (t.toString ()));
shell.bgAppend (String.format ("echo '%s'", getString (R.string.msg_getting_daemom_status)));
shell.bgAppend (String.format ("cd '%s' && sh gradlew --status", mProject.getProjectPath ()));
@@ -553,107 +538,37 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
}
}
- public void hideToolbarAndTabs () {
- mBinding.editorAppBarLayout.setVisibility (View.INVISIBLE);
- }
-
- public void showToolbarAndTabs () {
- mBinding.editorAppBarLayout.setVisibility (View.VISIBLE);
- }
-
- public void showViewOptions () {
- try {
- if (mCurrentFragment != null && mCurrentFragment.getEditor () != null) {
- mCurrentFragment.getEditor ().hideAutoCompleteWindow ();
- mCurrentFragment.getEditor ().hideDiagnosticWindow ();
- }
-
- TransitionManager.beginDelayedTransition (mBinding.getRoot (), createContainerTransformFor (mBinding.fabView, mBinding.viewOptionsCard));
- mBinding.viewOptionsCard.setVisibility (View.VISIBLE);
- mBinding.transformScrim.setVisibility (View.VISIBLE);
- mBinding.fabView.setVisibility (View.GONE);
- } catch (Throwable e) {
- LOG.error ("Failed to show view options", e);
+ public void hideViewOptions () {
+ if (mEditorBottomSheet.getState () != BottomSheetBehavior.STATE_COLLAPSED) {
+ mEditorBottomSheet.setState (BottomSheetBehavior.STATE_COLLAPSED);
}
}
- public void hideViewOptions () {
- TransitionManager.beginDelayedTransition (mBinding.getRoot (), createContainerTransformFor (mBinding.viewOptionsCard, mBinding.fabView));
- mBinding.viewOptionsCard.setVisibility (View.GONE);
- mBinding.transformScrim.setVisibility (View.GONE);
- mBinding.fabView.setVisibility (View.VISIBLE);
- }
-
- public void showBuildResult () {
- TransitionManager.beginDelayedTransition (mBinding.getRoot (), createContainerTransformFor (mBinding.viewBuildOut, mBinding.buildContainer));
- mBinding.buildContainer.setVisibility (View.VISIBLE);
- mBinding.viewOptionsCard.setVisibility (View.GONE);
- hideToolbarAndTabs ();
- }
-
- public void hideBuildResult () {
- showToolbarAndTabs ();
- TransitionManager.beginDelayedTransition (mBinding.getRoot (), createContainerTransformFor (mBinding.buildContainer, mBinding.viewBuildOut));
- mBinding.buildContainer.setVisibility (View.GONE);
- mBinding.viewOptionsCard.setVisibility (View.VISIBLE);
- }
-
- public void showLogResult () {
- TransitionManager.beginDelayedTransition (mBinding.getRoot (), createContainerTransformFor (mBinding.viewLogs, mBinding.logContainer));
- mBinding.logContainer.setVisibility (View.VISIBLE);
- mBinding.viewOptionsCard.setVisibility (View.GONE);
- hideToolbarAndTabs ();
- }
-
- public void hideLogResult () {
- showToolbarAndTabs ();
-
- TransitionManager.beginDelayedTransition (mBinding.getRoot (), createContainerTransformFor (mBinding.logContainer, mBinding.viewLogs));
- mBinding.logContainer.setVisibility (View.GONE);
- mBinding.viewOptionsCard.setVisibility (View.VISIBLE);
- }
-
- public void showDiagnostics () {
- TransitionManager.beginDelayedTransition (mBinding.getRoot (), createContainerTransformFor (mBinding.viewDiags, mBinding.diagContainer));
- mBinding.diagContainer.setVisibility (View.VISIBLE);
- mBinding.viewOptionsCard.setVisibility (View.GONE);
- hideToolbarAndTabs ();
- }
-
- public void hideDiagnostics () {
- showToolbarAndTabs ();
- TransitionManager.beginDelayedTransition (mBinding.getRoot (), createContainerTransformFor (mBinding.diagContainer, mBinding.viewDiags));
- mBinding.diagContainer.setVisibility (View.GONE);
- mBinding.viewOptionsCard.setVisibility (View.VISIBLE);
- }
-
public void showSearchResults () {
- TransitionManager.beginDelayedTransition (mBinding.getRoot (), createContainerTransformFor (mBinding.viewSearchResults, mBinding.searchResultsContainer));
- mBinding.searchResultsContainer.setVisibility (View.VISIBLE);
- mBinding.viewOptionsCard.setVisibility (View.GONE);
- hideToolbarAndTabs ();
- }
-
- public void hideSearchResults () {
- showToolbarAndTabs ();
- TransitionManager.beginDelayedTransition (mBinding.getRoot (), createContainerTransformFor (mBinding.searchResultsContainer, mBinding.viewSearchResults));
- mBinding.searchResultsContainer.setVisibility (View.GONE);
- mBinding.viewOptionsCard.setVisibility (View.VISIBLE);
+ if (mEditorBottomSheet.getState () != BottomSheetBehavior.STATE_EXPANDED) {
+ mEditorBottomSheet.setState (BottomSheetBehavior.STATE_EXPANDED);
+ }
+
+ final int index = bottomSheetTabAdapter.findIndexOfFragmentByClass (SearchResultFragment.class);
+ if (index >= 0 && index < mBinding.bottomSheet.tabs.getTabCount ()) {
+ final var tab = mBinding.bottomSheet.tabs.getTabAt (index);
+ if (tab != null) {
+ tab.select ();
+ }
+ }
}
public void handleDiagnosticsResultVisibility (boolean errorVisible) {
- mBinding.diagEmptyView.setVisibility (errorVisible ? View.VISIBLE : View.GONE);
- getDiagnosticsList ().setVisibility (errorVisible ? View.GONE : View.VISIBLE);
+ bottomSheetTabAdapter.getDiagnosticsFragment ().handleResultVisibility (errorVisible);
}
public void handleSearchResultVisibility (boolean errorVisible) {
- mBinding.searchEmptyView.setVisibility (errorVisible ? View.VISIBLE : View.GONE);
- getSearchResultList ().setVisibility (errorVisible ? View.GONE : View.VISIBLE);
+ bottomSheetTabAdapter.getSearchResultFragment ().handleResultVisibility (errorVisible);
}
public void setStatus (final CharSequence text) {
try {
- runOnUiThread (() -> mBinding.editorStatusText.setText (text));
+ runOnUiThread (() -> mBinding.bottomSheet.statusText.setText (text));
} catch (Throwable th) {
LOG.error ("Failed to update status text", th);
}
@@ -682,7 +597,6 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
@Override
public void onDiagnosticClick (File file, @NonNull Diagnostic diagnostic) {
openFileAndSelect (file, diagnostic.getRange ());
- hideDiagnostics ();
hideViewOptions ();
}
@@ -843,85 +757,12 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
return mDaemonStatusFragment == null ? mDaemonStatusFragment = new TextSheetFragment ().setTextSelectable (true).setTitleText (R.string.gradle_daemon_status) : mDaemonStatusFragment;
}
- public CodeEditor getBuildView () {
- return getBuildView (false);
+ public void setDiagnosticsAdapter (@NonNull final DiagnosticsAdapter adapter) {
+ bottomSheetTabAdapter.getDiagnosticsFragment ().setAdapter (adapter);
}
- public CodeEditor getBuildView (boolean setup) {
- CodeEditor edit = buildView == null ? createBuildView () : buildView;
- if (setup && edit.getParent () == null) {
- setupContainers ();
- }
- return edit;
- }
-
- public CodeEditor createBuildView () {
- buildView = new CodeEditor (this);
- buildView.setEditable (false);
- buildView.setDividerWidth (0);
- buildView.setEditorLanguage (new EmptyLanguage ());
- buildView.setOverScrollEnabled (false);
- buildView.setTextActionMode (CodeEditor.TextActionMode.ACTION_MODE);
- buildView.setWordwrap (false);
- buildView.setUndoEnabled (false);
- buildView.setTypefaceLineNumber (TypefaceUtils.jetbrainsMono ());
- buildView.setTypefaceText (TypefaceUtils.jetbrainsMono ());
- buildView.setTextSize (12);
- buildView.setColorScheme (new SchemeAndroidIDE ());
- return buildView;
- }
-
- public CodeEditor getLogView () {
- return getLogView (false);
- }
-
- public CodeEditor getLogView (boolean setup) {
- CodeEditor edit = logView == null ? createLogView () : logView;
- if (setup && edit.getParent () == null) {
- setupContainers ();
- }
- return edit;
- }
-
- public CodeEditor createLogView () {
- logView = new CodeEditor (this);
- logView.setEditable (false);
- logView.setDividerWidth (0);
- logView.setEditorLanguage (getLogLanguage ());
- logView.setOverScrollEnabled (false);
- logView.setTextActionMode (CodeEditor.TextActionMode.ACTION_MODE);
- logView.setWordwrap (false);
- logView.setUndoEnabled (false);
- logView.setTypefaceLineNumber (TypefaceUtils.jetbrainsMono ());
- logView.setTypefaceText (TypefaceUtils.jetbrainsMono ());
- logView.setTextSize (12);
- buildView.setColorScheme (new SchemeAndroidIDE ());
- return logView;
- }
-
- public RecyclerView getDiagnosticsList () {
- return diagnosticList == null ? createDiagnosticsList () : diagnosticList;
- }
-
- public RecyclerView createDiagnosticsList () {
- diagnosticList = new RecyclerView (this);
- diagnosticList.setLayoutManager (new LinearLayoutManager (this));
- diagnosticList.setAdapter (new DiagnosticsAdapter (new ArrayList<> (), this));
- return diagnosticList;
- }
-
- public RecyclerView getSearchResultList () {
- return searchResultList == null ? createSearchResultList () : searchResultList;
- }
-
- public RecyclerView createSearchResultList () {
- searchResultList = new RecyclerView (this);
- searchResultList.setLayoutManager (new LinearLayoutManager (this));
- return searchResultList;
- }
-
- public LogLanguageImpl getLogLanguage () {
- return mLogLanguageImpl == null ? mLogLanguageImpl = new LogLanguageImpl () : mLogLanguageImpl;
+ public void setSearchResultAdapter (@NonNull final SearchListAdapter adapter) {
+ bottomSheetTabAdapter.getSearchResultFragment ().setAdapter (adapter);
}
@Override
@@ -1173,67 +1014,10 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
}
private void setupContainers () {
- removeFromParent (getBuildView ());
- removeFromParent (getLogView ());
- removeFromParent (getDiagnosticsList ());
- removeFromParent (getSearchResultList ());
-
- mBinding.buildOutcontainer.addView (getBuildView (), new ViewGroup.LayoutParams (-1, -1));
- mBinding.buildContainer.setVisibility (View.GONE);
- mBinding.buildOutToolbar.setNavigationOnClickListener (v -> hideBuildResult ());
- mBinding.buildOutToolbar.setOnClickListener (v -> hideBuildResult ());
-
- mBinding.buildOutToolbar.getMenu ().clear ();
- getMenuInflater ().inflate (R.menu.menu_build_output, mBinding.buildOutToolbar.getMenu ());
- mBinding.buildOutToolbar.setOnMenuItemClickListener (item -> {
- if (item.getItemId () == R.id.buildOut_clear) {
- getBuildView ().setText ("");
- setStatus ("");
- return true;
- }
- return false;
- });
-
- mBinding.logOutcontainer.addView (getLogView (), new ViewGroup.LayoutParams (-1, -1));
- mBinding.logContainer.setVisibility (View.GONE);
- mBinding.logOutToolbar.setNavigationOnClickListener (v -> hideLogResult ());
- mBinding.logOutToolbar.setOnClickListener (v -> hideLogResult ());
-
- mBinding.diagListContainer.addView (getDiagnosticsList (), new ViewGroup.LayoutParams (-1, -1));
- mBinding.diagContainer.setVisibility (View.GONE);
- mBinding.diagToolbar.setNavigationOnClickListener (v -> hideDiagnostics ());
- mBinding.diagToolbar.setOnClickListener (v -> hideDiagnostics ());
-
- mBinding.searchResultsListContainer.addView (getSearchResultList (), new ViewGroup.LayoutParams (-1, -1));
- mBinding.searchResultsContainer.setVisibility (View.GONE);
- mBinding.searchResultsToolbar.setNavigationOnClickListener (v -> hideSearchResults ());
- mBinding.searchResultsToolbar.setOnClickListener (v -> hideSearchResults ());
-
- mBinding.viewOptionsCard.setVisibility (View.GONE);
- mBinding.transformScrim.setVisibility (View.GONE);
-
- mBinding.transformScrim.setOnClickListener (v -> hideViewOptions ());
- mBinding.viewBuildOut.setOnClickListener (v -> showBuildResult ());
- mBinding.viewDiags.setOnClickListener (v -> showDiagnostics ());
- mBinding.viewSearchResults.setOnClickListener (v -> showSearchResults ());
- mBinding.viewLogs.setOnClickListener (v -> showLogResult ());
- mBinding.viewFiles.setOnClickListener (v -> showFiles ());
- mBinding.viewDaemonStatus.setOnClickListener (v -> showDaemonStatus ());
-
handleDiagnosticsResultVisibility (true);
handleSearchResultVisibility (true);
}
- @NonNull
- private MaterialContainerTransform createContainerTransformFor (View start, View end) {
- return createContainerTransformFor (start, end, mBinding.realContainer);
- }
-
- @NonNull
- private MaterialContainerTransform createContainerTransformFor (View start, View end, View drawingView) {
- return TransformUtils.createContainerTransformFor (start, end, drawingView);
- }
-
private void startServices () {
if (!IDELanguageClientImpl.isInitialized ()) {
@@ -1249,22 +1033,18 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
getBuildServiceHandler ().assembleDebug (false);
}
- private void removeFromParent (@NonNull View v) {
- if (v.getParent () != null && v.getParent () instanceof ViewGroup) {
- ((ViewGroup) v.getParent ()).removeView (v);
- }
- }
-
private void onSoftInputChanged () {
invalidateOptionsMenu ();
if (KeyboardUtils.isSoftInputVisible (this)) {
TransitionManager.beginDelayedTransition (mBinding.getRoot (), new Slide (Gravity.TOP));
symbolInput.setVisibility (View.VISIBLE);
- mBinding.fabView.hide ();
+ mBinding.bottomSheet.statusText.setVisibility (View.GONE);
+ mBinding.bottomSheet.swipeHint.setVisibility (View.GONE);
} else {
TransitionManager.beginDelayedTransition (mBinding.getRoot (), new Slide (Gravity.BOTTOM));
symbolInput.setVisibility (View.GONE);
- mBinding.fabView.show ();
+ mBinding.bottomSheet.statusText.setVisibility (View.VISIBLE);
+ mBinding.bottomSheet.swipeHint.setVisibility (View.VISIBLE);
}
}
diff --git a/app/src/main/java/com/itsaky/androidide/adapters/EditorBottomSheetTabAdapter.java b/app/src/main/java/com/itsaky/androidide/adapters/EditorBottomSheetTabAdapter.java
new file mode 100644
index 000000000..cb70ec05a
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/adapters/EditorBottomSheetTabAdapter.java
@@ -0,0 +1,118 @@
+/*
+ * 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.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.fragment.app.FragmentActivity;
+import androidx.viewpager2.adapter.FragmentStateAdapter;
+
+import com.itsaky.androidide.R;
+import com.itsaky.androidide.fragments.BuildOutputFragment;
+import com.itsaky.androidide.fragments.DiagnosticsListFragment;
+import com.itsaky.androidide.fragments.IDELogFragment;
+import com.itsaky.androidide.fragments.LogViewFragment;
+import com.itsaky.androidide.fragments.SearchResultFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class EditorBottomSheetTabAdapter extends FragmentStateAdapter {
+
+ private final List fragments;
+
+ public EditorBottomSheetTabAdapter (@NonNull FragmentActivity fragmentActivity) {
+ super (fragmentActivity);
+
+ this.fragments = new ArrayList<> ();
+ this.fragments.add (new Tab (fragmentActivity.getString (R.string.build_output), new BuildOutputFragment ()));
+ this.fragments.add (new Tab (fragmentActivity.getString (R.string.app_logs), new LogViewFragment ()));
+ this.fragments.add (new Tab (fragmentActivity.getString (R.string.ide_logs), new IDELogFragment ()));
+ this.fragments.add (new Tab (fragmentActivity.getString (R.string.view_diags), new DiagnosticsListFragment ()));
+ this.fragments.add (new Tab (fragmentActivity.getString (R.string.view_search_results), new SearchResultFragment ()));
+ }
+
+ @NonNull
+ @Override
+ public Fragment createFragment (int position) {
+ return this.fragments.get (position).fragment;
+ }
+
+ @Override
+ public int getItemCount () {
+ return fragments.size ();
+ }
+
+ public String getTitle (int position) {
+ return fragments.get (position).title;
+ }
+
+ @NonNull
+ public BuildOutputFragment getBuildOutputFragment () {
+ return Objects.requireNonNull (findFragmentByClass (BuildOutputFragment.class));
+ }
+
+ @NonNull
+ public LogViewFragment getLogFragment () {
+ return Objects.requireNonNull (findFragmentByClass (LogViewFragment.class));
+ }
+
+ @NonNull
+ public DiagnosticsListFragment getDiagnosticsFragment () {
+ return Objects.requireNonNull (findFragmentByClass (DiagnosticsListFragment.class));
+ }
+
+ @NonNull
+ public SearchResultFragment getSearchResultFragment () {
+ return Objects.requireNonNull (findFragmentByClass (SearchResultFragment.class));
+ }
+
+ @Nullable
+ private T findFragmentByClass (Class clazz) {
+ for (final var tab : this.fragments) {
+ if (tab.fragment.getClass () == clazz) {
+ return (T) tab.fragment;
+ }
+ }
+ return null;
+ }
+
+ public int findIndexOfFragmentByClass (Class tClass) {
+ for (int i = 0; i < this.fragments.size (); i++) {
+ final var tab = this.fragments.get (i);
+ if (tab.fragment.getClass () == tClass) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ static class Tab {
+
+ public Tab (String title, Fragment fragment) {
+ this.title = title;
+ this.fragment = fragment;
+ }
+
+ String title;
+ Fragment fragment;
+ }
+}
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/BuildOutputFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/BuildOutputFragment.java
new file mode 100644
index 000000000..f65b891c9
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/fragments/BuildOutputFragment.java
@@ -0,0 +1,58 @@
+/*
+ * 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.fragments;
+
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.blankj.utilcode.util.ThreadUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class BuildOutputFragment extends NonEditableEditorFragment {
+
+ private final List unsavedLines = new ArrayList<> ();
+
+ @Override
+ public void onViewCreated (@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated (view, savedInstanceState);
+
+ if (!unsavedLines.isEmpty ()) {
+ for (String line : unsavedLines) {
+ Objects.requireNonNull (getEditor ()).getText ().append (line.trim () + "\n");
+ }
+ unsavedLines.clear ();
+ }
+ }
+
+ public void appendOutput (String output) {
+ if (getEditor () == null) {
+ unsavedLines.add (output);
+ return;
+ }
+ ThreadUtils.runOnUiThread (() -> {
+ final var message = output == null || output.endsWith ("\n") ? output : output + "\n";
+ getEditor ().getText ().append (message);
+ });
+ }
+}
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/DiagnosticsListFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/DiagnosticsListFragment.java
new file mode 100644
index 000000000..2081c7841
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/fragments/DiagnosticsListFragment.java
@@ -0,0 +1,83 @@
+/*
+ * 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.fragments;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.itsaky.androidide.adapters.DiagnosticsAdapter;
+import com.itsaky.androidide.views.EmptyView;
+
+import java.util.ArrayList;
+
+public class DiagnosticsListFragment extends Fragment {
+
+ private RecyclerView list;
+ private EmptyView emptyView;
+
+ private DiagnosticsAdapter unsavedAdapter;
+
+ @Nullable
+ @Override
+ public View onCreateView (@NonNull LayoutInflater inflater, @Nullable ViewGroup parent, @Nullable Bundle savedInstanceState) {
+ final var container = new LinearLayout (inflater.getContext ());
+ container.setOrientation (LinearLayout.VERTICAL);
+ container.setLayoutParams (new ViewGroup.LayoutParams (-1, -1));
+
+ this.list = new RecyclerView (inflater.getContext ());
+ this.emptyView = new EmptyView (inflater.getContext ());
+
+ container.addView (list, new LinearLayout.LayoutParams (-1, -1));
+ container.addView (emptyView, new LinearLayout.LayoutParams (-1, -1));
+
+ return container;
+ }
+
+ @Override
+ public void onViewCreated (@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated (view, savedInstanceState);
+
+ list.setLayoutManager (new LinearLayoutManager (list.getContext ()));
+ list.setAdapter (unsavedAdapter != null ? unsavedAdapter : new DiagnosticsAdapter (new ArrayList<> (), null));
+ unsavedAdapter = null;
+ }
+
+ public void setAdapter (@NonNull DiagnosticsAdapter adapter) {
+ if (list != null) {
+ list.setAdapter (adapter);
+ } else {
+ unsavedAdapter = adapter;
+ }
+ }
+
+ public void handleResultVisibility (boolean error) {
+ if (emptyView != null && list != null) {
+ emptyView.setVisibility (error ? View.VISIBLE : View.GONE);
+ list.setVisibility (error ? View.GONE : View.VISIBLE);
+ }
+ }
+}
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/IDELogFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/IDELogFragment.java
new file mode 100644
index 000000000..8231d2b31
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/fragments/IDELogFragment.java
@@ -0,0 +1,21 @@
+/*
+ * 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.fragments;
+
+public class IDELogFragment extends LogViewFragment {
+}
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/LogViewFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/LogViewFragment.java
new file mode 100644
index 000000000..825a38675
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/fragments/LogViewFragment.java
@@ -0,0 +1,64 @@
+/*
+ * 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.fragments;
+
+import android.os.Bundle;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.blankj.utilcode.util.ThreadUtils;
+import com.itsaky.androidide.language.logs.LogLanguageImpl;
+import com.itsaky.androidide.models.LogLine;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class LogViewFragment extends NonEditableEditorFragment {
+
+ private final LogLanguageImpl language = new LogLanguageImpl ();
+ private final List unsavedLines = new ArrayList<> ();
+
+ @Override
+ public void onViewCreated (@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated (view, savedInstanceState);
+ Objects.requireNonNull (getEditor ()).setEditorLanguage (language);
+
+ if (!unsavedLines.isEmpty ()) {
+ for (var line : unsavedLines) {
+ language.addLine (line);
+ getEditor ().getText ().append (line.toString ().trim () + "\n");
+ }
+ unsavedLines.clear ();
+ }
+ }
+
+ public void appendLog (LogLine line) {
+ if (getEditor () == null) {
+ unsavedLines.add (line);
+ return;
+ }
+
+ this.language.addLine (line);
+ final var lineString = line.toString ();
+ final var msg = lineString.endsWith ("\n") ? lineString : lineString + "\n";
+ ThreadUtils.runOnUiThread (() -> getEditor ().getText ().append (msg));
+ }
+}
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/NonEditableEditorFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/NonEditableEditorFragment.java
new file mode 100644
index 000000000..ec8c78435
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/fragments/NonEditableEditorFragment.java
@@ -0,0 +1,72 @@
+/*
+ * 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.fragments;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+
+import com.itsaky.androidide.databinding.FragmentNonEditableEditorBinding;
+import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE;
+import com.itsaky.androidide.utils.TypefaceUtils;
+
+import io.github.rosemoe.editor.langs.EmptyLanguage;
+import io.github.rosemoe.editor.widget.CodeEditor;
+
+public abstract class NonEditableEditorFragment extends Fragment {
+
+ private FragmentNonEditableEditorBinding binding;
+
+ @Nullable
+ @Override
+ public View onCreateView (@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ this.binding = FragmentNonEditableEditorBinding.inflate (inflater, container, false);
+ return binding.getRoot ();
+ }
+
+ @Override
+ public void onViewCreated (@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated (view, savedInstanceState);
+
+ final var editor = binding.getRoot ();
+ editor.setEditable (false);
+ editor.setDividerWidth (0);
+ editor.setEditorLanguage (new EmptyLanguage ());
+ editor.setOverScrollEnabled (false);
+ editor.setTextActionMode (CodeEditor.TextActionMode.ACTION_MODE);
+ editor.setWordwrap (false);
+ editor.setUndoEnabled (false);
+ editor.setTypefaceLineNumber (TypefaceUtils.jetbrainsMono ());
+ editor.setTypefaceText (TypefaceUtils.jetbrainsMono ());
+ editor.setTextSize (12);
+ editor.setColorScheme (new SchemeAndroidIDE ());
+ }
+
+ @Nullable
+ public CodeEditor getEditor () {
+ if (binding == null) {
+ return null;
+ }
+ return binding.editor;
+ }
+}
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/SearchResultFragment.java b/app/src/main/java/com/itsaky/androidide/fragments/SearchResultFragment.java
new file mode 100644
index 000000000..ac1ce194b
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/fragments/SearchResultFragment.java
@@ -0,0 +1,81 @@
+/*
+ * 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.fragments;
+
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.itsaky.androidide.adapters.SearchListAdapter;
+import com.itsaky.androidide.views.EmptyView;
+
+public class SearchResultFragment extends Fragment {
+
+ private RecyclerView list;
+ private EmptyView emptyView;
+
+ private SearchListAdapter unsavedAdapter;
+
+ @Nullable
+ @Override
+ public View onCreateView (@NonNull LayoutInflater inflater, @Nullable ViewGroup parent, @Nullable Bundle savedInstanceState) {
+ final var container = new LinearLayout (inflater.getContext ());
+ container.setOrientation (LinearLayout.VERTICAL);
+ container.setLayoutParams (new ViewGroup.LayoutParams (-1, -1));
+
+ this.list = new RecyclerView (inflater.getContext ());
+ this.emptyView = new EmptyView (inflater.getContext ());
+
+ container.addView (list, new LinearLayout.LayoutParams (-1, -1));
+ container.addView (emptyView, new LinearLayout.LayoutParams (-1, -1));
+
+ return container;
+ }
+
+ @Override
+ public void onViewCreated (@NonNull View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated (view, savedInstanceState);
+
+ list.setLayoutManager (new LinearLayoutManager (list.getContext ()));
+ list.setAdapter (unsavedAdapter != null ? unsavedAdapter : new SearchListAdapter (null, null, null));
+ unsavedAdapter = null;
+ }
+
+ public void setAdapter (@NonNull final SearchListAdapter adapter) {
+ if (list == null) {
+ unsavedAdapter = adapter;
+ return;
+ }
+ this.list.setAdapter (adapter);
+ }
+
+ public void handleResultVisibility (boolean error) {
+ if (emptyView != null && list != null) {
+ emptyView.setVisibility (error ? View.VISIBLE : View.GONE);
+ list.setVisibility (error ? View.GONE : View.VISIBLE);
+ }
+ }
+}
diff --git a/app/src/main/java/com/itsaky/androidide/fragments/sheets/LogSheet.java b/app/src/main/java/com/itsaky/androidide/fragments/sheets/LogSheet.java
deleted file mode 100755
index 7f0199663..000000000
--- a/app/src/main/java/com/itsaky/androidide/fragments/sheets/LogSheet.java
+++ /dev/null
@@ -1,87 +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.fragments.sheets;
-
-import android.graphics.Typeface;
-import android.util.TypedValue;
-import android.view.ViewGroup;
-import android.widget.HorizontalScrollView;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-import android.widget.TextView;
-import com.blankj.utilcode.util.ThrowableUtils;
-import com.itsaky.androidide.R;
-import com.itsaky.androidide.models.LogLine;
-import android.annotation.SuppressLint;
-
-public class LogSheet extends BaseBottomSheetFragment {
-
- private ScrollView verticalScroll;
- private LinearLayout mContainer;
-
- @Override
- protected void bind(LinearLayout container) {
- mContainer = new LinearLayout(getContext());
- mContainer.setOrientation(LinearLayout.VERTICAL);
-
- verticalScroll = new ScrollView(getContext());
- verticalScroll.setFillViewport(true);
-
- HorizontalScrollView scroll = new HorizontalScrollView(getContext());
- scroll.setFillViewport(true);
-
- container.removeAllViews();
- verticalScroll.removeAllViews();
- mContainer.removeAllViews();
- scroll.removeAllViews();
-
- container.addView(verticalScroll);
- verticalScroll.addView(scroll, new ScrollView.LayoutParams(-1, -1));
- scroll.addView(mContainer, new HorizontalScrollView.LayoutParams(-1, -1));
- }
-
- @Override
- protected String getTitle() {
- return getString(R.string.logs);
- }
-
- public void addLine(LogLine line) {
- if(line != null) {
- try {
- mContainer.addView(createLogTextView(line), new ViewGroup.LayoutParams(-1, -2));
- verticalScroll.scrollTo(0, mContainer.getChildAt(mContainer.getChildCount() - 1).getBottom());
- } catch (Throwable th) {}
- }
- }
-
- @SuppressLint("SetTextI18n")
- protected TextView createLogTextView(LogLine line) {
- TextView text = new TextView(getContext());
- text.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
- text.setTextColor(line.getColor(getContext()));
- text.setText(line + "");
- text.setSingleLine(true);
- text.setMaxLines(1);
- text.setTypeface(Typeface.MONOSPACE);
- return text;
- }
-}
diff --git a/app/src/main/java/com/itsaky/androidide/lsp/IDELanguageClientImpl.java b/app/src/main/java/com/itsaky/androidide/lsp/IDELanguageClientImpl.java
index 53c0bbb26..457100e35 100755
--- a/app/src/main/java/com/itsaky/androidide/lsp/IDELanguageClientImpl.java
+++ b/app/src/main/java/com/itsaky/androidide/lsp/IDELanguageClientImpl.java
@@ -359,7 +359,7 @@ public class IDELanguageClientImpl implements IDELanguageClient {
if(!file.exists() || !file.isFile()) return;
diagnostics.put(file, params.getDiagnostics());
- activity().getDiagnosticsList().setAdapter(newDiagnosticsAdapter());
+ activity().setDiagnosticsAdapter(newDiagnosticsAdapter());
EditorFragment editor = null;
if(activity().getPagerAdapter() != null && (editor = activity().getPagerAdapter().findEditorByFile(file)) != null) {
@@ -382,7 +382,7 @@ public class IDELanguageClientImpl implements IDELanguageClient {
if(error) {
- activity().getSearchResultList().setAdapter(new SearchListAdapter(null, null, null));
+ activity().setSearchResultAdapter (new SearchListAdapter(null, null, null));
return;
}
diff --git a/app/src/main/java/com/itsaky/androidide/services/IDELogService.java b/app/src/main/java/com/itsaky/androidide/services/IDELogService.java
new file mode 100644
index 000000000..a4aae68d8
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/services/IDELogService.java
@@ -0,0 +1,38 @@
+/*
+ * 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.services;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class IDELogService extends Service {
+
+ public IDELogService () {
+ }
+
+ @Override
+ public void onCreate () {
+ super.onCreate ();
+ }
+
+ @Override
+ public IBinder onBind (Intent intent) {
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/itsaky/androidide/utils/EditorBottomSheetBehavior.java b/app/src/main/java/com/itsaky/androidide/utils/EditorBottomSheetBehavior.java
new file mode 100644
index 000000000..2067958d0
--- /dev/null
+++ b/app/src/main/java/com/itsaky/androidide/utils/EditorBottomSheetBehavior.java
@@ -0,0 +1,68 @@
+/*
+ * 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.utils;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+
+import com.google.android.material.bottomsheet.BottomSheetBehavior;
+import com.itsaky.androidide.databinding.LayoutEditorBottomSheetBinding;
+
+public class EditorBottomSheetBehavior extends BottomSheetBehavior {
+
+ private LayoutEditorBottomSheetBinding binding;
+
+ public EditorBottomSheetBehavior (Context context, AttributeSet attributeSet) {
+ super(context, attributeSet);
+
+ setSaveFlags (SAVE_ALL);
+ }
+
+ public void setBinding (LayoutEditorBottomSheetBinding binding) {
+ this.binding = binding;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent (@NonNull CoordinatorLayout parent, @NonNull V child, @NonNull MotionEvent event) {
+ if (binding != null) {
+ final var rect = getPagerRect ();
+ if (rect.contains (event.getX (), event.getY ())) {
+ return false;
+ }
+ }
+
+ return super.onInterceptTouchEvent (parent, child, event);
+ }
+
+ @NonNull
+ private RectF getPagerRect () {
+ final var rect = new RectF ();
+ rect.left = binding.pager.getX ();
+ rect.top = binding.pager.getY ();
+ rect.right = rect.left + binding.pager.getWidth ();
+ rect.bottom = rect.top + binding.pager.getHeight ();
+ return rect;
+ }
+}
diff --git a/app/src/main/res/layout/activity_download.xml b/app/src/main/res/layout/activity_download.xml
index c13c57226..a77a3bd34 100755
--- a/app/src/main/res/layout/activity_download.xml
+++ b/app/src/main/res/layout/activity_download.xml
@@ -57,7 +57,7 @@
diff --git a/app/src/main/res/layout/activity_editor.xml b/app/src/main/res/layout/activity_editor.xml
index a2ee7b88e..e08d8fe00 100755
--- a/app/src/main/res/layout/activity_editor.xml
+++ b/app/src/main/res/layout/activity_editor.xml
@@ -8,24 +8,22 @@
android:id="@+id/editor_drawerLayout"
android:animateLayoutChanges="true">
-
-
+
+ app:layout_behavior="com.google.android.material.appbar.AppBarLayout$Behavior">
-
-
-
+
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/layout_diagnostic_info.xml b/app/src/main/res/layout/layout_diagnostic_info.xml
index e535c2023..744d49f31 100755
--- a/app/src/main/res/layout/layout_diagnostic_info.xml
+++ b/app/src/main/res/layout/layout_diagnostic_info.xml
@@ -1,11 +1,9 @@
-
+ android:textIsSelectable="true" />
diff --git a/app/src/main/res/layout/layout_editor_bottom_sheet.xml b/app/src/main/res/layout/layout_editor_bottom_sheet.xml
new file mode 100644
index 000000000..aa47429a7
--- /dev/null
+++ b/app/src/main/res/layout/layout_editor_bottom_sheet.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index bafc8e7f5..2f7073d94 100755
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -26,9 +26,9 @@
Discussions on Telegram
I have nothing to show you…
Terminal
- @android:string/ok
Reset
- Logs
+ App Logs
+ IDE Logs
Splash image
Cancel
Get started
@@ -339,5 +339,6 @@
Code generation failed
Failed to generate XML code. Would you like to exit anyway?
UI Designer returned invalid result
+ Swipe up for build output, logs and more.