diff --git a/app/src/main/assets/data/common/tooling-api-all.jar b/app/src/main/assets/data/common/tooling-api-all.jar
index 77f5294457..6fa1c8591f 100644
Binary files a/app/src/main/assets/data/common/tooling-api-all.jar and b/app/src/main/assets/data/common/tooling-api-all.jar differ
diff --git a/app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt b/app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt
index 13a1dd18e8..25133a9f0c 100644
--- a/app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt
+++ b/app/src/main/java/com/itsaky/androidide/activities/editor/EditorHandlerActivity.kt
@@ -251,9 +251,6 @@ open class EditorHandlerActivity : ProjectHandlerActivity(), IEditorHandler {
log.info("Opening file at index:", position, "file: ", file)
val editor = CodeEditorView(this, file, selection!!)
- editor.editor.subscribeEvent(ContentChangeEvent::class.java) { event, _ ->
- onEditorContentChanged(event)
- }
editor.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
binding.editorContainer.addView(editor)
@@ -365,11 +362,9 @@ open class EditorHandlerActivity : ProjectHandlerActivity(), IEditorHandler {
}
}
- private fun onEditorContentChanged(event: ContentChangeEvent) {
- if (event.action != ContentChangeEvent.ACTION_SET_NEW_TEXT) {
- viewModel.setFilesModified(true)
- invalidateOptionsMenu()
- }
+ private fun onEditorContentChanged() {
+ viewModel.setFilesModified(true)
+ invalidateOptionsMenu()
}
override fun areFilesModified(): Boolean {
@@ -542,6 +537,9 @@ open class EditorHandlerActivity : ProjectHandlerActivity(), IEditorHandler {
@Subscribe(threadMode = ThreadMode.MAIN)
fun onDocumentChange(event: DocumentChangeEvent) {
+ // update content modification status
+ onEditorContentChanged()
+
val index = findIndexOfEditorByFile(event.file.toFile())
if (index == -1) {
return
diff --git a/app/src/main/java/com/itsaky/androidide/ui/editor/CodeEditorView.java b/app/src/main/java/com/itsaky/androidide/ui/editor/CodeEditorView.java
index 61f224ddb0..5e99caef60 100644
--- a/app/src/main/java/com/itsaky/androidide/ui/editor/CodeEditorView.java
+++ b/app/src/main/java/com/itsaky/androidide/ui/editor/CodeEditorView.java
@@ -118,6 +118,12 @@ public CodeEditorView(
final var editor = getEditor();
editor.post(() -> {
editor.setText(contents, createEditorArgs());
+
+ // editor.setText(...) sets the modified flag to true
+ // but in this case, file is read from disk and hence the contents are not modified at all
+ // so the flag must be changed to unmodified
+ // TODO: Find a better way to check content modification status
+ editor.markUnmodified();
postRead();
selection.validate();
diff --git a/app/src/main/res/xml/ide_file_provider_paths.xml b/app/src/main/res/xml/ide_file_provider_paths.xml
index ee86c813ba..7ee76a55e4 100644
--- a/app/src/main/res/xml/ide_file_provider_paths.xml
+++ b/app/src/main/res/xml/ide_file_provider_paths.xml
@@ -14,12 +14,11 @@
~ You should have received a copy of the GNU General Public License
~ along with AndroidIDE. If not, see .
-->
-
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
diff --git a/changelogs/v2.4.1-beta.md b/changelogs/v2.4.1-beta.md
new file mode 100644
index 0000000000..15592ded13
--- /dev/null
+++ b/changelogs/v2.4.1-beta.md
@@ -0,0 +1,10 @@
+# AndroidIDE v2.4.1-beta
+
+## Important notes
+
+- The terminal packages have been moved to `packages.androidide.com/apt/termux-main`.
+
+## Fixes
+
+- Project initialization fails if the project contains a `java-library` module.
+- Classes from the same package are imported when selecting a class completion item (#869).
\ No newline at end of file
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/ui/EditorActionsMenu.kt b/editor/src/main/java/com/itsaky/androidide/editor/ui/EditorActionsMenu.kt
index 463798ffbd..bfa6fae5ec 100644
--- a/editor/src/main/java/com/itsaky/androidide/editor/ui/EditorActionsMenu.kt
+++ b/editor/src/main/java/com/itsaky/androidide/editor/ui/EditorActionsMenu.kt
@@ -83,6 +83,11 @@ open class EditorActionsMenu constructor(val editor: IDEEditor) :
private var mLastScroll: Long = 0
private var mLastPosition: Int = 0
+ private val contentHeight by lazy {
+ // approximated size is around 56dp
+ SizeUtils.dp2px(56f)
+ }
+
private val menu: MenuBuilder = MenuBuilder(editor.context)
protected open var location = ActionItem.Location.EDITOR_TEXT_ACTIONS
@@ -226,6 +231,8 @@ open class EditorActionsMenu constructor(val editor: IDEEditor) :
private fun selectTop(rect: RectF): Int {
val rowHeight = editor.rowHeight
+ // when the window is being shown for the first time, the height is 0
+ val height = if (this.height == 0) contentHeight else this.height
return if (rect.top - rowHeight * 3 / 2f > height) {
(rect.top - rowHeight * 3 / 2 - height).toInt()
} else {
@@ -325,7 +332,7 @@ open class EditorActionsMenu constructor(val editor: IDEEditor) :
override fun show() {
- if (editor.searcher.searching) {
+ if (editor.searcher.isSearching) {
// Do not show if user is searching text
return
}
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/ui/EditorSearchLayout.kt b/editor/src/main/java/com/itsaky/androidide/editor/ui/EditorSearchLayout.kt
index 5f9060989e..f3974c54f2 100644
--- a/editor/src/main/java/com/itsaky/androidide/editor/ui/EditorSearchLayout.kt
+++ b/editor/src/main/java/com/itsaky/androidide/editor/ui/EditorSearchLayout.kt
@@ -28,8 +28,8 @@ import android.view.inputmethod.EditorInfo
import android.widget.FrameLayout
import android.widget.PopupMenu
import com.itsaky.androidide.editor.databinding.LayoutFindInFileBinding
-import com.itsaky.androidide.resources.R
import com.itsaky.androidide.editor.ui.ReplaceAction.doReplace
+import com.itsaky.androidide.resources.R
import com.itsaky.androidide.utils.SingleTextWatcher
import io.github.rosemoe.sora.widget.EditorSearcher.SearchOptions
import java.util.regex.Pattern
@@ -47,6 +47,8 @@ class EditorSearchLayout(context: Context, val editor: IDEEditor) : FrameLayout(
private val findInFileBinding: LayoutFindInFileBinding
private val optionsMenu: PopupMenu
+ private var isSearching = false
+
init {
findInFileBinding = LayoutFindInFileBinding.inflate(LayoutInflater.from(context))
findInFileBinding.prev.setOnClickListener(::onSearchActionClick)
@@ -113,6 +115,7 @@ class EditorSearchLayout(context: Context, val editor: IDEEditor) : FrameLayout(
findInFileBinding.searchInput.removeTextChangedListener(this.searchInputTextWatcher)
findInFileBinding.root.visibility = GONE
this.searchInputTextWatcher = null
+ this.editor.searcher.onClose()
}
if (!searcher.hasQuery()) {
return
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.java b/editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.java
index c440bed593..1988be6395 100644
--- a/editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.java
+++ b/editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.java
@@ -722,10 +722,7 @@ public void ensureWindowsDismissed() {
* @param event The content change event.
*/
private void handleContentChange(ContentChangeEvent event, Unsubscribe unsubscribe) {
- if (event.getAction() != ContentChangeEvent.ACTION_SET_NEW_TEXT) {
- isModified = true;
- }
-
+ isModified = true;
if (getFile() == null) {
return;
}
diff --git a/editor/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt b/editor/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt
index 41732085aa..6f4914c5e7 100644
--- a/editor/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt
+++ b/editor/src/main/java/io/github/rosemoe/sora/widget/IDEEditorSearcher.kt
@@ -15,8 +15,6 @@
* along with AndroidIDE. If not, see .
*/
-@file:Suppress("DEPRECATION")
-
package io.github.rosemoe.sora.widget
import com.itsaky.androidide.editor.ui.IDEEditor
@@ -29,7 +27,7 @@ import com.itsaky.androidide.editor.ui.IDEEditor
*/
open class IDEEditorSearcher(editor: IDEEditor) : EditorSearcher(editor) {
- var searching = false
+ var isSearching = false
private set
protected fun getEditor(): CodeEditor {
@@ -67,11 +65,15 @@ open class IDEEditorSearcher(editor: IDEEditor) : EditorSearcher(editor) {
}
override fun stopSearch() {
- searching = false
+ isSearching = false
super.stopSearch()
}
+ fun onClose() {
+ isSearching = false
+ }
+
private fun markSearching() {
- searching = true
+ isSearching = true
}
}
diff --git a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/fragments/AttrValueEditorFragment.kt b/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/fragments/AttrValueEditorFragment.kt
index fdbf11a384..a59116a24f 100644
--- a/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/fragments/AttrValueEditorFragment.kt
+++ b/uidesigner/src/main/java/com/itsaky/androidide/uidesigner/fragments/AttrValueEditorFragment.kt
@@ -76,7 +76,7 @@ class AttrValueEditorFragment : Fragment() {
val header = this.header ?: return
val view = this.viewModel.view ?: return
val attr = this.viewModel.selectedAttr ?: return
-
+
val ns = attr.namespace?.prefix?.let { "${it}:" } ?: ""
header.name.text = "${ns}${attr.name}"
header.desc.text = attr.namespace?.uri ?: ""
@@ -90,10 +90,15 @@ class AttrValueEditorFragment : Fragment() {
)
textView.dropDownVerticalOffset = -binding.root.height
textView.showDropDown()
-
+
val value = binding.attrValue.text.toString()
attr.value = value
- view.applyAttribute(attr.copyAttr(value = value))
+ try {
+ view.applyAttribute(attr.copyAttr(value = value))
+ } catch (e: Exception) {
+ // When the user is editing the attribute value, it is always invalid and cannot be
+ // resolved. Exceptions may be thrown while parsing the value which should be ignored
+ }
}
textView.setText(attr.value)