mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
Use sheets to edit attribute values in UI Designer
This commit is contained in:
Generated
+5
@@ -41,5 +41,10 @@
|
||||
<option name="name" value="MavenLocal" />
|
||||
<option name="url" value="file:/$USER_HOME$/.m2/repository/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenLocal" />
|
||||
<option name="name" value="MavenLocal" />
|
||||
<option name="url" value="file:/$USER_HOME$/.m2/repository" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+1
@@ -49,6 +49,7 @@
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/layout/layout_attr_editor_sheet.xml" value="0.25" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/layout/layout_attr_editor_sheet_item.xml" value="0.25" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/layout/layout_attr_value_editor.xml" value="0.25" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/layout/layout_attr_value_editor_enum.xml" value="0.25" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/layout/layout_code_editor.xml" value="0.20185185185185187" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/layout/layout_completion_item.xml" value="0.23854166666666668" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/AndroidIDE/app/src/main/res/layout/layout_crash_report.xml" value="0.25" />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'com.google.firebase.crashlytics'
|
||||
|
||||
@@ -112,6 +113,10 @@ dependencies {
|
||||
implementation 'com.google.firebase:firebase-analytics'
|
||||
implementation 'com.google.firebase:firebase-crashlytics'
|
||||
implementation 'com.google.firebase:firebase-messaging'
|
||||
|
||||
// Kotlin
|
||||
implementation "androidx.core:core-ktx:1.7.0"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
|
||||
// Local projects here
|
||||
implementation project(':treeview')
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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.adapters;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentStatePagerAdapter;
|
||||
|
||||
import com.itsaky.androidide.fragments.attr.BaseValueEditorFragment;
|
||||
import com.itsaky.androidide.models.XMLAttribute;
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Adapter for value format tabs of attribute editor in UI Designer.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class AttrValueFormatTabAdapter extends FragmentStatePagerAdapter {
|
||||
|
||||
private static final Logger LOG = Logger.instance ("AttrValueEditorTabAdapter");
|
||||
private final List<Fragment> mFragments = new ArrayList<> ();
|
||||
private final List<String> mTitles = new ArrayList<> ();
|
||||
private final XMLAttribute attribute;
|
||||
|
||||
private final BaseValueEditorFragment.OnValueChangeListener changeListener;
|
||||
|
||||
public AttrValueFormatTabAdapter (@NonNull FragmentManager manager, XMLAttribute attribute, BaseValueEditorFragment.OnValueChangeListener changeListener) {
|
||||
super (manager);
|
||||
Objects.requireNonNull (attribute);
|
||||
|
||||
this.changeListener = changeListener;
|
||||
this.attribute = attribute;
|
||||
}
|
||||
|
||||
public void addFragment (final Class<? extends BaseValueEditorFragment> fragment, String title) {
|
||||
Objects.requireNonNull (fragment);
|
||||
Objects.requireNonNull (title);
|
||||
if (TextUtils.isEmpty (title.trim ())) {
|
||||
throw new IllegalArgumentException ("Invalid tab title");
|
||||
}
|
||||
|
||||
mTitles.add (capitalize (title));
|
||||
mFragments.add (createFragment (fragment, title));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private String capitalize (String title) {
|
||||
title = title.trim ();
|
||||
|
||||
final var sb = new StringBuilder ();
|
||||
for (int i = 0; i < title.length (); i++) {
|
||||
var ch = title.charAt (i);
|
||||
if (i == 0) {
|
||||
ch = Character.toUpperCase (ch);
|
||||
} else {
|
||||
ch = Character.toLowerCase (ch);
|
||||
}
|
||||
|
||||
sb.append (ch);
|
||||
}
|
||||
|
||||
return sb.toString ();
|
||||
}
|
||||
|
||||
public String getTitle (int position) {
|
||||
return mTitles.get (position);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public Fragment createFragment (Class<? extends BaseValueEditorFragment> clazz, @NonNull final String name) {
|
||||
try {
|
||||
final var frag = clazz.newInstance ();
|
||||
frag.setAttribute (attribute);
|
||||
frag.setName (name);
|
||||
frag.setOnValueChangeListener (this.changeListener);
|
||||
|
||||
return frag;
|
||||
} catch (Throwable th) {
|
||||
LOG.error ("Unable to create value editor fragment", th);
|
||||
throw new RuntimeException (th);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAll () {
|
||||
mFragments.clear ();
|
||||
mTitles.clear ();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment getItem (int position) {
|
||||
return mFragments.get (position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount () {
|
||||
return mFragments.size ();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public CharSequence getPageTitle (int position) {
|
||||
return mTitles.get (position);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.fragments.attr;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.itsaky.androidide.models.XMLAttribute;
|
||||
import com.itsaky.inflater.IAttribute;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Base class for value editor fragment.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class BaseValueEditorFragment extends Fragment {
|
||||
|
||||
protected OnValueChangeListener mValueChangeListener;
|
||||
protected XMLAttribute attribute;
|
||||
protected String name;
|
||||
|
||||
public void setAttribute (XMLAttribute attribute) {
|
||||
this.attribute = attribute;
|
||||
}
|
||||
|
||||
public void setName (String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void setOnValueChangeListener (OnValueChangeListener listener) {
|
||||
this.mValueChangeListener = listener;
|
||||
}
|
||||
|
||||
protected void notifyValueChanged (@NonNull String newValue) {
|
||||
Objects.requireNonNull (newValue);
|
||||
|
||||
if (mValueChangeListener != null) {
|
||||
mValueChangeListener.onValueChanged (this.attribute, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for listening for value change event.
|
||||
*/
|
||||
public interface OnValueChangeListener {
|
||||
/**
|
||||
* Called when the value was changed.
|
||||
*
|
||||
* @param attribute The attribute whose value was changed.
|
||||
* @param newValue The new value for the editor.
|
||||
*/
|
||||
void onValueChanged (IAttribute attribute, String newValue);
|
||||
}
|
||||
}
|
||||
@@ -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.fragments.attr;
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class BooleanEditor extends BaseValueEditorFragment {
|
||||
}
|
||||
@@ -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.fragments.attr;
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class ColorEditor extends BaseValueEditorFragment {
|
||||
}
|
||||
@@ -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.fragments.attr;
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class DimensionEditor extends BaseValueEditorFragment {
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.fragments.attr;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.material.chip.Chip;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class EnumEditor extends FixedValueEditor {
|
||||
|
||||
@Override
|
||||
public void onViewCreated (@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated (view, savedInstanceState);
|
||||
|
||||
Objects.requireNonNull (this.attribute);
|
||||
Objects.requireNonNull (this.chipGroup);
|
||||
|
||||
this.chipGroup.setSingleSelection (true);
|
||||
|
||||
final var attr = this.attribute.getAttr ();
|
||||
for (var value : attr.possibleValues) {
|
||||
if (TextUtils.isEmpty (value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.chipGroup.addView (newChip (value, value.equals (this.attribute.getValue ())));
|
||||
}
|
||||
|
||||
this.chipGroup.setOnCheckedChangeListener ((group, checkedId) -> {
|
||||
final var chip = (Chip) group.findViewById (checkedId);
|
||||
final var val = chip.getText ().toString ().trim ();
|
||||
notifyValueChanged (val);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.fragments.attr;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.google.android.material.chip.Chip;
|
||||
import com.google.android.material.chip.ChipGroup;
|
||||
import com.itsaky.androidide.R;
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public abstract class FixedValueEditor extends BaseValueEditorFragment {
|
||||
|
||||
protected ChipGroup chipGroup;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView (@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
this.chipGroup = new ChipGroup (inflater.getContext ());
|
||||
this.chipGroup.setLayoutParams (new ViewGroup.LayoutParams (ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
this.chipGroup.setSelectionRequired (true);
|
||||
this.chipGroup.setSingleSelection (false);
|
||||
|
||||
return this.chipGroup;
|
||||
}
|
||||
|
||||
protected Chip newChip (String title, boolean checked) {
|
||||
final var chip = new Chip (requireContext ());
|
||||
chip.setText (title);
|
||||
chip.setCheckedIcon (ContextCompat.getDrawable (requireContext (), R.drawable.ic_ok));
|
||||
chip.setChecked (checked);
|
||||
chip.setChipBackgroundColor (ContextCompat.getColorStateList (requireContext (), R.color.bg_enum_chips));
|
||||
chip.setTextColor (ContextCompat.getColor (requireContext (), R.color.primaryTextColor));
|
||||
chip.setLayoutParams (new ChipGroup.LayoutParams (ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
chip.setChipStrokeWidth (1f);
|
||||
chip.setChipStrokeColor (ColorStateList.valueOf (ContextCompat.getColor (requireContext (), R.color.primaryDarkColor)));
|
||||
|
||||
return chip;
|
||||
}
|
||||
}
|
||||
@@ -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.fragments.attr;
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class FlagEditor extends BaseValueEditorFragment {
|
||||
}
|
||||
@@ -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.fragments.attr;
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class FloatEditor extends BaseValueEditorFragment {
|
||||
}
|
||||
@@ -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.fragments.attr;
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class FractionEditor extends BaseValueEditorFragment {
|
||||
}
|
||||
@@ -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.fragments.attr;
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class IntegerEditor extends BaseValueEditorFragment {
|
||||
}
|
||||
@@ -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.fragments.attr;
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class ReferenceEditor extends BaseValueEditorFragment {
|
||||
}
|
||||
@@ -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.fragments.attr;
|
||||
|
||||
/**
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class StringEditor extends BaseValueEditorFragment {
|
||||
}
|
||||
@@ -75,6 +75,7 @@ public class AttrEditorSheet extends BottomSheetDialogFragment
|
||||
private static final List<IconTextListItem> VIEW_ACTIONS = new ArrayList<> ();
|
||||
private static final Logger LOG = Logger.instance ("AttrBottomSheet");
|
||||
private AttributeListSheet mAttrListSheet;
|
||||
private AttrValueEditorSheet mValueEditorSheet;
|
||||
private IView selectedView;
|
||||
private File layout;
|
||||
private LayoutAttrEditorSheetBinding binding;
|
||||
@@ -108,8 +109,6 @@ public class AttrEditorSheet extends BottomSheetDialogFragment
|
||||
R.drawable.ic_view_select_parent));
|
||||
}
|
||||
|
||||
binding.valueEditorLayout.closeButton.setOnClickListener (v -> hideValueEditorLayout ());
|
||||
|
||||
setupViewData ();
|
||||
|
||||
AttributeDialogs.init (requireActivity ());
|
||||
@@ -171,12 +170,11 @@ public class AttrEditorSheet extends BottomSheetDialogFragment
|
||||
return;
|
||||
}
|
||||
|
||||
showEditorDialog (attribute);
|
||||
showValueEditorSheet (attribute);
|
||||
}
|
||||
|
||||
private void hideValueEditorLayout () {
|
||||
TransitionManager.beginDelayedTransition (binding.getRoot ());
|
||||
binding.valueEditorLayout.getRoot ().setVisibility (View.GONE);
|
||||
private void showValueEditorSheet (@NonNull XMLAttribute attribute) {
|
||||
getValueEditorSheet (attribute).show (getChildFragmentManager (), "attr_value_editor_sheet");
|
||||
}
|
||||
|
||||
private void showEditorDialog (@NonNull XMLAttribute attribute) {
|
||||
@@ -371,10 +369,36 @@ public class AttrEditorSheet extends BottomSheetDialogFragment
|
||||
return mAttrListSheet;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public AttrValueEditorSheet getValueEditorSheet (@NonNull XMLAttribute attribute) {
|
||||
|
||||
if (mValueEditorSheet == null) {
|
||||
mValueEditorSheet = AttrValueEditorSheet.newInstance (attribute);
|
||||
mValueEditorSheet.setOnValueChangeListener (this::onValueChanged);
|
||||
}
|
||||
|
||||
mValueEditorSheet.setAttribute (attribute);
|
||||
return mValueEditorSheet;
|
||||
}
|
||||
|
||||
public void onValueChanged (@NonNull IAttribute attribute, String newValue) {
|
||||
Objects.requireNonNull (this.selectedView);
|
||||
|
||||
final var attributeName = attribute.getAttributeName ();
|
||||
final var namespace = attribute.getNamespace ();
|
||||
|
||||
if (this.selectedView.hasAttribute (namespace, attributeName)) {
|
||||
this.selectedView.updateAttribute (namespace, attributeName, newValue);
|
||||
} else {
|
||||
final var attr = new UiAttribute (namespace, attributeName, newValue);
|
||||
this.selectedView.addAttribute (attr);
|
||||
}
|
||||
}
|
||||
|
||||
private void addNewAttribute (@NonNull Attr attr) {
|
||||
final XMLAttribute attribute = new XMLAttribute (attr.namespace, attr.name, "", false);
|
||||
attribute.setAttr (attr);
|
||||
showEditorDialog (attribute);
|
||||
showValueEditorSheet (attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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.fragments.sheets;
|
||||
|
||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_BOOLEAN;
|
||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_COLOR;
|
||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_DIMENSION;
|
||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_ENUM;
|
||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_FLAG;
|
||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_FLOAT;
|
||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_FRACTION;
|
||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_INTEGER;
|
||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_REFERENCE;
|
||||
import static com.itsaky.attrinfo.models.Attr.FORMAT_STRING;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||
import com.itsaky.androidide.adapters.AttrValueFormatTabAdapter;
|
||||
import com.itsaky.androidide.databinding.LayoutAttrValueEditorBinding;
|
||||
import com.itsaky.androidide.fragments.attr.BaseValueEditorFragment;
|
||||
import com.itsaky.androidide.fragments.attr.BooleanEditor;
|
||||
import com.itsaky.androidide.fragments.attr.ColorEditor;
|
||||
import com.itsaky.androidide.fragments.attr.DimensionEditor;
|
||||
import com.itsaky.androidide.fragments.attr.EnumEditor;
|
||||
import com.itsaky.androidide.fragments.attr.FlagEditor;
|
||||
import com.itsaky.androidide.fragments.attr.FloatEditor;
|
||||
import com.itsaky.androidide.fragments.attr.FractionEditor;
|
||||
import com.itsaky.androidide.fragments.attr.IntegerEditor;
|
||||
import com.itsaky.androidide.fragments.attr.ReferenceEditor;
|
||||
import com.itsaky.androidide.fragments.attr.StringEditor;
|
||||
import com.itsaky.androidide.models.XMLAttribute;
|
||||
import com.itsaky.attrinfo.models.Attr;
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Sheet for editing value of an attribute.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class AttrValueEditorSheet extends BottomSheetDialogFragment {
|
||||
|
||||
private static final String KEY_ATTRIBUTE = "attrEditorSheet_attribute";
|
||||
private LayoutAttrValueEditorBinding binding;
|
||||
private AttrValueFormatTabAdapter adapter;
|
||||
private XMLAttribute attribute;
|
||||
|
||||
private BaseValueEditorFragment.OnValueChangeListener changeListener;
|
||||
|
||||
public void setOnValueChangeListener (BaseValueEditorFragment.OnValueChangeListener changeListener) {
|
||||
this.changeListener = changeListener;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static AttrValueEditorSheet newInstance (final XMLAttribute attribute) {
|
||||
Objects.requireNonNull (attribute);
|
||||
|
||||
final var args = new Bundle ();
|
||||
args.putParcelable (KEY_ATTRIBUTE, attribute);
|
||||
|
||||
final var fragment = new AttrValueEditorSheet ();
|
||||
fragment.setArguments (args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView (@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
this.binding = LayoutAttrValueEditorBinding.inflate (inflater, container, false);
|
||||
return binding.getRoot ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated (@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated (view, savedInstanceState);
|
||||
|
||||
if (attribute == null) {
|
||||
this.attribute = requireArguments ().getParcelable (KEY_ATTRIBUTE);
|
||||
}
|
||||
|
||||
Objects.requireNonNull (this.attribute);
|
||||
|
||||
final var namespace = this.attribute.getNamespace ();
|
||||
final var formatText = Attr.createFormatText (attribute.getFormat ());
|
||||
this.binding.attributeName.setText (String.format ("%s:%s", namespace.getName (), attribute.getAttributeName ()));
|
||||
this.binding.attributeFormat.setText (formatText);
|
||||
|
||||
setupTabs (formatText);
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private void setupTabs (@NonNull String formatText) {
|
||||
this.binding.tabs.removeAllTabs ();
|
||||
this.binding.pager.setSaveEnabled (false);
|
||||
|
||||
if (this.adapter != null) {
|
||||
this.adapter.removeAll ();
|
||||
this.adapter.notifyDataSetChanged ();
|
||||
}
|
||||
|
||||
this.adapter = new AttrValueFormatTabAdapter (getChildFragmentManager (), attribute, changeListener);
|
||||
|
||||
final var formats = formatText.split ("\\|");
|
||||
for (var formatName : formats) {
|
||||
if (TextUtils.isEmpty (formatName) || formatName.length () < 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final var frag = getFragmentClass (formatName);
|
||||
if (frag != null) {
|
||||
this.adapter.addFragment (frag, formatName);
|
||||
}
|
||||
}
|
||||
|
||||
binding.pager.setAdapter (this.adapter);
|
||||
binding.tabs.setupWithViewPager (binding.pager);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Contract(pure = true)
|
||||
private Class<? extends BaseValueEditorFragment> getFragmentClass (@NonNull String name) {
|
||||
switch (name) {
|
||||
case FORMAT_REFERENCE:
|
||||
return ReferenceEditor.class;
|
||||
case FORMAT_COLOR:
|
||||
return ColorEditor.class;
|
||||
case FORMAT_BOOLEAN:
|
||||
return BooleanEditor.class;
|
||||
case FORMAT_DIMENSION:
|
||||
return DimensionEditor.class;
|
||||
case FORMAT_FLOAT:
|
||||
return FloatEditor.class;
|
||||
case FORMAT_INTEGER:
|
||||
return IntegerEditor.class;
|
||||
case FORMAT_FRACTION:
|
||||
return FractionEditor.class;
|
||||
case FORMAT_STRING:
|
||||
return StringEditor.class;
|
||||
case FORMAT_ENUM:
|
||||
return EnumEditor.class;
|
||||
case FORMAT_FLAG:
|
||||
return FlagEditor.class;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setAttribute (XMLAttribute attribute) {
|
||||
Objects.requireNonNull (attribute);
|
||||
this.attribute = attribute;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.itsaky.androidide.views;
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.ViewGroup
|
||||
import com.google.android.material.tabs.TabLayout
|
||||
|
||||
// https://stackoverflow.com/a/65605542
|
||||
class ScalableTabLayout : TabLayout {
|
||||
constructor(context: Context) : super(context)
|
||||
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
|
||||
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
|
||||
context,
|
||||
attrs,
|
||||
defStyleAttr
|
||||
)
|
||||
|
||||
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
||||
val tabLayout = getChildAt(0) as ViewGroup
|
||||
val childCount = tabLayout.childCount
|
||||
if (childCount > 0) {
|
||||
val widthPixels = MeasureSpec.getSize(widthMeasureSpec)
|
||||
val tabMinWidth = widthPixels / childCount
|
||||
var remainderPixels = widthPixels % childCount
|
||||
for (i in 0 until childCount) {
|
||||
val it = tabLayout.getChildAt(i)
|
||||
if (remainderPixels > 0) {
|
||||
it.minimumWidth = tabMinWidth + 1
|
||||
remainderPixels--
|
||||
} else {
|
||||
it.minimumWidth = tabMinWidth
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* 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.views;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.google.android.material.textfield.MaterialAutoCompleteTextView;
|
||||
import com.itsaky.androidide.ui.edit.IValueSuggestionProvider;
|
||||
import com.itsaky.androidide.utils.TextWatcherAdapter;
|
||||
import com.itsaky.inflater.IAttribute;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* {@link MaterialAutoCompleteTextView} implementation used for providing suggestions while editing
|
||||
* attribute values.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
@SuppressLint("ViewConstructor")
|
||||
public class ValueEditorTextView extends MaterialAutoCompleteTextView {
|
||||
|
||||
private final IAttribute attribute;
|
||||
private final int format;
|
||||
private final Set<IValueSuggestionProvider> mSuggestionProviders = new HashSet<>();
|
||||
|
||||
private final TextWatcher watcher =
|
||||
new TextWatcherAdapter() {
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(@NonNull Editable s) {
|
||||
final var prefix = s.toString();
|
||||
final var items = new ArrayList<String>();
|
||||
|
||||
for (IValueSuggestionProvider provider : mSuggestionProviders) {
|
||||
if (provider.checkFormat(format)) {
|
||||
items.addAll(provider.suggest(attribute, prefix));
|
||||
}
|
||||
}
|
||||
|
||||
setThreshold(1);
|
||||
setAdapter(
|
||||
new ArrayAdapter<>(
|
||||
getContext(), android.R.layout.simple_list_item_1, items));
|
||||
}
|
||||
};
|
||||
|
||||
public ValueEditorTextView(@NonNull Context context, IAttribute attribute, int format) {
|
||||
super(context);
|
||||
this.attribute = attribute;
|
||||
this.format = format;
|
||||
|
||||
addTextChangedListener(this.watcher);
|
||||
}
|
||||
|
||||
public void registerSuggestionProvider(IValueSuggestionProvider provider) {
|
||||
Objects.requireNonNull(provider);
|
||||
mSuggestionProviders.add(provider);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?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/>.
|
||||
-->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/secondaryLightColor_transparent" android:state_checked="true" android:state_selected="true" />
|
||||
<item android:color="@color/content_background" />
|
||||
</selector>
|
||||
@@ -19,18 +19,16 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/content_background"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="8dp">
|
||||
android:background="@color/content_background">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/widget_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/primaryDarkColor"
|
||||
android:ellipsize="middle"
|
||||
android:maxLines="1"
|
||||
android:padding="16dp"
|
||||
android:textColor="@color/primaryTextColor"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
@@ -39,55 +37,55 @@
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Button" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/actions_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/msg_attr_editor_actions"
|
||||
android:textColor="@color/secondaryTextColor"
|
||||
app:layout_constraintStart_toStartOf="@id/widget_name"
|
||||
app:layout_constraintTop_toBottomOf="@id/widget_name" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/actions_list"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/actions_header" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/attrs_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/msg_applicable_attrs"
|
||||
android:textColor="@color/secondaryTextColor"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/actions_list" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/attr_list"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/attrs_header" />
|
||||
|
||||
<include
|
||||
android:id="@+id/value_editor_layout"
|
||||
layout="@layout/layout_attr_value_editor"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:visibility="gone"
|
||||
android:padding="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toBottomOf="@id/widget_name">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/actions_header"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/msg_attr_editor_actions"
|
||||
android:textColor="@color/secondaryTextColor"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/actions_list"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/actions_header" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/attrs_header"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
android:text="@string/msg_applicable_attrs"
|
||||
android:textColor="@color/secondaryTextColor"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/actions_list" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/attr_list"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/attrs_header" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -19,19 +19,21 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@color/content_background"
|
||||
tools:padding="16dp">
|
||||
android:background="@color/content_background">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/attribute_name"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@color/primaryDarkColor"
|
||||
android:maxLines="1"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:textColor="@color/primaryTextColor"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintEnd_toStartOf="@id/close_button"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="android:layout_height" />
|
||||
@@ -40,35 +42,46 @@
|
||||
android:id="@+id/attribute_format"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@color/primaryDarkColor"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:textColor="@color/secondaryTextColor_light"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintEnd_toStartOf="@id/close_button"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/attribute_name"
|
||||
tools:text="dimension|reference" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/close_button"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:padding="8dp"
|
||||
android:src="@drawable/ic_close"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.LinearLayoutCompat
|
||||
android:id="@+id/editor_layout_container"
|
||||
<com.itsaky.androidide.views.ScalableTabLayout
|
||||
android:id="@+id/tabs"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/primaryDarkColor"
|
||||
android:clipChildren="false"
|
||||
android:clipToPadding="false"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/attribute_format" />
|
||||
app:layout_constraintTop_toBottomOf="@id/attribute_format"
|
||||
app:tabBackground="@android:color/transparent"
|
||||
app:tabIndicatorAnimationMode="elastic"
|
||||
app:tabIndicatorColor="@color/secondaryColor"
|
||||
app:tabIndicatorHeight="3dp"
|
||||
app:tabMaxWidth="0dp"
|
||||
app:tabMode="scrollable"
|
||||
app:tabSelectedTextColor="@color/secondaryColor"
|
||||
app:tabTextAppearance="@style/AppTheme.TabLayout.Title" />
|
||||
|
||||
<androidx.viewpager.widget.ViewPager
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:minHeight="100dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tabs" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -5,6 +5,7 @@
|
||||
<color name="primaryDarkColor">#010101</color>
|
||||
<color name="secondaryColor">#ff5252</color>
|
||||
<color name="secondaryLightColor">#ff867f</color>
|
||||
<color name="secondaryLightColor_transparent">#1FFF867F</color>
|
||||
<color name="secondaryDarkColor">#c50e29</color>
|
||||
<color name="primaryTextColor">#ffffff</color>
|
||||
<color name="primaryTextColorLight">#bdbdbd</color>
|
||||
|
||||
@@ -39,7 +39,7 @@ import java.util.regex.Pattern;
|
||||
* @see com.itsaky.attrinfo.AttrInfo
|
||||
*/
|
||||
public class Attr {
|
||||
|
||||
|
||||
public static final int REFERENCE = 1;
|
||||
public static final int COLOR = 1 << 1;
|
||||
public static final int BOOLEAN = 1 << 2;
|
||||
@@ -51,122 +51,135 @@ public class Attr {
|
||||
public static final int ENUM = 1 << 8;
|
||||
public static final int FLAG = 1 << 9;
|
||||
public static final int UNKNOWN = 1 << 10;
|
||||
private static final Logger LOG = Logger.instance("AttrInfo::Attr");
|
||||
|
||||
public static final String FORMAT_REFERENCE = "reference";
|
||||
public static final String FORMAT_COLOR = "color";
|
||||
public static final String FORMAT_BOOLEAN = "boolean";
|
||||
public static final String FORMAT_DIMENSION = "dimension";
|
||||
public static final String FORMAT_FLOAT = "float";
|
||||
public static final String FORMAT_INTEGER = "integer";
|
||||
public static final String FORMAT_FRACTION = "fraction";
|
||||
public static final String FORMAT_STRING = "string";
|
||||
public static final String FORMAT_ENUM = "enum";
|
||||
public static final String FORMAT_FLAG = "flag";
|
||||
|
||||
private static final Logger LOG = Logger.instance ("AttrInfo::Attr");
|
||||
|
||||
public INamespace namespace;
|
||||
public String name;
|
||||
public Set<String> possibleValues;
|
||||
public int format;
|
||||
|
||||
public Attr(String name) {
|
||||
this(name, INamespace.ANDROID);
|
||||
|
||||
public Attr (String name) {
|
||||
this (name, INamespace.ANDROID);
|
||||
}
|
||||
|
||||
public Attr(String name, INamespace namespace) {
|
||||
|
||||
public Attr (String name, INamespace namespace) {
|
||||
this.name = name;
|
||||
this.namespace = namespace;
|
||||
this.possibleValues = new TreeSet<>();
|
||||
this.possibleValues = new TreeSet<> ();
|
||||
}
|
||||
|
||||
public static int formatForName(@NonNull String names) {
|
||||
|
||||
public static int formatForName (@NonNull String names) {
|
||||
var result = 0;
|
||||
if (names.contains("|")) {
|
||||
for (var name : names.split(Pattern.quote("|"))) {
|
||||
result |= formatForSingleName(name);
|
||||
if (names.contains ("|")) {
|
||||
for (var name : names.split (Pattern.quote ("|"))) {
|
||||
result |= formatForSingleName (name);
|
||||
}
|
||||
} else {
|
||||
result = formatForSingleName(names);
|
||||
result = formatForSingleName (names);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Contract(pure = true)
|
||||
public static int formatForSingleName(@NonNull String name) {
|
||||
public static int formatForSingleName (@NonNull String name) {
|
||||
switch (name) {
|
||||
case "reference":
|
||||
case FORMAT_REFERENCE:
|
||||
return REFERENCE;
|
||||
case "color":
|
||||
case FORMAT_COLOR:
|
||||
return COLOR;
|
||||
case "boolean":
|
||||
case FORMAT_BOOLEAN:
|
||||
return BOOLEAN;
|
||||
case "dimension":
|
||||
case FORMAT_DIMENSION:
|
||||
return DIMENSION;
|
||||
case "float":
|
||||
case FORMAT_FLOAT:
|
||||
return FLOAT;
|
||||
case "integer":
|
||||
case FORMAT_INTEGER:
|
||||
return INTEGER;
|
||||
case "fraction":
|
||||
case FORMAT_FRACTION:
|
||||
return FRACTION;
|
||||
case "string":
|
||||
case FORMAT_STRING:
|
||||
return STRING;
|
||||
case "enum":
|
||||
case FORMAT_ENUM:
|
||||
return ENUM;
|
||||
case "flag":
|
||||
case FORMAT_FLAG:
|
||||
return FLAG;
|
||||
default:
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public static String createFormatText(int format) {
|
||||
final var formats = new ArrayList<String>();
|
||||
|
||||
public static String createFormatText (int format) {
|
||||
final var formats = new ArrayList<String> ();
|
||||
if ((format & REFERENCE) != 0) {
|
||||
formats.add("reference");
|
||||
formats.add (FORMAT_REFERENCE);
|
||||
}
|
||||
|
||||
|
||||
if ((format & COLOR) != 0) {
|
||||
formats.add("color");
|
||||
formats.add (FORMAT_COLOR);
|
||||
}
|
||||
|
||||
|
||||
if ((format & BOOLEAN) != 0) {
|
||||
formats.add("boolean");
|
||||
formats.add (FORMAT_BOOLEAN);
|
||||
}
|
||||
|
||||
|
||||
if ((format & DIMENSION) != 0) {
|
||||
formats.add("dimension");
|
||||
formats.add (FORMAT_DIMENSION);
|
||||
}
|
||||
|
||||
|
||||
if ((format & FLOAT) != 0) {
|
||||
formats.add("float");
|
||||
formats.add (FORMAT_FLOAT);
|
||||
}
|
||||
|
||||
|
||||
if ((format & INTEGER) != 0) {
|
||||
formats.add("integer");
|
||||
formats.add (FORMAT_INTEGER);
|
||||
}
|
||||
|
||||
|
||||
if ((format & FRACTION) != 0) {
|
||||
formats.add("fraction");
|
||||
formats.add (FORMAT_FRACTION);
|
||||
}
|
||||
|
||||
|
||||
if ((format & STRING) != 0) {
|
||||
formats.add("string");
|
||||
formats.add (FORMAT_STRING);
|
||||
}
|
||||
|
||||
|
||||
if ((format & ENUM) != 0) {
|
||||
formats.add("enum");
|
||||
formats.add (FORMAT_ENUM);
|
||||
}
|
||||
|
||||
|
||||
if ((format & FLAG) != 0) {
|
||||
formats.add("flag");
|
||||
formats.add (FORMAT_FLAG);
|
||||
}
|
||||
|
||||
if (formats.isEmpty()) {
|
||||
formats.add("unknown");
|
||||
|
||||
if (formats.isEmpty ()) {
|
||||
formats.add ("unknown");
|
||||
}
|
||||
|
||||
return TextUtils.join("|", formats);
|
||||
|
||||
return TextUtils.join ("|", formats);
|
||||
}
|
||||
|
||||
public boolean hasPossibleValues() {
|
||||
return possibleValues != null && possibleValues.size() > 0;
|
||||
|
||||
public boolean hasPossibleValues () {
|
||||
return possibleValues != null && possibleValues.size () > 0;
|
||||
}
|
||||
|
||||
public boolean hasFormat(int format) {
|
||||
|
||||
public boolean hasFormat (int format) {
|
||||
return (this.format & format) != 0;
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
public String toString () {
|
||||
return "Attr ["
|
||||
+ " name: "
|
||||
+ name
|
||||
@@ -175,33 +188,33 @@ public class Attr {
|
||||
+ namespace
|
||||
+ "\n"
|
||||
+ " values: "
|
||||
+ TextUtils.join(", ", this.possibleValues)
|
||||
+ TextUtils.join (", ", this.possibleValues)
|
||||
+ "\n"
|
||||
+ " format: "
|
||||
+ format
|
||||
+ "\n"
|
||||
+ "]";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
public boolean equals (Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
|
||||
if (o == null || getClass () != o.getClass ()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Attr attr = (Attr) o;
|
||||
return format == attr.format
|
||||
&& Objects.equals(namespace, attr.namespace)
|
||||
&& Objects.equals(name, attr.name)
|
||||
&& Objects.equals(possibleValues, attr.possibleValues);
|
||||
&& Objects.equals (namespace, attr.namespace)
|
||||
&& Objects.equals (name, attr.name)
|
||||
&& Objects.equals (possibleValues, attr.possibleValues);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(namespace, name, possibleValues, format);
|
||||
public int hashCode () {
|
||||
return Objects.hash (namespace, name, possibleValues, format);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user