feat: add basic layout for attribute value editor

This commit is contained in:
Akash Yadav
2022-12-01 10:57:42 +05:30
parent 5a461042f6
commit f04e2b44e8
15 changed files with 497 additions and 70 deletions
+1 -1
View File
@@ -289,7 +289,7 @@
<string name="msg_file_tree">File tree</string>
<string name="hint_color_resource">Color resource</string>
<string name="title_color_picker">Color picker</string>
<string name="hint_string_value">String value</string>
<string name="hint_attr_value">Attribute value</string>
<string name="hint_string_resource">String resource</string>
<string name="hint_resource_reference">Any resource reference</string>
<string name="msg_code_actions">Actions</string>
Binary file not shown.
@@ -19,6 +19,7 @@ package com.itsaky.androidide.uidesigner
import android.os.Bundle
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.core.view.GravityCompat
@@ -26,6 +27,9 @@ import com.itsaky.androidide.app.BaseIDEActivity
import com.itsaky.androidide.uidesigner.databinding.ActivityUiDesignerBinding
import com.itsaky.androidide.uidesigner.fragments.DesignerWorkspaceFragment
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel.Companion.SCREEN_VALUE_EDITOR
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel.Companion.SCREEN_VIEW_INFO
import com.itsaky.androidide.utils.ILogger
/**
* The UI Designer activity allows the user to design XML layouts with a drag-n-drop interface.
@@ -34,6 +38,7 @@ import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel
*/
class UIDesignerActivity : BaseIDEActivity() {
private val log = ILogger.newInstance("UIDesignerActivity")
private var binding: ActivityUiDesignerBinding? = null
private val workspace: DesignerWorkspaceFragment?
get() = this.binding?.workspace?.getFragment()
@@ -31,7 +31,7 @@ import com.itsaky.androidide.uidesigner.databinding.LayoutViewattrItemBinding
*
* @author Akash Yadav
*/
class ViewAttrListAdapter(attributes: List<IAttribute>) : RecyclerView.Adapter<VH>() {
class ViewAttrListAdapter(attributes: List<IAttribute>, private val onClick: (IAttribute) -> Unit) : RecyclerView.Adapter<VH>() {
private val attributes = attributes.sortedBy { it.name }
@@ -52,5 +52,9 @@ class ViewAttrListAdapter(attributes: List<IAttribute>) : RecyclerView.Adapter<V
binding.attrName.text = "${attr.namespace.prefix}:${attr.name}"
binding.attrValue.text = attr.value
binding.root.setOnClickListener {
onClick(attr)
}
}
}
@@ -0,0 +1,82 @@
/*
* 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.uidesigner.fragments
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.google.android.material.transition.MaterialSharedAxis
import com.itsaky.androidide.uidesigner.databinding.LayoutAttrValueEditorBinding
import com.itsaky.androidide.uidesigner.databinding.LayoutViewInfoHeaderBinding
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel
/**
* Fragment to allow the user to edit the value of the selected fragment.
*
* @author Akash Yadav
*/
class AttrValueEditorFragment : Fragment() {
private var header: LayoutViewInfoHeaderBinding? = null
private val viewModel by viewModels<WorkspaceViewModel>(ownerProducer = { requireActivity() })
private var binding: LayoutAttrValueEditorBinding? = null
set(value) {
if (value == null) {
field = null
header = null
return
}
field = value
header = LayoutViewInfoHeaderBinding.bind(value.root)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
this.binding = LayoutAttrValueEditorBinding.inflate(inflater, container, false)
return this.binding!!.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel._selectedAttr.observe(viewLifecycleOwner) { showAttrInfo() }
}
@SuppressLint("SetTextI18n")
private fun showAttrInfo() {
val binding = this.binding ?: return
val header = this.header ?: return
val attr = this.viewModel.selectedAttr ?: return
header.name.text = "${attr.namespace.prefix}:${attr.name}"
header.desc.text = attr.namespace.uri
binding.attrValue.editText?.setText(attr.value)
}
override fun onDestroyView() {
super.onDestroyView()
this.binding = null
}
}
@@ -42,14 +42,14 @@ import com.itsaky.androidide.uidesigner.UIDesignerActivity
import com.itsaky.androidide.uidesigner.databinding.FragmentDesignerWorkspaceBinding
import com.itsaky.androidide.uidesigner.drag.WidgetDragListener
import com.itsaky.androidide.uidesigner.drag.WidgetTouchListener
import com.itsaky.androidide.uidesigner.fragments.ViewInfoDialogFragment.Companion.TAG
import com.itsaky.androidide.uidesigner.fragments.ViewInfoFragment.Companion.TAG
import com.itsaky.androidide.uidesigner.models.PlaceholderView
import com.itsaky.androidide.uidesigner.models.UiView
import com.itsaky.androidide.uidesigner.models.UiViewGroup
import com.itsaky.androidide.uidesigner.utils.bgDesignerView
import com.itsaky.androidide.uidesigner.utils.layeredForeground
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel.Companion.FLIPPER_SCREEN_WORKSPACE
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel.Companion.SCREEN_WORKSPACE
import com.itsaky.androidide.utils.ILogger
import java.io.File
@@ -68,7 +68,7 @@ class DesignerWorkspaceFragment : BaseFragment() {
UiViewGroup(LayoutFile(File(""), ""), LinearLayout::class.qualifiedName!!, binding!!.workspace)
}
private val viewInfo by lazy { ViewInfoDialogFragment() }
private val viewInfo by lazy { ViewInfoSheet() }
private val placeholder by lazy {
val view =
@@ -89,7 +89,7 @@ class DesignerWorkspaceFragment : BaseFragment() {
setupView(view as UiView)
if (workspaceView.childCount == 0) {
viewModel.flipperScreen = FLIPPER_SCREEN_WORKSPACE
viewModel.workspaceFlipperScreen = SCREEN_WORKSPACE
}
}
@@ -142,7 +142,7 @@ class DesignerWorkspaceFragment : BaseFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel._flipperScreen.observe(viewLifecycleOwner) { binding?.flipper?.displayedChild = it }
viewModel._workspaceScreen.observe(viewLifecycleOwner) { binding?.flipper?.displayedChild = it }
viewModel._errText.observe(viewLifecycleOwner) { binding?.errText?.text = it }
@@ -172,7 +172,7 @@ class DesignerWorkspaceFragment : BaseFragment() {
private fun setupView(view: IView) {
view.view.setOnTouchListener(
WidgetTouchListener(view, requireContext()) {
viewInfo.view = it
viewModel.view = it
viewInfo.show(childFragmentManager, TAG)
true
}
@@ -21,31 +21,38 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.itsaky.androidide.inflater.IView
import com.google.android.material.transition.MaterialSharedAxis
import com.itsaky.androidide.uidesigner.adapters.ViewAttrListAdapter
import com.itsaky.androidide.uidesigner.databinding.LayoutViewInfoBinding
import com.itsaky.androidide.uidesigner.databinding.LayoutViewInfoHeaderBinding
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel.Companion.SCREEN_VALUE_EDITOR
/**
* A [BottomSheetDialogFragment] which shows information about a clicked view.
*
* @author Akash Yadav
*/
class ViewInfoDialogFragment : BottomSheetDialogFragment() {
class ViewInfoFragment : Fragment() {
private val viewModel by viewModels<WorkspaceViewModel>(ownerProducer = { requireActivity() })
private var binding: LayoutViewInfoBinding? = null
var view: IView? = null
set(value) {
field = value
if (isShowing) {
showViewInfo()
if (value == null) {
field = null
header = null
return
}
field = value
header = LayoutViewInfoHeaderBinding.bind(value.root)
}
val isShowing: Boolean
get() = dialog?.isShowing ?: false
private var header: LayoutViewInfoHeaderBinding? = null
companion object {
const val TAG = "ide.uidesigner.viewinfo"
}
@@ -61,7 +68,7 @@ class ViewInfoDialogFragment : BottomSheetDialogFragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (this.view != null) {
viewModel._view.observe(viewLifecycleOwner) {
showViewInfo()
}
}
@@ -73,15 +80,18 @@ class ViewInfoDialogFragment : BottomSheetDialogFragment() {
private fun showViewInfo() {
val binding = this.binding ?: return
val view = this.view ?: return
val header = this.header ?: return
val view = this.viewModel.view ?: return
header.name.text = view.simpleName
header.desc.text = view.name
binding.attrList.adapter = ViewAttrListAdapter(view.attributes) {
viewModel.selectedAttr = it
viewModel.viewInfoScreen = SCREEN_VALUE_EDITOR
}
binding.viewName.text = view.simpleName
binding.viewInfo.text = view.name
binding.attrList.adapter = ViewAttrListAdapter(view.attributes)
binding.btnDelete.setOnClickListener {
view.removeFromParent()
dismiss()
}
}
}
@@ -0,0 +1,85 @@
/*
* 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.uidesigner.fragments
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.ComponentDialog
import androidx.activity.OnBackPressedCallback
import androidx.fragment.app.viewModels
import androidx.transition.TransitionManager.beginDelayedTransition
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.google.android.material.transition.MaterialSharedAxis
import com.itsaky.androidide.uidesigner.databinding.LayoutViewInfoSheetBinding
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel.Companion.SCREEN_VALUE_EDITOR
import com.itsaky.androidide.uidesigner.viewmodel.WorkspaceViewModel.Companion.SCREEN_VIEW_INFO
/** @author Akash Yadav */
class ViewInfoSheet : BottomSheetDialogFragment() {
private var binding: LayoutViewInfoSheetBinding? = null
private val viewModel by viewModels<WorkspaceViewModel>(ownerProducer = { requireActivity() })
val isShowing: Boolean
get() = dialog?.isShowing ?: false
private val viewInfoBackPressedCallback =
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if (viewModel.viewInfoScreen == SCREEN_VALUE_EDITOR) {
viewModel.viewInfoScreen = SCREEN_VIEW_INFO
isEnabled = false
}
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
this.binding = LayoutViewInfoSheetBinding.inflate(inflater, container, false)
return this.binding!!.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel._viewInfoScreen.observe(viewLifecycleOwner) {
binding?.apply {
val prev = flipper.displayedChild
beginDelayedTransition(root, MaterialSharedAxis(MaterialSharedAxis.X, prev < it))
flipper.displayedChild = it
}
this.viewInfoBackPressedCallback.isEnabled = it == SCREEN_VALUE_EDITOR
}
viewModel._view.observe(viewLifecycleOwner) { viewModel.viewInfoScreen = SCREEN_VIEW_INFO }
(requireDialog() as ComponentDialog)
.onBackPressedDispatcher
.addCallback(viewLifecycleOwner, viewInfoBackPressedCallback)
}
override fun onDestroyView() {
super.onDestroyView()
this.binding = null
}
}
@@ -17,45 +17,68 @@
package com.itsaky.androidide.uidesigner.viewmodel
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModel
import com.itsaky.androidide.inflater.IAttribute
import com.itsaky.androidide.inflater.IView
import java.io.File
class WorkspaceViewModel : ViewModel() {
internal val _drawerOpened = MutableLiveData(false)
internal val _errText = MutableLiveData("")
internal val _flipperScreen = MutableLiveData(0)
internal val _workspaceScreen = MutableLiveData(SCREEN_WORKSPACE)
internal val _viewInfoScreen = MutableLiveData(SCREEN_VIEW_INFO)
internal val _view = MutableLiveData<IView>(null)
internal val _selectedAttr = MutableLiveData<IAttribute>(null)
private val _file = MutableLiveData<File>()
companion object {
const val FLIPPER_SCREEN_WORKSPACE = 0
const val FLIPPER_SCREEN_ERROR = 1
const val SCREEN_WORKSPACE = 0
const val SCREEN_ERROR = 1
const val SCREEN_VIEW_INFO = 0
const val SCREEN_VALUE_EDITOR = 1
}
var file: File
get() = _file.value!!
set(value) {
_file.value = value
}
var drawerOpened : Boolean
var drawerOpened: Boolean
get() = this._drawerOpened.value!!
set(value) {
this._drawerOpened.value = value
}
var errText: String
get() = _errText.value ?: ""
set(value) {
_errText.value = value
flipperScreen = FLIPPER_SCREEN_ERROR
workspaceFlipperScreen = SCREEN_ERROR
}
var workspaceFlipperScreen: Int
get() = _workspaceScreen.value ?: SCREEN_WORKSPACE
set(value) {
_workspaceScreen.value = value
}
var view: IView?
get() = this._view.value
set(value) {
this._view.value = value
}
var viewInfoScreen: Int
get() = _viewInfoScreen.value ?: SCREEN_VIEW_INFO
set(value) {
_viewInfoScreen.value = value
}
var flipperScreen: Int
get() = _flipperScreen.value ?: FLIPPER_SCREEN_WORKSPACE
var selectedAttr: IAttribute?
get() = this._selectedAttr.value
set(value) {
_flipperScreen.value = value
this._selectedAttr.value = value
}
}
@@ -0,0 +1,71 @@
<?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/>.
-->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<include layout="@layout/layout_view_info_header" />
<include
android:id="@+id/_title_attr_divider"
layout="@layout/layout_divider_horizontal"
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/desc" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/attr_value"
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:hint="@string/hint_attr_value"
android:theme="@style/AppTheme.TextInputLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/comment"
app:layout_constraintTop_toTopOf="@id/comment">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:maxLines="1"
tools:text="match_parent" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/comment"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
app:layout_constraintEnd_toStartOf="@id/attr_value"
app:layout_constraintStart_toStartOf="@id/name"
app:layout_constraintTop_toBottomOf="@id/_title_attr_divider"
tools:text="Specifies the basic height of the view. This is a required attribute for any view inside of a containing layout manager. Its value may be a dimension (such as &quot;12dip&quot;) for a constant height or one of the special constants." />
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -34,14 +34,6 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/err_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
tools:text="This is an error." />
<LinearLayout
android:id="@+id/workspace"
android:layout_width="match_parent"
@@ -51,6 +43,14 @@
android:backgroundTintMode="src_atop"
android:orientation="vertical" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/err_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
tools:text="This is an error." />
</ViewFlipper>
@@ -0,0 +1,72 @@
<?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/>.
-->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/content_background"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<include layout="@layout/layout_view_info_header" />
<include
android:id="@+id/_title_attr_divider"
layout="@layout/layout_divider_horizontal"
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/desc" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/comment"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/name"
app:layout_constraintTop_toBottomOf="@id/_title_attr_divider"
tools:text="Specifies the basic height of the view. This is a required attribute for any view inside of a containing layout manager. Its value may be a dimension (such as &quot;12dip&quot;) for a constant height or one of the special constants." />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/attr_value"
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:hint="@string/hint_attr_value"
android:theme="@style/AppTheme.TextInputLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/comment">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:maxLines="1" />
</com.google.android.material.textfield.TextInputLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
@@ -20,29 +20,11 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/content_background"
android:paddingTop="16dp"
android:paddingBottom="16dp">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/view_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="TextView" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/view_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
app:layout_constraintStart_toStartOf="@id/view_name"
app:layout_constraintTop_toBottomOf="@id/view_name"
tools:text="android.widget.TextView" />
<include layout="@layout/layout_view_info_header" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_delete"
@@ -54,9 +36,9 @@
android:tooltipText="@string/title_viewaction_delete"
app:icon="@drawable/ic_delete"
app:iconTint="@color/secondaryIconColor"
app:layout_constraintBottom_toBottomOf="@id/view_info"
app:layout_constraintBottom_toBottomOf="@id/desc"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/view_name" />
app:layout_constraintTop_toTopOf="@id/name" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_add"
@@ -79,7 +61,7 @@
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/view_info" />
app:layout_constraintTop_toBottomOf="@id/desc" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/attr_list"
@@ -0,0 +1,44 @@
<?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/>.
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
<com.google.android.material.textview.MaterialTextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="TextView" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
app:layout_constraintStart_toStartOf="@id/name"
app:layout_constraintTop_toBottomOf="@id/name"
tools:text="android.widget.TextView" />
</merge>
@@ -0,0 +1,49 @@
<?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/>.
-->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ViewFlipper
android:id="@+id/flipper"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/view_info"
android:name="com.itsaky.androidide.uidesigner.fragments.ViewInfoFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="@layout/layout_view_info" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/attr_editor"
android:name="com.itsaky.androidide.uidesigner.fragments.AttrValueEditorFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout="@layout/layout_attr_value_editor" />
</ViewFlipper>
</androidx.constraintlayout.widget.ConstraintLayout>