mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
Implement basic attribute editor
This commit is contained in:
Generated
+1
@@ -24,6 +24,7 @@
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/layout/activity_editor.xml" value="0.264" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/layout/activity_main.xml" value="0.20253164556962025" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/layout/fragment_editor.xml" value="0.20512820512820512" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/layout/layour_dimension_editor.xml" value="0.20512820512820512" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/layout/layout_about_items.xml" value="0.20512820512820512" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/layout/layout_attr_editor.xml" value="0.2936708860759494" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/layout/layout_attr_editor_item.xml" value="0.264" />
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
package com.itsaky.androidide.fragments.sheets;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -24,6 +25,7 @@ import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.transition.ChangeBounds;
|
||||
import androidx.transition.TransitionManager;
|
||||
|
||||
@@ -36,6 +38,7 @@ import com.itsaky.androidide.databinding.LayoutAttrEditorSheetBinding;
|
||||
import com.itsaky.androidide.databinding.LayoutAttrEditorSheetItemBinding;
|
||||
import com.itsaky.androidide.models.IconTextListItem;
|
||||
import com.itsaky.androidide.models.XMLAttribute;
|
||||
import com.itsaky.androidide.utils.AttributeDialogs;
|
||||
import com.itsaky.androidide.utils.DialogUtils;
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
import com.itsaky.layoutinflater.IView;
|
||||
@@ -44,8 +47,11 @@ import com.itsaky.toaster.Toaster;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.itsaky.attrinfo.models.Attr.*;
|
||||
|
||||
public class AttrEditorSheet extends BottomSheetDialogFragment implements SimpleIconTextAdapter.OnBindListener {
|
||||
|
||||
private static final List<IconTextListItem> VIEW_ACTIONS = new ArrayList<> ();
|
||||
@@ -76,6 +82,14 @@ public class AttrEditorSheet extends BottomSheetDialogFragment implements Simple
|
||||
}
|
||||
|
||||
setupViewData ();
|
||||
|
||||
AttributeDialogs.init (getActivity ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss (@NonNull DialogInterface dialog) {
|
||||
AttributeDialogs.release ();
|
||||
super.onDismiss (dialog);
|
||||
}
|
||||
|
||||
public AttrEditorSheet setDeletionFailedListener (OnViewDeletionFailedListener listener) {
|
||||
@@ -111,6 +125,31 @@ public class AttrEditorSheet extends BottomSheetDialogFragment implements Simple
|
||||
LOG.error (getString (R.string.msg_no_attr_format), attribute);
|
||||
return;
|
||||
}
|
||||
|
||||
showEditorDialog (attribute);
|
||||
}
|
||||
|
||||
private void showEditorDialog (@NonNull XMLAttribute attribute) {
|
||||
final var format = attribute.getFormat ();
|
||||
final var attr = attribute.getAttr ();
|
||||
|
||||
AlertDialog dialog = null;
|
||||
if (hasFormat (format, DIMENSION)) {
|
||||
if (attr == null) {
|
||||
throw new IllegalStateException ("The provided attribute has not been resoleved.");
|
||||
}
|
||||
|
||||
final var possibleValues = attr.possibleValues;
|
||||
dialog = AttributeDialogs.dimensionEditor (possibleValues.toArray(new String[0]), attribute.getValue (), (dialog1, which) -> {
|
||||
LOG.debug ("Dimension value changed to : " + attribute.getValue ());
|
||||
});
|
||||
}
|
||||
|
||||
// TODO Once the user has selected another value, update it for the view too.
|
||||
}
|
||||
|
||||
private boolean hasFormat (int format, int check) {
|
||||
return (format &check ) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,8 +21,10 @@ import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.itsaky.androidide.app.StudioApp;
|
||||
import com.itsaky.attrinfo.models.Attr;
|
||||
import com.itsaky.layoutinflater.IAttribute;
|
||||
import com.itsaky.layoutinflater.impl.UiAttribute;
|
||||
|
||||
@@ -47,6 +49,8 @@ public class XMLAttribute extends UiAttribute implements Parcelable {
|
||||
*/
|
||||
private int format = -1;
|
||||
|
||||
private Attr attr;
|
||||
|
||||
public XMLAttribute (IAttribute attribute) {
|
||||
this (attribute, true);
|
||||
}
|
||||
@@ -79,14 +83,18 @@ public class XMLAttribute extends UiAttribute implements Parcelable {
|
||||
}
|
||||
|
||||
final var attrs = StudioApp.getInstance ().attrInfo ();
|
||||
final var attr = attrs.getAttribute (getAttributeName ());
|
||||
if (attr != null) {
|
||||
this.format = attr.format;
|
||||
this.attr = attrs.getAttribute (getAttributeName ());
|
||||
if (this.attr != null) {
|
||||
this.format = this.attr.format;
|
||||
}
|
||||
|
||||
return getFormat ();
|
||||
}
|
||||
|
||||
public Attr getAttr () {
|
||||
return attr;
|
||||
}
|
||||
|
||||
public static final Creator<XMLAttribute> CREATOR = new Creator<XMLAttribute> () {
|
||||
@NonNull
|
||||
@Contract("_ -> new")
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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.utils;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.RadioGroup;
|
||||
|
||||
import static com.itsaky.androidide.utils.DialogUtils.newMaterialDialogBuilder;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import com.itsaky.androidide.R;
|
||||
import com.itsaky.androidide.databinding.LayoutDimensionEditorBinding;
|
||||
|
||||
/**
|
||||
* Helper class for creating dialogs for editing view attributes.
|
||||
*
|
||||
* TODO Should we merge this into {@link DialogUtils}
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class AttributeDialogs {
|
||||
|
||||
private static final String DIMENSION_MATCH = "match_parent";
|
||||
private static final String DIMENSION_WRAP = "wrap_content";
|
||||
|
||||
/**
|
||||
* Context that will be used for creating dialogs.
|
||||
* This must be initialized by calling {@link #init(Context)}
|
||||
* and the reference must be released by calling {@link #release()}
|
||||
*/
|
||||
private static Context mContext;
|
||||
|
||||
/**
|
||||
* Initialize this class with the provided context.
|
||||
* @param ctx The context that will be used for creating dialogs.
|
||||
* @see #release()
|
||||
*/
|
||||
public static void init (Context ctx) {
|
||||
mContext = ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the context instance stored in this class.
|
||||
*
|
||||
* @see #init(Context)
|
||||
*/
|
||||
public static void release () {
|
||||
mContext = null;
|
||||
}
|
||||
|
||||
public static AlertDialog dimensionEditor (CharSequence[] values, CharSequence value, DialogInterface.OnClickListener onSubmit) {
|
||||
final var binding = LayoutDimensionEditorBinding.inflate(LayoutInflater.from (mContext));
|
||||
binding.choices.setOnCheckedChangeListener ((group, checkedId) -> {
|
||||
binding.otherValue.setVisibility (binding.other.isChecked () ? View.VISIBLE : View.GONE);
|
||||
});
|
||||
|
||||
if (DIMENSION_MATCH.equals (value)) {
|
||||
binding.choices.check (R.id.match);
|
||||
} else if (DIMENSION_WRAP.equals (value)) {
|
||||
binding.choices.check (R.id.wrap);
|
||||
} else {
|
||||
binding.choices.check (R.id.other);
|
||||
}
|
||||
|
||||
final var builder = newMaterialDialogBuilder (mContext);
|
||||
builder.setView (binding.getRoot ());
|
||||
builder.setPositiveButton (android.R.string.ok, ((dialog, which) -> {
|
||||
dialog.dismiss ();
|
||||
if (onSubmit != null) {
|
||||
onSubmit.onClick (dialog, which);
|
||||
}
|
||||
}));
|
||||
builder.setNegativeButton (android.R.string.cancel, (dialog, which) -> dialog.dismiss ());
|
||||
return builder.show ();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #enumSelector(CharSequence[], int, DialogInterface.OnClickListener)
|
||||
*/
|
||||
public static AlertDialog enumSelector (CharSequence[] values, CharSequence value, DialogInterface.OnClickListener onSelected) {
|
||||
return enumSelector (values, findIndexOf (values, value), onSelected);
|
||||
}
|
||||
|
||||
private static int findIndexOf (@NonNull CharSequence[] values, CharSequence value) {
|
||||
for (int i=0;i<values.length;i++) {
|
||||
if (value.equals (values[i])) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
throw new IndexOutOfBoundsException ("Cannot find index for value: " + value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new single choice dialog for selecting enum values.
|
||||
* @param values The value entries in the enum declaration.
|
||||
* @param selected The item that will be selected when the dialog is shown.
|
||||
* @param onSelected The click listener that will be invoked when an item is selected from the list.
|
||||
* @return The newly created dialog instance.
|
||||
*/
|
||||
public static AlertDialog enumSelector (CharSequence[] values, int selected, DialogInterface.OnClickListener onSelected) {
|
||||
final var builder = newMaterialDialogBuilder (mContext);
|
||||
builder.setSingleChoiceItems (values, selected, (dialog, which) -> {
|
||||
dialog.dismiss ();
|
||||
if (onSelected != null) {
|
||||
onSelected.onClick (dialog, which);
|
||||
}
|
||||
});
|
||||
return builder.show ();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -45,6 +45,16 @@ public class DialogUtils {
|
||||
return new MaterialAlertDialogBuilder (context, R.style.AppTheme_MaterialAlertDialog);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new alert dialog with two buttons: <span>Yes</span> and <span>No</span>.
|
||||
* This method simply calls {@link #newYesNoDialog(Context, String, String, DialogInterface.OnClickListener, DialogInterface.OnClickListener)}
|
||||
* with default values for title and message.
|
||||
*
|
||||
* @param context The context for the dialog.
|
||||
* @param positiveClickListener A listener that will be invoked on the <span>Yes</span> button click.
|
||||
* @param negativeClickListener A listener that will be invoked on the <span>No</span> button click.
|
||||
* @return The newly created dialog.
|
||||
*/
|
||||
@NonNull
|
||||
public static MaterialAlertDialogBuilder newYesNoDialog (Context context,
|
||||
DialogInterface.OnClickListener positiveClickListener,
|
||||
@@ -56,6 +66,16 @@ public class DialogUtils {
|
||||
negativeClickListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new alert dialog with two buttons: <span>Yes</span> and <span>No</span>.
|
||||
*
|
||||
* @param context The context for the dialog.
|
||||
* @param title The title of the dialog.
|
||||
* @param message The message of the dialog.
|
||||
* @param positiveClickListener A listener that will be invoked on the <span>Yes</span> button click.
|
||||
* @param negativeClickListener A listener that will be invoked on the <span>No</span> button click.
|
||||
* @return The newly created dialog instance.
|
||||
*/
|
||||
@NonNull
|
||||
public static MaterialAlertDialogBuilder newYesNoDialog (Context context,
|
||||
String title,
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/widget_name"
|
||||
android:layout_width="0dp"
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<?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/>.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/choices"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/match"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/attr_val_match_parent" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/wrap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/attr_val_wrap_content" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/other"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/attr_val_other" />
|
||||
|
||||
</RadioGroup>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/other_value"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/hint_new_attr_value">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -316,7 +316,7 @@
|
||||
<string name="hint_new_attr_value">New value</string>
|
||||
<string name="attr_val_wrap_content">wrap_content</string>
|
||||
<string name="attr_val_match_parent">match_parent</string>
|
||||
<string name="attr_val_fixed">Fixed</string>
|
||||
<string name="attr_val_other">Other value</string>
|
||||
<string name="msg_enter_dimension_value">Enter dimension value</string>
|
||||
<string name="msg_applicable_attrs">Applicable attributes</string>
|
||||
<string name="msg_attr_editor_actions">Actions</string>
|
||||
|
||||
Reference in New Issue
Block a user