mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
fix: completion window improvements
- fixed a bug which resulted in selected completion item not being indicated properly (closes #1242) - added option to set selected completion item background color in color schemes
This commit is contained in:
+32
-36
@@ -16,9 +16,9 @@
|
||||
*/
|
||||
package com.itsaky.androidide.editor.adapters
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import android.content.res.Resources
|
||||
import android.graphics.Typeface
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.text.TextUtils
|
||||
import android.util.TypedValue
|
||||
import android.view.LayoutInflater
|
||||
@@ -29,7 +29,6 @@ import com.itsaky.androidide.editor.R
|
||||
import com.itsaky.androidide.editor.databinding.LayoutCompletionItemBinding
|
||||
import com.itsaky.androidide.lookup.Lookup
|
||||
import com.itsaky.androidide.lsp.models.ClassCompletionData
|
||||
import com.itsaky.androidide.lsp.models.CompletionItem as LspCompletionItem
|
||||
import com.itsaky.androidide.lsp.models.CompletionItemKind.CLASS
|
||||
import com.itsaky.androidide.lsp.models.CompletionItemKind.CONSTRUCTOR
|
||||
import com.itsaky.androidide.lsp.models.CompletionItemKind.ENUM
|
||||
@@ -49,26 +48,19 @@ import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.COMPLETION_WND
|
||||
import com.itsaky.androidide.syntax.colorschemes.SchemeAndroidIDE.COMPLETION_WND_TEXT_TYPE
|
||||
import com.itsaky.androidide.tasks.executeAsync
|
||||
import com.itsaky.androidide.utils.customOrJBMono
|
||||
import com.itsaky.androidide.utils.resolveAttr
|
||||
import com.itsaky.androidide.xml.versions.ApiVersions
|
||||
import com.itsaky.androidide.xml.versions.Info
|
||||
import io.github.rosemoe.sora.lang.completion.CompletionItem
|
||||
import io.github.rosemoe.sora.widget.component.EditorAutoCompletion
|
||||
import io.github.rosemoe.sora.widget.component.EditorCompletionAdapter
|
||||
import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
|
||||
import com.itsaky.androidide.lsp.models.CompletionItem as LspCompletionItem
|
||||
|
||||
class CompletionListAdapter : EditorCompletionAdapter() {
|
||||
|
||||
override fun attachValues(window: EditorAutoCompletion, items: List<CompletionItem>) {
|
||||
super.attachValues(window, items)
|
||||
}
|
||||
|
||||
override fun getItemHeight(): Int {
|
||||
return TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
40f,
|
||||
Resources.getSystem().displayMetrics
|
||||
)
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
40f,
|
||||
Resources.getSystem().displayMetrics
|
||||
)
|
||||
.toInt()
|
||||
}
|
||||
|
||||
@@ -97,12 +89,7 @@ class CompletionListAdapter : EditorCompletionAdapter() {
|
||||
if (desc.isEmpty()) {
|
||||
binding.completionDetail.visibility = View.GONE
|
||||
}
|
||||
binding.root.setBackgroundColor(
|
||||
context.resolveAttr(
|
||||
if (isCurrentCursorPosition) R.color.completionList_backgroundSelected
|
||||
else R.color.completionList_background
|
||||
)
|
||||
)
|
||||
|
||||
binding.completionApiInfo.visibility = View.GONE
|
||||
|
||||
applyColorScheme(binding, isCurrentCursorPosition)
|
||||
@@ -111,15 +98,8 @@ class CompletionListAdapter : EditorCompletionAdapter() {
|
||||
}
|
||||
|
||||
private fun applyColorScheme(binding: LayoutCompletionItemBinding, isCurrent: Boolean) {
|
||||
var color =
|
||||
if (isCurrent) getThemeColor(SchemeAndroidIDE.COMPLETION_WND_BG_CURRENT_ITEM)
|
||||
else getThemeColor(EditorColorScheme.COMPLETION_WND_BACKGROUND)
|
||||
if (color != 0) {
|
||||
binding.root.backgroundTintList = ColorStateList.valueOf(color)
|
||||
binding.completionIconText.backgroundTintList = ColorStateList.valueOf(color)
|
||||
}
|
||||
|
||||
color = getThemeColor(COMPLETION_WND_TEXT_LABEL)
|
||||
setItemBackground(binding, isCurrent)
|
||||
var color = getThemeColor(COMPLETION_WND_TEXT_LABEL)
|
||||
if (color != 0) {
|
||||
binding.completionLabel.setTextColor(color)
|
||||
binding.completionIconText.setTextColor(color)
|
||||
@@ -141,6 +121,22 @@ class CompletionListAdapter : EditorCompletionAdapter() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun setItemBackground(binding: LayoutCompletionItemBinding, isCurrent: Boolean) {
|
||||
val color =
|
||||
if (isCurrent) getThemeColor(SchemeAndroidIDE.COMPLETION_WND_BG_CURRENT_ITEM)
|
||||
else 0
|
||||
|
||||
val cornerRadius = binding.root.context.resources
|
||||
.getDimensionPixelSize(R.dimen.completion_window_corner_radius).toFloat()
|
||||
|
||||
val gd = GradientDrawable().apply {
|
||||
setColor(color)
|
||||
setCornerRadius(cornerRadius)
|
||||
}
|
||||
|
||||
binding.root.background = gd
|
||||
}
|
||||
|
||||
private fun showApiInfoIfNeeded(item: LspCompletionItem, textView: TextView) {
|
||||
executeAsync({
|
||||
if (!isValidForApiVersion(item)) {
|
||||
@@ -212,15 +208,15 @@ class CompletionListAdapter : EditorCompletionAdapter() {
|
||||
val data = item.data
|
||||
return if ( // These represent a class type
|
||||
(type === CLASS ||
|
||||
type === INTERFACE ||
|
||||
type === ENUM ||
|
||||
type === INTERFACE ||
|
||||
type === ENUM ||
|
||||
|
||||
// These represent a method type
|
||||
type === METHOD ||
|
||||
type === CONSTRUCTOR ||
|
||||
// These represent a method type
|
||||
type === METHOD ||
|
||||
type === CONSTRUCTOR ||
|
||||
|
||||
// A field type
|
||||
type === FIELD) && data != null
|
||||
// A field type
|
||||
type === FIELD) && data != null
|
||||
) {
|
||||
val className =
|
||||
when (data) {
|
||||
|
||||
+4
@@ -72,6 +72,10 @@ class SchemeParser(private val resolveFileRef: (String) -> File) {
|
||||
"completion.window.text.type",
|
||||
SchemeAndroidIDE.COMPLETION_WND_TEXT_TYPE
|
||||
),
|
||||
COMPLETION_WND_BG_CURRENT_ITEM(
|
||||
"completion.window.item.current",
|
||||
SchemeAndroidIDE.COMPLETION_WND_BG_CURRENT_ITEM
|
||||
),
|
||||
NON_PRINTABLE_CHAR("non_printable_char", EditorColorScheme.NON_PRINTABLE_CHAR),
|
||||
HIGHLIGHTED_DELIMITERS_UNDERLINE(
|
||||
"highlighted.delimiters.underline",
|
||||
|
||||
@@ -19,7 +19,9 @@ package com.itsaky.androidide.editor.ui
|
||||
|
||||
import android.graphics.drawable.GradientDrawable
|
||||
import android.view.ViewGroup
|
||||
import com.blankj.utilcode.util.SizeUtils.dp2px
|
||||
import android.view.ViewGroup.MarginLayoutParams
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import com.itsaky.androidide.editor.R
|
||||
import io.github.rosemoe.sora.widget.component.DefaultCompletionLayout
|
||||
import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
|
||||
|
||||
@@ -32,14 +34,27 @@ import io.github.rosemoe.sora.widget.schemes.EditorColorScheme
|
||||
class EditorCompletionLayout : DefaultCompletionLayout() {
|
||||
|
||||
override fun onApplyColorScheme(colorScheme: EditorColorScheme) {
|
||||
super.onApplyColorScheme(colorScheme)
|
||||
|
||||
val gd =
|
||||
(completionList.parent as? ViewGroup?)?.background as? GradientDrawable?
|
||||
?: throw RuntimeException(
|
||||
"CompletionLayout implementation changed. Please report this issue."
|
||||
)
|
||||
val resources = completionList.context.resources
|
||||
val cornerRadius = resources.getDimensionPixelSize(R.dimen.completion_window_corner_radius)
|
||||
.toFloat()
|
||||
|
||||
gd.setStroke(dp2px(1f), colorScheme.getColor(EditorColorScheme.COMPLETION_WND_CORNER))
|
||||
val strokeWidth = resources
|
||||
.getDimensionPixelSize(R.dimen.completion_window_stroke_width)
|
||||
|
||||
(completionList.parent as? ViewGroup?)?.background = GradientDrawable().apply {
|
||||
setCornerRadius(cornerRadius)
|
||||
setStroke(strokeWidth, colorScheme.getColor(EditorColorScheme.COMPLETION_WND_CORNER))
|
||||
setColor(colorScheme.getColor(EditorColorScheme.COMPLETION_WND_BACKGROUND))
|
||||
}
|
||||
|
||||
if (completionList.layoutParams is MarginLayoutParams) {
|
||||
completionList.updateLayoutParams<MarginLayoutParams> {
|
||||
marginStart = strokeWidth
|
||||
topMargin = strokeWidth
|
||||
marginEnd = strokeWidth
|
||||
bottomMargin = strokeWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,7 @@ import io.github.rosemoe.sora.lang.completion.CompletionItem
|
||||
import io.github.rosemoe.sora.lang.completion.CompletionPublisher
|
||||
import io.github.rosemoe.sora.widget.component.CompletionLayout
|
||||
import io.github.rosemoe.sora.widget.component.EditorAutoCompletion
|
||||
import io.github.rosemoe.sora.widget.component.EditorCompletionAdapter
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
import java.lang.ref.WeakReference
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
@@ -37,24 +36,23 @@ import kotlin.math.min
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class EditorCompletionWindow(val editor: IDEEditor) : EditorAutoCompletion(editor) {
|
||||
private var mListView: ListView? = null
|
||||
private var mAdapter: EditorCompletionAdapter? = null
|
||||
private val mItems: MutableList<CompletionItem> = mutableListOf()
|
||||
|
||||
private var listView: ListView? = null
|
||||
private val items: MutableList<CompletionItem> = mutableListOf()
|
||||
private val log = ILogger.newInstance(javaClass.simpleName)
|
||||
|
||||
|
||||
init {
|
||||
mAdapter = super.adapter
|
||||
setLayout(EditorCompletionLayout())
|
||||
}
|
||||
|
||||
|
||||
override fun setLayout(layout: CompletionLayout) {
|
||||
super.setLayout(layout)
|
||||
(layout.completionList as? ListView)?.let {
|
||||
mListView = it
|
||||
it.adapter = mAdapter
|
||||
listView = it
|
||||
it.adapter = this.adapter
|
||||
it.setOnItemLongClickListener { _, view, position, _ ->
|
||||
val data =
|
||||
(mItems[position] as? com.itsaky.androidide.lsp.models.CompletionItem)?.data
|
||||
(items[position] as? com.itsaky.androidide.lsp.models.CompletionItem)?.data
|
||||
?: return@setOnItemLongClickListener false
|
||||
val url =
|
||||
DocumentationReferenceProvider.getUrl(data) ?: return@setOnItemLongClickListener false
|
||||
@@ -68,17 +66,9 @@ class EditorCompletionWindow(val editor: IDEEditor) : EditorAutoCompletion(edito
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun setAdapter(adapter: EditorCompletionAdapter?) {
|
||||
super.setAdapter(adapter)
|
||||
mAdapter = adapter
|
||||
mAdapter!!.attachValues(this, mItems)
|
||||
mAdapter!!.notifyDataSetInvalidated()
|
||||
mListView!!.adapter = adapter
|
||||
}
|
||||
|
||||
|
||||
override fun select(pos: Int): Boolean {
|
||||
if (pos > mAdapter!!.count) {
|
||||
if (pos > adapter!!.count) {
|
||||
return false
|
||||
}
|
||||
return try {
|
||||
@@ -88,7 +78,7 @@ class EditorCompletionWindow(val editor: IDEEditor) : EditorAutoCompletion(edito
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun select(): Boolean {
|
||||
return try {
|
||||
super.select()
|
||||
@@ -97,7 +87,7 @@ class EditorCompletionWindow(val editor: IDEEditor) : EditorAutoCompletion(edito
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun cancelCompletion() {
|
||||
if (completionThread != null) {
|
||||
ProgressManager.instance.cancel(completionThread)
|
||||
@@ -105,54 +95,71 @@ class EditorCompletionWindow(val editor: IDEEditor) : EditorAutoCompletion(edito
|
||||
super.cancelCompletion()
|
||||
popup.dismiss()
|
||||
}
|
||||
|
||||
|
||||
override fun requireCompletion() {
|
||||
if (cancelShowUp || !isEnabled) {
|
||||
return
|
||||
}
|
||||
|
||||
val text = editor.text
|
||||
if (text.cursor.isSelected) {
|
||||
if (text.cursor.isSelected || checkNoCompletion()) {
|
||||
hide()
|
||||
return
|
||||
}
|
||||
|
||||
if (System.nanoTime() - requestTime < editor.props.cancelCompletionNs) {
|
||||
hide()
|
||||
requestTime = System.nanoTime()
|
||||
return
|
||||
}
|
||||
|
||||
cancelCompletion()
|
||||
requestTime = System.nanoTime()
|
||||
super.currentSelection = -1
|
||||
val reference = AtomicReference<List<CompletionItem>>()
|
||||
val publisher =
|
||||
currentSelection = -1
|
||||
|
||||
publisher =
|
||||
CompletionPublisher(
|
||||
editor.handler,
|
||||
{
|
||||
val newItems = reference.get()
|
||||
mItems.clear()
|
||||
mItems.addAll(newItems)
|
||||
mAdapter!!.notifyDataSetChanged()
|
||||
val newHeight = (mAdapter!!.itemHeight * mAdapter!!.count).toFloat()
|
||||
val items = publisher.items
|
||||
this.items.apply {
|
||||
clear()
|
||||
addAll(items)
|
||||
}
|
||||
|
||||
if (lastAttachedItems == null || lastAttachedItems.get() != items) {
|
||||
adapter.attachValues(this, this.items)
|
||||
adapter.notifyDataSetInvalidated()
|
||||
lastAttachedItems = WeakReference(items)
|
||||
} else {
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
val newHeight = (adapter!!.itemHeight * adapter!!.count).toFloat()
|
||||
if (newHeight == 0F) {
|
||||
hide()
|
||||
}
|
||||
|
||||
setSize(width, min(newHeight, maxHeight.toFloat()).toInt())
|
||||
if (!popup.isShowing) {
|
||||
dismiss()
|
||||
show()
|
||||
}
|
||||
if (mAdapter!!.count >= 1) {
|
||||
super.currentSelection = 0
|
||||
|
||||
if (adapter!!.count >= 1) {
|
||||
currentSelection = 0
|
||||
}
|
||||
},
|
||||
editor.editorLanguage.interruptionLevel
|
||||
)
|
||||
|
||||
publisher.setUpdateThreshold(1)
|
||||
reference.set(publisher.items)
|
||||
|
||||
|
||||
completionThread = CompletionThread(requestTime, publisher)
|
||||
completionThread.name = "CompletionThread-$requestTime"
|
||||
|
||||
|
||||
setLoading(true)
|
||||
|
||||
|
||||
completionThread.start()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ This file is part of AndroidIDE.
|
||||
~
|
||||
~ AndroidIDE is free software: you can redistribute it and/or modify
|
||||
@@ -22,7 +21,6 @@
|
||||
android:id="@+id/relativeLayout2"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/colorPrimaryContainer"
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="40dp"
|
||||
tools:ignore="SmallSp">
|
||||
@@ -44,10 +42,11 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/completion_label"
|
||||
android:textStyle="bold"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
@@ -55,7 +54,6 @@
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
|
||||
android:textColor="?attr/colorOnPrimaryContainer"
|
||||
android:textSize="13sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toStartOf="@id/completion_type"
|
||||
app:layout_constraintStart_toEndOf="@id/completion_iconText"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
@@ -81,9 +79,9 @@
|
||||
android:id="@+id/completion_api_info"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:singleLine="true"
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ This file is part of AndroidIDE.
|
||||
~
|
||||
~ AndroidIDE is free software: you can redistribute it and/or modify
|
||||
~ it under the terms of the GNU General Public License as published by
|
||||
~ the Free Software Foundation, either version 3 of the License, or
|
||||
~ (at your option) any later version.
|
||||
~
|
||||
~ AndroidIDE is distributed in the hope that it will be useful,
|
||||
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
~ GNU General Public License for more details.
|
||||
~
|
||||
~ You should have received a copy of the GNU General Public License
|
||||
~ along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<dimen name="completion_window_corner_radius">8dp</dimen>
|
||||
<dimen name="completion_window_stroke_width">1dp</dimen>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user