mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 15:56:48 +08:00
fix: crash when undoing attribute addition
This commit is contained in:
@@ -30,6 +30,7 @@ import com.blankj.utilcode.util.FileUtils;
|
||||
import com.itsaky.androidide.activities.editor.EditorHandlerActivity;
|
||||
import com.itsaky.androidide.adapters.DiagnosticsAdapter;
|
||||
import com.itsaky.androidide.adapters.SearchListAdapter;
|
||||
import com.itsaky.androidide.editor.ui.IDEEditor;
|
||||
import com.itsaky.androidide.fragments.sheets.ProgressSheet;
|
||||
import com.itsaky.androidide.lsp.api.ILanguageClient;
|
||||
import com.itsaky.androidide.lsp.models.CodeActionItem;
|
||||
@@ -44,10 +45,9 @@ import com.itsaky.androidide.models.Location;
|
||||
import com.itsaky.androidide.models.Range;
|
||||
import com.itsaky.androidide.models.SearchResult;
|
||||
import com.itsaky.androidide.tasks.TaskExecutor;
|
||||
import com.itsaky.androidide.ui.editor.CodeEditorView;
|
||||
import com.itsaky.androidide.utils.ILogger;
|
||||
import com.itsaky.androidide.utils.LSPUtils;
|
||||
import com.itsaky.androidide.ui.editor.CodeEditorView;
|
||||
import com.itsaky.androidide.editor.ui.IDEEditor;
|
||||
import com.itsaky.toaster.ToastUtilsKt;
|
||||
import com.itsaky.toaster.Toaster;
|
||||
|
||||
@@ -89,7 +89,7 @@ public class IDELanguageClientImpl implements ILanguageClient {
|
||||
if (mInstance != null) {
|
||||
throw new IllegalStateException("Client is already initialized");
|
||||
}
|
||||
|
||||
|
||||
mInstance = new IDELanguageClientImpl(provider);
|
||||
|
||||
return getInstance();
|
||||
@@ -110,7 +110,7 @@ public class IDELanguageClientImpl implements ILanguageClient {
|
||||
public static boolean isInitialized() {
|
||||
return mInstance != null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void publishDiagnostics(DiagnosticResult result) {
|
||||
if (result == DiagnosticResult.NO_UPDATE) {
|
||||
@@ -269,8 +269,7 @@ public class IDELanguageClientImpl implements ILanguageClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ShowDocumentResult showDocument(
|
||||
ShowDocumentParams params) {
|
||||
public ShowDocumentResult showDocument(ShowDocumentParams params) {
|
||||
boolean success = false;
|
||||
final var result = new ShowDocumentResult(false);
|
||||
if (activity() == null) {
|
||||
@@ -441,7 +440,7 @@ public class IDELanguageClientImpl implements ILanguageClient {
|
||||
private CodeEditorView findEditorByFile(File file) {
|
||||
return activity().getEditorForFile(file);
|
||||
}
|
||||
|
||||
|
||||
private Unit noOp(final Object obj) {
|
||||
return Unit.INSTANCE;
|
||||
}
|
||||
|
||||
@@ -251,7 +251,7 @@ public class IDEEditor extends CodeEditor implements com.itsaky.androidide.edito
|
||||
*/
|
||||
@Override
|
||||
public void setSelection(@NonNull Range range) {
|
||||
if (isValidRange(range, true)) {
|
||||
if (isValidPosition(range.getStart(), true) && isValidPosition(range.getEnd(), true)) {
|
||||
setSelectionRegion(
|
||||
range.getStart().getLine(),
|
||||
range.getStart().getColumn(),
|
||||
@@ -290,7 +290,6 @@ public class IDEEditor extends CodeEditor implements com.itsaky.androidide.edito
|
||||
* Validates the range if it is invalid and returns a valid range.
|
||||
*
|
||||
* @param range Th range to validate.
|
||||
* @return A new, validated range.
|
||||
*/
|
||||
@Override
|
||||
public void validateRange(@NonNull final Range range) {
|
||||
|
||||
Binary file not shown.
+3
-3
@@ -33,6 +33,7 @@ import com.itsaky.androidide.uidesigner.adapters.AddAttrListAdapter
|
||||
import com.itsaky.androidide.uidesigner.adapters.ViewAttrListAdapter
|
||||
import com.itsaky.androidide.uidesigner.databinding.LayoutAddAttrBinding
|
||||
import com.itsaky.androidide.uidesigner.databinding.LayoutViewInfoHeaderBinding
|
||||
import com.itsaky.androidide.uidesigner.models.UiAttribute
|
||||
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel
|
||||
|
||||
/**
|
||||
@@ -88,10 +89,9 @@ class AddAttrFragment : Fragment() {
|
||||
val attributes =
|
||||
adapter.supportedAttributes.filterNot { view.hasAttribute(it.namespace.uri, it.name) }
|
||||
binding.attrList.adapter = AddAttrListAdapter(attributes) {
|
||||
val attribute = newAttribute(view = viewModel.view, namespace = it.namespace, name = it.name, value = it.value)
|
||||
viewModel.selectedAttr = attribute
|
||||
val attribute = newAttribute(view = viewModel.view, namespace = it.namespace, name = it.name, value = "")
|
||||
viewModel.selectedAttr = attribute as UiAttribute
|
||||
viewModel.addAttrMode = true
|
||||
view.addAttribute(attribute)
|
||||
findNavController().navigate(R.id.attrValueEditorFragment)
|
||||
}
|
||||
}
|
||||
|
||||
+7
-11
@@ -26,10 +26,11 @@ import android.view.ViewGroup
|
||||
import android.widget.ArrayAdapter
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
import com.itsaky.androidide.inflater.internal.ViewImpl
|
||||
import com.itsaky.androidide.inflater.utils.newAttribute
|
||||
import com.itsaky.androidide.uidesigner.databinding.LayoutAttrValueEditorBinding
|
||||
import com.itsaky.androidide.uidesigner.databinding.LayoutViewInfoHeaderBinding
|
||||
import com.itsaky.androidide.uidesigner.models.UiAttribute
|
||||
import com.itsaky.androidide.uidesigner.utils.ValueCompletionProvider
|
||||
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel
|
||||
|
||||
@@ -56,11 +57,6 @@ class AttrValueEditorFragment : Fragment() {
|
||||
|
||||
private var textWatcher: TextWatcher? = null
|
||||
|
||||
companion object {
|
||||
const val KEY_EDIT_RESULT = "ide.uidesigner.viewinfo.attreditor.result"
|
||||
const val KEY_EDIT_RESULT_VALUE = "ide.uidesigner.viewinfo.attreditor.result.value"
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
@@ -80,6 +76,7 @@ class AttrValueEditorFragment : Fragment() {
|
||||
private fun showAttrInfo() {
|
||||
val binding = this.binding ?: return
|
||||
val header = this.header ?: return
|
||||
val view = this.viewModel.view ?: return
|
||||
val attr = this.viewModel.selectedAttr ?: return
|
||||
|
||||
header.name.text = "${attr.namespace.prefix}:${attr.name}"
|
||||
@@ -94,11 +91,10 @@ class AttrValueEditorFragment : Fragment() {
|
||||
)
|
||||
textView.dropDownVerticalOffset = -binding.root.height
|
||||
textView.showDropDown()
|
||||
|
||||
parentFragmentManager.setFragmentResult(
|
||||
KEY_EDIT_RESULT,
|
||||
Bundle().apply { putString(KEY_EDIT_RESULT_VALUE, binding.attrValue.text.toString()) }
|
||||
)
|
||||
|
||||
val value = binding.attrValue.text.toString()
|
||||
attr.value = value
|
||||
view.applyAttribute(attr.copyAttr(value = value))
|
||||
}
|
||||
|
||||
textView.setText(attr.value)
|
||||
|
||||
+15
-4
@@ -32,12 +32,15 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||
import com.itsaky.androidide.uidesigner.R
|
||||
import com.itsaky.androidide.uidesigner.databinding.LayoutViewInfoSheetBinding
|
||||
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel
|
||||
import com.itsaky.androidide.utils.ILogger
|
||||
|
||||
/** @author Akash Yadav */
|
||||
class ViewInfoSheet : BottomSheetDialogFragment() {
|
||||
private var binding: LayoutViewInfoSheetBinding? = null
|
||||
private val viewModel by viewModels<WorkspaceViewModel>(ownerProducer = { requireActivity() })
|
||||
|
||||
private val log = ILogger.newInstance("ViewInfoSheet")
|
||||
|
||||
companion object {
|
||||
const val TAG = "ide.uidesigner.viewinfo"
|
||||
}
|
||||
@@ -70,16 +73,24 @@ class ViewInfoSheet : BottomSheetDialogFragment() {
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
findNavControllerFromFragment()?.addOnDestinationChangedListener { _, destination, _ ->
|
||||
findNavControllerFromFragment().addOnDestinationChangedListener { _, destination, _ ->
|
||||
viewInfoBackPressedCallback.isEnabled = destination.id != R.id.viewInfoFragment
|
||||
|
||||
if (destination.id != R.id.attrValueEditorFragment) {
|
||||
// not disabling the undo manager when going into 'edit mode' will result in a lot
|
||||
// AttrUpdatedAction being pushed to UndoManager's undo stack.
|
||||
viewModel.undoManager.enabled = destination.id != R.id.attrValueEditorFragment
|
||||
|
||||
if (viewModel.currentDestination == R.id.attrValueEditorFragment) {
|
||||
// if we are returning from value editor, then
|
||||
// 1 - if we were updating the value of an existing attribute, then the updated value must
|
||||
// be updated in the view
|
||||
// 2 - if we were adding a new attribute, then that attribute should be added to the view.
|
||||
viewModel.notifyAttrUpdated()
|
||||
viewModel.selectedAttr = null
|
||||
viewModel.addAttrMode = false
|
||||
} else {
|
||||
viewModel.undoManager.disable()
|
||||
}
|
||||
|
||||
viewModel.currentDestination = destination.id
|
||||
}
|
||||
|
||||
(requireDialog() as ComponentDialog)
|
||||
|
||||
+1
-1
@@ -56,7 +56,7 @@ internal class WorkspaceViewAttrHandler : IView.AttributeChangeListener {
|
||||
frag.undoManager.push(
|
||||
AttrUpdatedAction(
|
||||
view = view,
|
||||
attr = (attribute as UiAttribute).copyAttr(view = view) as UiAttribute,
|
||||
attr = attribute as UiAttribute,
|
||||
oldValue = oldValue
|
||||
)
|
||||
)
|
||||
|
||||
@@ -17,13 +17,19 @@
|
||||
|
||||
package com.itsaky.androidide.uidesigner.undo
|
||||
|
||||
import com.itsaky.androidide.inflater.IAttribute
|
||||
import com.itsaky.androidide.inflater.IView
|
||||
import com.itsaky.androidide.uidesigner.models.UiAttribute
|
||||
import com.itsaky.androidide.utils.ILogger
|
||||
|
||||
/**
|
||||
* [UndoManager] action related to view attributes.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
internal abstract class AttrAction(protected val view: IView, protected val attr: UiAttribute) : IUiAction
|
||||
internal abstract class AttrAction(protected val view: IView, protected val attr: UiAttribute) :
|
||||
IUiAction {
|
||||
|
||||
override fun toString(): String {
|
||||
return "${javaClass.simpleName}(view=$view, attr=$attr)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@ import com.itsaky.androidide.uidesigner.models.UiAttribute
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
internal class AttrAddedAction(view: IView, attr: UiAttribute) : AttrAction(view, attr) {
|
||||
internal class AttrAddedAction(view: IView, attr: UiAttribute) :
|
||||
AttrAction(view, attr.copyAttr(view = view) as UiAttribute) {
|
||||
|
||||
override fun undo() {
|
||||
view.removeAttribute(attr)
|
||||
|
||||
@@ -25,7 +25,8 @@ import com.itsaky.androidide.uidesigner.models.UiAttribute
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
internal class AttrRemovedAction(view: IView, attr: UiAttribute) : AttrAction(view, attr) {
|
||||
internal class AttrRemovedAction(view: IView, attr: UiAttribute) :
|
||||
AttrAction(view, attr.copyAttr(view = view) as UiAttribute) {
|
||||
|
||||
override fun undo() {
|
||||
view.addAttribute(attr)
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
package com.itsaky.androidide.uidesigner.undo
|
||||
|
||||
import com.itsaky.androidide.utils.ILogger
|
||||
|
||||
/**
|
||||
* Handles undo and redo actions in the UI designer.
|
||||
*
|
||||
@@ -32,11 +34,11 @@ class UndoManager @JvmOverloads constructor(private var maxStackSize: Int = DEFA
|
||||
companion object {
|
||||
const val DEFAULT_STACK_SIZE = 30
|
||||
}
|
||||
|
||||
|
||||
fun enable() {
|
||||
this.enabled = true
|
||||
}
|
||||
|
||||
|
||||
fun disable() {
|
||||
this.enabled = false
|
||||
}
|
||||
@@ -86,7 +88,7 @@ class UndoManager @JvmOverloads constructor(private var maxStackSize: Int = DEFA
|
||||
if (!enabled) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
redoStack.clear()
|
||||
undoStack.addLast(action)
|
||||
trimStacks()
|
||||
|
||||
-5
@@ -20,7 +20,6 @@ package com.itsaky.androidide.uidesigner.utils
|
||||
import android.text.Editable
|
||||
import com.blankj.utilcode.util.ThreadUtils
|
||||
import com.itsaky.androidide.inflater.IAttribute
|
||||
import com.itsaky.androidide.inflater.internal.AttributeImpl
|
||||
import com.itsaky.androidide.inflater.internal.ViewImpl
|
||||
import com.itsaky.androidide.lsp.util.setupLookupForCompletion
|
||||
import com.itsaky.androidide.lsp.xml.models.XMLServerSettings
|
||||
@@ -64,10 +63,6 @@ internal class ValueCompletionProvider(
|
||||
this.prefix = value
|
||||
this.start()
|
||||
}
|
||||
|
||||
val copy = (attribute as AttributeImpl).copyAttr(view = view)
|
||||
copy.value = value
|
||||
view.updateAttribute(copy)
|
||||
}
|
||||
|
||||
class CompletionThread(
|
||||
|
||||
+30
-19
@@ -19,11 +19,8 @@ package com.itsaky.androidide.uidesigner.viewmodel
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.itsaky.androidide.inflater.IAttribute
|
||||
import com.itsaky.androidide.inflater.IView
|
||||
import com.itsaky.androidide.uidesigner.models.UiAttribute
|
||||
import com.itsaky.androidide.uidesigner.undo.AttrAddedAction
|
||||
import com.itsaky.androidide.uidesigner.undo.AttrUpdatedAction
|
||||
import com.itsaky.androidide.uidesigner.undo.UndoManager
|
||||
import java.io.File
|
||||
|
||||
@@ -32,9 +29,10 @@ internal class WorkspaceViewModel : ViewModel() {
|
||||
internal val _errText = MutableLiveData("")
|
||||
internal val _workspaceScreen = MutableLiveData(SCREEN_WORKSPACE)
|
||||
internal val _view = MutableLiveData<IView>(null)
|
||||
internal val _selectedAttr = MutableLiveData<IAttribute>(null)
|
||||
internal val _selectedAttr = MutableLiveData<UiAttribute>(null)
|
||||
internal val _addAttrMode = MutableLiveData(false)
|
||||
internal val _undoManager = MutableLiveData(UndoManager())
|
||||
internal val _currentDestination = MutableLiveData(0)
|
||||
private val _file = MutableLiveData<File>()
|
||||
|
||||
companion object {
|
||||
@@ -76,7 +74,7 @@ internal class WorkspaceViewModel : ViewModel() {
|
||||
this._view.value = value
|
||||
}
|
||||
|
||||
var selectedAttr: IAttribute?
|
||||
var selectedAttr: UiAttribute?
|
||||
get() = this._selectedAttr.value
|
||||
set(value) {
|
||||
this._selectedAttr.value = value
|
||||
@@ -88,31 +86,44 @@ internal class WorkspaceViewModel : ViewModel() {
|
||||
this._addAttrMode.value = value
|
||||
}
|
||||
|
||||
var currentDestination: Int
|
||||
get() = this._currentDestination.value ?: 0
|
||||
set(value) {
|
||||
this._currentDestination.value = value
|
||||
}
|
||||
|
||||
fun notifyAttrUpdated() {
|
||||
val attr = this.selectedAttr ?: return
|
||||
val view = this.view ?: return
|
||||
val undoManager = this.undoManager
|
||||
|
||||
if (addAttrMode) {
|
||||
if (attr.value.isBlank()) {
|
||||
view.removeAttribute(attr)
|
||||
return
|
||||
}
|
||||
|
||||
undoManager.push(AttrAddedAction(view, attr as UiAttribute))
|
||||
if (addAttrMode && attr.value.isNotBlank()) {
|
||||
// if we were adding a new attribute, then add the attribute to the view.
|
||||
view.addAttribute(attr)
|
||||
addAttrMode = false
|
||||
selectedAttr = null
|
||||
return
|
||||
}
|
||||
|
||||
val existing = view.findAttribute(attr.namespace.uri, attr.name)
|
||||
|
||||
if (existing !is UiAttribute || existing.value == attr.value) {
|
||||
// value of the attribute is same as before
|
||||
if (existing !is UiAttribute) {
|
||||
return
|
||||
}
|
||||
|
||||
undoManager.push(
|
||||
AttrUpdatedAction(view, existing.copyAttr(view = view) as UiAttribute, attr.value)
|
||||
)
|
||||
if (existing.value.isBlank()) {
|
||||
// the user left the value field blank, remove the attribute
|
||||
view.removeAttribute(existing)
|
||||
selectedAttr = null
|
||||
return
|
||||
}
|
||||
|
||||
if (existing.value == attr.value) {
|
||||
// value of the attribute is same as before
|
||||
selectedAttr = null
|
||||
return
|
||||
}
|
||||
|
||||
// the user was updating the value af the attribute, so update it in the view
|
||||
view.updateAttribute(existing.copyAttr(view = view, value = attr.value))
|
||||
this.selectedAttr = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,14 @@ interface IView {
|
||||
*/
|
||||
fun updateAttribute(attribute: IAttribute)
|
||||
|
||||
/**
|
||||
* Applies the given attribute without adding it to the attributes list or notifying the attribute
|
||||
* change listeners. Not resetting the attribute to its original value may have unexpected result.
|
||||
*
|
||||
* @param attribute The attribute to apply.
|
||||
*/
|
||||
fun applyAttribute(attribute: IAttribute)
|
||||
|
||||
/**
|
||||
* Checks whether this view has an attribute entry with the given [namespaceUri] and [name].
|
||||
*
|
||||
|
||||
@@ -28,6 +28,7 @@ import com.itsaky.androidide.inflater.IViewGroup
|
||||
import com.itsaky.androidide.inflater.R.drawable
|
||||
import com.itsaky.androidide.inflater.internal.utils.simpleName
|
||||
import com.itsaky.androidide.inflater.internal.utils.tagName
|
||||
import com.itsaky.androidide.inflater.utils.newAttribute
|
||||
import com.itsaky.androidide.utils.ILogger
|
||||
|
||||
open class ViewImpl
|
||||
@@ -68,19 +69,22 @@ constructor(
|
||||
}
|
||||
|
||||
override fun removeAttribute(attribute: IAttribute) {
|
||||
|
||||
|
||||
val exising = findAttribute(attribute) ?: return
|
||||
val value = exising.value
|
||||
|
||||
// reset the value of the attribute to its default value
|
||||
attribute.value = ""
|
||||
updateAttributeInternal(attribute = attribute, notify = false)
|
||||
|
||||
this._attributes.remove(attribute)
|
||||
notifyAttrRemoved(attribute)
|
||||
applyAttribute(attribute = newAttribute(view = this, attribute = exising, value = ""))
|
||||
|
||||
if (this._attributes.remove(exising)) {
|
||||
notifyAttrRemoved(newAttribute(view = this, attribute = exising, value = value))
|
||||
}
|
||||
}
|
||||
|
||||
override fun updateAttribute(attribute: IAttribute) {
|
||||
updateAttributeInternal(attribute)
|
||||
}
|
||||
|
||||
|
||||
override fun findAttribute(namespaceUri: String, name: String): IAttribute? {
|
||||
return this.attributes.find { it.namespace.uri == namespaceUri && it.name == name }
|
||||
}
|
||||
@@ -94,7 +98,7 @@ constructor(
|
||||
view.foreground = this.fg
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun registerAttributeChangeListener(listener: AttributeChangeListener) {
|
||||
if (this.attrChangeListeners.contains(listener)) {
|
||||
log.warn("Attempt to register an already-registered AttributeChangeListener")
|
||||
@@ -102,12 +106,12 @@ constructor(
|
||||
}
|
||||
this.attrChangeListeners.add(listener)
|
||||
}
|
||||
|
||||
|
||||
override fun unregisterAttributeChangeListener(listener: AttributeChangeListener) {
|
||||
this.attrChangeListeners.remove(listener)
|
||||
}
|
||||
|
||||
protected open fun applyAttribute(attribute: IAttribute) {
|
||||
override fun applyAttribute(attribute: IAttribute) {
|
||||
val adapter = ViewAdapterIndex.getAdapter(name)
|
||||
if (adapter == null) {
|
||||
log.warn("No attribute adapter found for view $name")
|
||||
@@ -115,7 +119,7 @@ constructor(
|
||||
}
|
||||
adapter.apply(this, attribute)
|
||||
}
|
||||
|
||||
|
||||
fun findNamespaces(): Set<INamespace> {
|
||||
return hashSetOf<INamespace>().apply {
|
||||
addAll(namespaces.values)
|
||||
@@ -124,12 +128,12 @@ constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun findNamespaceByUri(uri: String): INamespace? {
|
||||
return this.namespaces[uri] ?: (parent as? ViewImpl)?.findNamespaceByUri(uri)
|
||||
}
|
||||
|
||||
open fun immutable() : IView {
|
||||
|
||||
open fun immutable(): IView {
|
||||
return ImmutableViewImpl(this)
|
||||
}
|
||||
|
||||
@@ -150,33 +154,33 @@ constructor(
|
||||
builder.append(name)
|
||||
builder.append("\n")
|
||||
}
|
||||
|
||||
|
||||
private fun updateAttributeInternal(attribute: IAttribute, notify: Boolean = true) {
|
||||
val existing =
|
||||
findAttribute(attribute)
|
||||
?: throw IllegalArgumentException("Attribute '${attribute.name}' not found")
|
||||
|
||||
|
||||
val oldVal = existing.value
|
||||
existing.value = attribute.value
|
||||
applyAttribute(existing)
|
||||
|
||||
|
||||
if (notify) {
|
||||
notifyAttrUpdated(attribute, oldVal)
|
||||
notifyAttrUpdated(newAttribute(view = this, attribute = attribute), oldVal)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun notifyAttrAdded(attribute: IAttribute) {
|
||||
for (listener in this.attrChangeListeners) {
|
||||
listener.onAttributeAdded(this, attribute)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun notifyAttrRemoved(attribute: IAttribute) {
|
||||
for (listener in this.attrChangeListeners) {
|
||||
listener.onAttributeRemoved(this, attribute)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun notifyAttrUpdated(attribute: IAttribute, oldValue: String) {
|
||||
for (listener in this.attrChangeListeners) {
|
||||
listener.onAttributeUpdated(this, attribute, oldValue)
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ import com.itsaky.androidide.inflater.utils.newAttribute
|
||||
open class ViewAdapter<T : View> : IViewAdapter<T>() {
|
||||
|
||||
override fun createAttrHandlers(create: (String, AttributeHandlerScope<T>.() -> Unit) -> Unit) {
|
||||
create("alpha") { view.alpha = parseFloat(value) }
|
||||
create("alpha") { view.alpha = parseFloat(value, def = 1f) }
|
||||
create("background") { view.background = parseDrawable(context, value) }
|
||||
create("backgroundTint") { view.backgroundTintList = parseColorStateList(context, value) }
|
||||
create("backgroundTintMode") { view.backgroundTintMode = parsePorterDuffMode(value) }
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.inflater.internal.adapters.appcompat
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class AppCompatTextView {
|
||||
}
|
||||
@@ -36,6 +36,22 @@ fun lookupComponentFactory(): IComponentFactory? {
|
||||
return Lookup.DEFAULT.lookup(IComponentFactory.LAYOUT_INFLATER_COMPONENT_FACTORY_KEY)
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun newAttribute(
|
||||
view: IView? = null,
|
||||
attribute: IAttribute,
|
||||
namespace: INamespace? = null,
|
||||
name: String? = null,
|
||||
value: String? = null
|
||||
): IAttribute {
|
||||
return newAttribute(
|
||||
view = view,
|
||||
namespace = namespace ?: attribute.namespace,
|
||||
name = name ?: attribute.name,
|
||||
value = value ?: attribute.value
|
||||
)
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun newAttribute(
|
||||
view: IView? = null,
|
||||
|
||||
Reference in New Issue
Block a user