mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
Added basic drag and drop in UI Designer
This commit is contained in:
Generated
+4
@@ -3,9 +3,13 @@
|
||||
<component name="DesignSurface">
|
||||
<option name="filePathToZoomLevelMap">
|
||||
<map>
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/drawable-mdpi/bg_widgets_list.xml" value="0.3105485232067511" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/drawable/bg_design_container_background.xml" value="0.3105485232067511" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/drawable/bg_ripple.xml" value="0.3105485232067511" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/drawable/bg_ripple_pressed.xml" value="0.3105485232067511" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/drawable/bg_widget_drag_placeholder.xml" value="0.33" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/drawable/bg_widget_group_selected.xml" value="0.33" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/drawable/bg_widgets_list.xml" value="0.3105485232067511" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/drawable/ic_replace.xml" value="0.3105485232067511" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/drawable/ic_widget_edittext.xml" value="0.3105485232067511" />
|
||||
<entry key="..\:/Projects/AndroidStudioProjects/android-ide/app/src/main/res/drawable/ic_widget_seekbar.xml" value="0.3105485232067511" />
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
**************************************************************************************/
|
||||
package com.itsaky.androidide;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
@@ -37,38 +39,43 @@ import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.view.GravityCompat;
|
||||
import androidx.transition.Fade;
|
||||
import androidx.transition.Slide;
|
||||
import androidx.transition.TransitionManager;
|
||||
import androidx.transition.TransitionSet;
|
||||
|
||||
import com.blankj.utilcode.util.ThrowableUtils;
|
||||
import com.itsaky.androidide.adapters.WidgetGroupItemAdapter;
|
||||
import com.itsaky.androidide.adapters.WidgetItemAdapter;
|
||||
import com.itsaky.androidide.app.StudioActivity;
|
||||
import com.itsaky.androidide.databinding.ActivityDesignerBinding;
|
||||
import com.itsaky.androidide.layoutinflater.WidgetDragListener;
|
||||
import com.itsaky.androidide.models.UIWidget;
|
||||
import com.itsaky.androidide.models.UIWidgetGroup;
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
import com.itsaky.layoutinflater.ILayoutInflater;
|
||||
import com.itsaky.layoutinflater.IView;
|
||||
import com.itsaky.toaster.Toaster;
|
||||
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DesignerActivity extends StudioActivity {
|
||||
public class DesignerActivity extends StudioActivity implements WidgetItemAdapter.OnDragStartListener {
|
||||
|
||||
private ActivityDesignerBinding mBinding;
|
||||
|
||||
private UIWidgetGroup selectedGroup;
|
||||
|
||||
public static final String KEY_LAYOUT_PATH = "designer_layoutPath";
|
||||
public static final String DRAGGING_WIDGET_TAG = "DRAGGING_WIDGET";
|
||||
public static final String DRAGGING_WIDGET_MIME = "application/ide_widget";
|
||||
|
||||
private static final Logger LOG = Logger.instance("DesignerActivity");
|
||||
|
||||
private final List<UIWidgetGroup> widgetGroups = new ArrayList<>();
|
||||
|
||||
private final WidgetItemAdapter.OnWidgetDragListener dragListener = (widget, v, event) -> {
|
||||
getApp().toast("Dragging: " + widget.getName(), Toaster.Type.INFO);
|
||||
return true;
|
||||
};
|
||||
|
||||
@Override
|
||||
protected View bindLayout() {
|
||||
mBinding = ActivityDesignerBinding.inflate(getLayoutInflater());
|
||||
@@ -79,21 +86,26 @@ public class DesignerActivity extends StudioActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setSupportActionBar(mBinding.toolbar);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
final var toggle = new ActionBarDrawerToggle(this, mBinding.getRoot(), mBinding.toolbar, R.string.app_name, R.string.app_name);
|
||||
mBinding.getRoot().addDrawerListener(toggle);
|
||||
toggle.syncState();
|
||||
|
||||
final var extras = getIntent().getExtras();
|
||||
final var path = extras.getString(KEY_LAYOUT_PATH, null);
|
||||
final var name = path.substring(path.lastIndexOf(File.separator) + 1);
|
||||
|
||||
getSupportActionBar().setTitle(name);
|
||||
|
||||
setSupportActionBar(mBinding.toolbar);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
final Bundle extras = getIntent().getExtras();
|
||||
final String path = extras.getString(KEY_LAYOUT_PATH, null);
|
||||
|
||||
try {
|
||||
final ILayoutInflater inflater = getApp().getLayoutInflater();
|
||||
inflater.resetContextProvider(newContextProvider());
|
||||
final IView view = inflater.inflatePath(path, mBinding.layoutContainer);
|
||||
mBinding.layoutContainer.addView(view.asView());
|
||||
|
||||
mBinding.layoutContainer.setOnDragListener(new WidgetDragListener(this));
|
||||
} catch (Throwable th) {
|
||||
mBinding.layoutContainer.removeAllViews();
|
||||
mBinding.layoutContainer.addView(createErrorText(th));
|
||||
@@ -120,11 +132,12 @@ public class DesignerActivity extends StudioActivity {
|
||||
|
||||
// IMPORTANT: Do not select any other groups here
|
||||
common.setSelected(true);
|
||||
this.selectedGroup = common;
|
||||
widgetGroups.add(common);
|
||||
|
||||
final var layouts = new UIWidgetGroup("Layouts");
|
||||
layouts.addChild(new UIWidget("LinearLayout", R.drawable.ic_widget_linear, LinearLayout.class));
|
||||
layouts.addChild(new UIWidget("RelativeLayout", R.drawable.ic_widget_relative, RelativeLayout.class));
|
||||
final var layouts = new UIWidgetGroup(getString(R.string.widget_group_layouts));
|
||||
layouts.addChild(new UIWidget(getString(R.string.layout_linear), R.drawable.ic_widget_linear, LinearLayout.class));
|
||||
layouts.addChild(new UIWidget(getString(R.string.layout_relative), R.drawable.ic_widget_relative, RelativeLayout.class));
|
||||
|
||||
widgetGroups.add(layouts);
|
||||
|
||||
@@ -134,9 +147,22 @@ public class DesignerActivity extends StudioActivity {
|
||||
showWidgetGroup(common);
|
||||
}
|
||||
|
||||
@SuppressLint("NotifyDataSetChanged")
|
||||
private void showWidgetGroup (@NonNull UIWidgetGroup group) {
|
||||
final var children = group.getChildren();
|
||||
mBinding.widgetItems.setAdapter(new WidgetItemAdapter(children, dragListener));
|
||||
this.mBinding.widgetItems.setAdapter(new WidgetItemAdapter(children, this));
|
||||
this.selectedGroup.setSelected(false);
|
||||
this.selectedGroup = group;
|
||||
this.selectedGroup.setSelected(true);
|
||||
|
||||
TransitionManager.beginDelayedTransition(mBinding.navigation,
|
||||
new TransitionSet()
|
||||
.addTransition(new Slide(Gravity.END))
|
||||
.addTransition(new Fade())
|
||||
);
|
||||
|
||||
//noinspection ConstantConditions
|
||||
this.mBinding.groupItems.getAdapter().notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -154,4 +180,9 @@ public class DesignerActivity extends StudioActivity {
|
||||
error.setBackgroundColor(ContextCompat.getColor(this, android.R.color.white));
|
||||
return error;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDragStarted(View view) {
|
||||
mBinding.getRoot().closeDrawer(GravityCompat.START);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.view.menu.MenuBuilder;
|
||||
@@ -118,6 +121,8 @@ import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.eclipse.lsp4j.DidChangeConfigurationParams;
|
||||
import org.eclipse.lsp4j.InitializeResult;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
|
||||
import com.itsaky.androidide.lsp.IDELanguageClientImpl;
|
||||
|
||||
public class EditorActivity extends StudioActivity implements FileTreeFragment.FileActionListener,
|
||||
@@ -392,7 +397,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
if (getBuildService() == null) return false;
|
||||
int id = item.getItemId();
|
||||
if (id == R.id.menuEditor_runDebug || id == R.id.menuEditor_quickRun) {
|
||||
getBuildService().assembleDebug(true);
|
||||
getmBuildServiceHandler().assembleDebug(true);
|
||||
} else if (id == R.id.menuEditor_runRelease) {
|
||||
getBuildService().assembleRelease();
|
||||
} else if (id == R.id.menuEditor_runClean) {
|
||||
@@ -661,7 +666,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDiagnosticClick(File file, Diagnostic diagnostic) {
|
||||
public void onDiagnosticClick(File file, @NonNull Diagnostic diagnostic) {
|
||||
openFileAndSelect(file, diagnostic.getRange());
|
||||
hideDiagnostics();
|
||||
hideViewOptions();
|
||||
@@ -686,7 +691,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
* @param initialX Initial X coordinate of view
|
||||
* @param initialY Initial Y coordinate of view
|
||||
*/
|
||||
public void positionViewWithinScreen(final View view, final float initialX, final float initialY) {
|
||||
public void positionViewWithinScreen(@NonNull final View view, final float initialX, final float initialY) {
|
||||
view.setX(initialX);
|
||||
view.setY(initialY);
|
||||
|
||||
@@ -727,7 +732,8 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabSelected(TabLayout.Tab tab) {
|
||||
public void
|
||||
onTabSelected(@NonNull TabLayout.Tab tab) {
|
||||
EditorFragment current = mPagerAdapter.getFrag(tab.getPosition());
|
||||
if(current != null && current.getFile() != null) {
|
||||
this.mCurrentFragment = current;
|
||||
@@ -739,7 +745,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(TabLayout.Tab tab) {
|
||||
public void onTabUnselected(@NonNull TabLayout.Tab tab) {
|
||||
EditorFragment frag = mPagerAdapter.getFrag(tab.getPosition());
|
||||
if(frag == null) return;
|
||||
boolean isGradle = frag.isModified() && frag.getFile().getName().endsWith(EditorFragment.EXT_GRADLE);
|
||||
@@ -755,7 +761,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(MenuItem p1) {
|
||||
public boolean onNavigationItemSelected(@NonNull MenuItem p1) {
|
||||
final int id = p1.getItemId();
|
||||
if(id == R.id.editornav_discuss) {
|
||||
getApp().openTelegramGroup();
|
||||
@@ -980,7 +986,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
return result.gradleSaved;
|
||||
}
|
||||
|
||||
public void install(File apk) {
|
||||
public void install(@NonNull File apk) {
|
||||
if(apk.exists()) {
|
||||
Intent i = IntentUtils.getInstallAppIntent(apk);
|
||||
if(i != null) {
|
||||
@@ -1096,6 +1102,8 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
.create();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Contract(" -> new")
|
||||
private ILayoutInflater.ContextProvider getContextProvider() {
|
||||
return new ILayoutInflater.ContextProvider() {
|
||||
@Override
|
||||
@@ -1105,6 +1113,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
};
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Set<File> getResourceDirectories() {
|
||||
final Set<File> dirs = new HashSet<>();
|
||||
if (mProject != null && mProject.getModulePaths() != null && !mProject.getModulePaths().isEmpty()) {
|
||||
@@ -1211,10 +1220,12 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
handleSearchResultVisibility(true);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private MaterialContainerTransform createContainerTransformFor(View start, View end) {
|
||||
return createContainerTransformFor(start, end, mBinding.realContainer);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private MaterialContainerTransform createContainerTransformFor(View start, View end, View drawingView) {
|
||||
return TransformUtils.createContainerTransformFor(start, end, drawingView);
|
||||
}
|
||||
@@ -1231,10 +1242,10 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
mFileOptionsHandler.start();
|
||||
|
||||
mBuildServiceHandler.start();
|
||||
getBuildService().assembleDebug(false);
|
||||
getmBuildServiceHandler().assembleDebug(false);
|
||||
}
|
||||
|
||||
private void removeFromParent(View v) {
|
||||
private void removeFromParent(@NonNull View v) {
|
||||
if(v.getParent() != null && v.getParent() instanceof ViewGroup) {
|
||||
((ViewGroup) v.getParent()).removeView(v);
|
||||
}
|
||||
@@ -1253,7 +1264,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshSymbolInput(EditorFragment frag) {
|
||||
private void refreshSymbolInput(@NonNull EditorFragment frag) {
|
||||
symbolInput.bindEditor(frag.getEditor());
|
||||
symbolInput.setSymbols(Symbols.forFile(frag.getFile()));
|
||||
}
|
||||
@@ -1263,7 +1274,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
getSyncBanner()
|
||||
.setNegative(android.R.string.cancel, null)
|
||||
.setPositive(android.R.string.ok, v -> {
|
||||
getBuildService().assembleDebug(false);
|
||||
getmBuildServiceHandler().assembleDebug(false);
|
||||
})
|
||||
.show();
|
||||
}
|
||||
@@ -1305,6 +1316,7 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
return mFindInProjectDialog == null ? createFindInProjectDialog() : mFindInProjectDialog;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private AlertDialog createFindInProjectDialog() {
|
||||
if(mProject == null
|
||||
|| mProject.getModulePaths() == null
|
||||
@@ -1385,6 +1397,10 @@ public class EditorActivity extends StudioActivity implements FileTreeFragment.F
|
||||
private IDEService getBuildService() {
|
||||
return mBuildServiceHandler.getService();
|
||||
}
|
||||
|
||||
public BuildServiceHandler getmBuildServiceHandler () {
|
||||
return mBuildServiceHandler;
|
||||
}
|
||||
|
||||
private void showNeedHelpDialog() {
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this, R.style.AppTheme_MaterialAlertDialog);
|
||||
|
||||
@@ -70,6 +70,7 @@ public class SimpleIconTextAdapter extends RecyclerView.Adapter<SimpleIconTextAd
|
||||
} else {
|
||||
binding.icon.setImageResource(icon);
|
||||
}
|
||||
|
||||
binding.text.setText(item.getText());
|
||||
|
||||
if (this.bindListener != null) {
|
||||
|
||||
@@ -17,6 +17,13 @@
|
||||
|
||||
package com.itsaky.androidide.adapters;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.itsaky.androidide.R;
|
||||
import com.itsaky.androidide.models.IconTextListItem;
|
||||
import com.itsaky.androidide.models.UIWidgetGroup;
|
||||
|
||||
@@ -26,30 +33,32 @@ public class WidgetGroupItemAdapter extends SimpleIconTextAdapter implements Sim
|
||||
|
||||
private final OnGroupClickListener clickListener;
|
||||
|
||||
public WidgetGroupItemAdapter(List<UIWidgetGroup> groups, OnGroupClickListener clickListener) {
|
||||
public WidgetGroupItemAdapter(@NonNull List<UIWidgetGroup> groups, @Nullable OnGroupClickListener clickListener) {
|
||||
super(groups);
|
||||
this.clickListener = clickListener;
|
||||
|
||||
super.setOnBindListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBind(IconTextListItem item, VH holder, int position) {
|
||||
final var binding = holder.binding;
|
||||
final var group = (UIWidgetGroup) getItemAt(position);
|
||||
|
||||
if (this.clickListener != null) {
|
||||
binding.getRoot().setOnClickListener(v -> this.clickListener.onGroupClick(group));
|
||||
}
|
||||
|
||||
// Ignored
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postBind(IconTextListItem item, VH holder, int position) {
|
||||
public void postBind(IconTextListItem item, @NonNull VH holder, int position) {
|
||||
final var binding = holder.binding;
|
||||
final var group = (UIWidgetGroup) item;
|
||||
|
||||
if (group.isSelected()) {
|
||||
binding.getRoot().setBackground(ContextCompat.getDrawable(binding.getRoot().getContext(), R.drawable.bg_widget_group_selected));
|
||||
} else {
|
||||
binding.getRoot().setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
|
||||
if (this.clickListener != null) {
|
||||
binding.getRoot().setOnClickListener(v -> this.clickListener.onGroupClick(group));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,13 @@
|
||||
|
||||
package com.itsaky.androidide.adapters;
|
||||
|
||||
import android.view.DragEvent;
|
||||
import android.content.ClipData;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.itsaky.androidide.DesignerActivity;
|
||||
import com.itsaky.androidide.layoutinflater.WidgetDragShadowBuilder;
|
||||
import com.itsaky.androidide.models.IconTextListItem;
|
||||
import com.itsaky.androidide.models.UIWidget;
|
||||
|
||||
@@ -29,30 +31,43 @@ import java.util.List;
|
||||
|
||||
public class WidgetItemAdapter extends SimpleIconTextAdapter implements SimpleIconTextAdapter.OnBindListener {
|
||||
|
||||
private final OnWidgetDragListener dragListener;
|
||||
private final OnDragStartListener dragStartListener;
|
||||
|
||||
public WidgetItemAdapter(List<UIWidget> widgets, OnWidgetDragListener dragListener) {
|
||||
public WidgetItemAdapter(List<UIWidget> widgets, OnDragStartListener dragStartListener) {
|
||||
super(widgets);
|
||||
this.dragListener = dragListener;
|
||||
this.dragStartListener = dragStartListener;
|
||||
|
||||
setOnBindListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onBind(IconTextListItem item, @NonNull VH holder, int position) {
|
||||
final var binding = holder.binding;
|
||||
final var widget = (UIWidget) getItemAt(position);
|
||||
|
||||
if (this.dragListener != null) {
|
||||
binding.getRoot().setOnDragListener((v, event) -> {
|
||||
return this.dragListener.onDrag(widget, v, event);
|
||||
});
|
||||
}
|
||||
|
||||
return false; // Returning true will not set the text and icon
|
||||
}
|
||||
|
||||
public static interface OnWidgetDragListener {
|
||||
boolean onDrag(UIWidget widget, View v, DragEvent event);
|
||||
@Override
|
||||
public void postBind(IconTextListItem item, VH holder, int position) {
|
||||
final var binding = holder.binding;
|
||||
final var root = binding.getRoot();
|
||||
final var widget = (UIWidget) getItemAt(position);
|
||||
|
||||
root.setOnLongClickListener(v -> {
|
||||
final var shadow = new WidgetDragShadowBuilder(binding.icon);
|
||||
final var dataItem = new ClipData.Item(DesignerActivity.DRAGGING_WIDGET_TAG);
|
||||
final var data = new ClipData(DesignerActivity.DRAGGING_WIDGET_TAG,
|
||||
new String[]{DesignerActivity.DRAGGING_WIDGET_MIME},
|
||||
dataItem);
|
||||
binding.icon.startDragAndDrop(data, shadow, widget, 0);
|
||||
|
||||
if (this.dragStartListener != null) {
|
||||
this.dragStartListener.onDragStarted(v);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
public interface OnDragStartListener {
|
||||
void onDragStarted (View view);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ package com.itsaky.androidide.app;
|
||||
import com.google.firebase.messaging.FirebaseMessaging;
|
||||
import com.itsaky.androidide.app.StudioApp;
|
||||
import com.itsaky.androidide.language.xml.completion.XMLCompletionService;
|
||||
import com.itsaky.androidide.layoutinflater.IDELayoutInflater;
|
||||
import com.itsaky.androidide.services.MessagingService;
|
||||
import com.itsaky.layoutinflater.ILayoutInflater;
|
||||
import com.itsaky.layoutinflater.LayoutInflaterConfiguration;
|
||||
@@ -73,7 +74,7 @@ public class StudioApp extends BaseApplication {
|
||||
}
|
||||
|
||||
public void createInflater (LayoutInflaterConfiguration config) {
|
||||
this.mLayoutInflater = ILayoutInflater.newInstance(config);
|
||||
this.mLayoutInflater = new IDELayoutInflater(config);
|
||||
}
|
||||
|
||||
public ILayoutInflater getLayoutInflater () {
|
||||
|
||||
@@ -40,7 +40,8 @@ import java.util.stream.Collectors;
|
||||
public class BuildServiceHandler extends IDEHandler implements BuildListener {
|
||||
|
||||
private IDEService service;
|
||||
|
||||
private boolean shouldInstallApk = false;
|
||||
|
||||
public BuildServiceHandler(Provider provider) {
|
||||
super(provider);
|
||||
}
|
||||
@@ -51,15 +52,18 @@ public class BuildServiceHandler extends IDEHandler implements BuildListener {
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if(this.activity() == null)
|
||||
if(this.activity() == null) {
|
||||
throwNPE();
|
||||
}
|
||||
|
||||
AndroidProject project = provider.provideAndroidProject();
|
||||
if(project == null)
|
||||
if(project == null) {
|
||||
throwNPE();
|
||||
}
|
||||
|
||||
if(project.getProjectPath() == null)
|
||||
if(project.getProjectPath() == null) {
|
||||
throwNPE();
|
||||
}
|
||||
|
||||
this.service = new IDEService(new File(project.getProjectPath()));
|
||||
this.service.setListener(this);
|
||||
@@ -116,11 +120,12 @@ public class BuildServiceHandler extends IDEHandler implements BuildListener {
|
||||
public void onBuildSuccessful(GradleTask task, String msg) {
|
||||
appendOutput(task, msg);
|
||||
if(task == null || activity() == null) return;
|
||||
if(task.canOutput())
|
||||
if(task.canOutput()) {
|
||||
activity().setStatus(msg);
|
||||
}
|
||||
|
||||
// If this task generates APK, ask user if he/she wants to install them
|
||||
if (task instanceof ApkGeneratingTask) {
|
||||
if (shouldInstallApk && task instanceof ApkGeneratingTask) {
|
||||
final IDEProject project = activity().provideIDEProject();
|
||||
final Optional<IDEModule> app = project.getModuleByPath(":app"); // TODO Handle multiple application modules
|
||||
if(app.isPresent()) {
|
||||
@@ -175,6 +180,15 @@ public class BuildServiceHandler extends IDEHandler implements BuildListener {
|
||||
}
|
||||
activity().getBinding().buildProgressIndicator.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public void setShouldInstallApk (boolean install) {
|
||||
this.shouldInstallApk = install;
|
||||
}
|
||||
|
||||
public void assembleDebug (boolean shouldInstallApk) {
|
||||
setShouldInstallApk(shouldInstallApk);
|
||||
getService().assembleDebug(shouldInstallApk);
|
||||
}
|
||||
|
||||
private boolean isClasspathValid(String path) {
|
||||
if(path == null || path.trim().length() <= 0 || path.trim().equals("/")) return false;
|
||||
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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.layoutinflater;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.itsaky.layoutinflater.LayoutInflaterConfiguration;
|
||||
import com.itsaky.layoutinflater.XMLLayoutInflater;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
/**
|
||||
* A layout inflater for inflating views from XML.
|
||||
* This implementation handles IDE-specific stuff. Like, setting drag listeners to view groups.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
public class IDELayoutInflater extends XMLLayoutInflater {
|
||||
|
||||
public IDELayoutInflater(LayoutInflaterConfiguration config) {
|
||||
super(config);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected View createAndroidViewForName(String name) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
|
||||
final var view = super.createAndroidViewForName(name);
|
||||
if (view instanceof ViewGroup) {
|
||||
final var group = (ViewGroup) view;
|
||||
group.setOnDragListener(new WidgetDragListener(group.getContext()));
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
}
|
||||
+82
@@ -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.layoutinflater;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
import android.view.DragEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.blankj.utilcode.util.SizeUtils;
|
||||
import com.itsaky.androidide.DesignerActivity;
|
||||
import com.itsaky.androidide.R;
|
||||
import com.itsaky.toaster.Toaster;
|
||||
|
||||
public class WidgetDragListener implements View.OnDragListener {
|
||||
|
||||
private final View placeholder;
|
||||
|
||||
private final int PLACEHOLDER_HEIGHT = 20; // in dp
|
||||
private final int PLACEHOLDER_WIDTH = 40; // in dp
|
||||
|
||||
public WidgetDragListener(@NonNull Context context) {
|
||||
this.placeholder = new View(context);
|
||||
this.placeholder.setBackgroundResource(R.drawable.bg_widget_drag_placeholder);
|
||||
this.placeholder.setLayoutParams(new ViewGroup.LayoutParams(SizeUtils.dp2px(PLACEHOLDER_WIDTH), SizeUtils.dp2px(PLACEHOLDER_HEIGHT)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDrag(View v, @NonNull DragEvent event) {
|
||||
final var group = (ViewGroup) v; // Assuming that this drag listener is always set to ViewGroup(s)
|
||||
final var action = event.getAction();
|
||||
final var clipDesc = event.getClipDescription();
|
||||
|
||||
switch (action) {
|
||||
case DragEvent.ACTION_DRAG_STARTED:
|
||||
if (clipDesc.hasMimeType(DesignerActivity.DRAGGING_WIDGET_MIME)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case DragEvent.ACTION_DRAG_ENTERED:
|
||||
removePlaceholderFromParent();
|
||||
group.addView(this.placeholder);
|
||||
break;
|
||||
case DragEvent.ACTION_DRAG_EXITED:
|
||||
removePlaceholderFromParent();
|
||||
break;
|
||||
case DragEvent.ACTION_DROP:
|
||||
removePlaceholderFromParent();
|
||||
Toast.makeText(group.getContext(), "Widget dropped", Toast.LENGTH_SHORT).show();
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void removePlaceholderFromParent () {
|
||||
if (this.placeholder.getParent() != null) {
|
||||
((ViewGroup) this.placeholder.getParent()).removeView((this.placeholder));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.layoutinflater;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.view.View;
|
||||
|
||||
public class WidgetDragShadowBuilder extends View.DragShadowBuilder {
|
||||
|
||||
private final double TOUCH_Y_OFFSET = 0.3;
|
||||
|
||||
public WidgetDragShadowBuilder (View view) {
|
||||
super(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) {
|
||||
if (getView() != null) {
|
||||
final var width = getView().getWidth();
|
||||
final var height = getView().getHeight();
|
||||
outShadowSize.set(width, height);
|
||||
outShadowTouchPoint.set(width / 2, height + (int) (height * TOUCH_Y_OFFSET));
|
||||
} else {
|
||||
super.onProvideShadowMetrics(outShadowSize, outShadowTouchPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,7 @@ import org.eclipse.lsp4j.Diagnostic;
|
||||
import org.eclipse.lsp4j.Position;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
|
||||
// TODO Request Language server for syntax highlighting instead of waiting for it to send highlight ranges
|
||||
public class JavaLexerImpl extends io.github.rosemoe.editor.langs.AbstractCodeAnalyzer {
|
||||
|
||||
private final EditorLanguage language;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?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/>.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<stroke android:width="1dp"
|
||||
android:color="@android:color/darker_gray"
|
||||
android:dashGap="3dp"
|
||||
android:dashWidth="6dp"/>
|
||||
|
||||
</shape>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?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/>.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<solid
|
||||
android:color="@color/primaryLightColor"
|
||||
/>
|
||||
<corners
|
||||
android:radius="5dp"
|
||||
/>
|
||||
|
||||
</shape>
|
||||
@@ -1,32 +1,32 @@
|
||||
<?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/>.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<solid
|
||||
android:color="@android:color/black"
|
||||
/>
|
||||
|
||||
<corners
|
||||
android:bottomLeftRadius="10dp"
|
||||
android:topLeftRadius="10dp"
|
||||
android:topRightRadius="0dp"
|
||||
android:bottomRightRadius="0dp"/>
|
||||
|
||||
<?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/>.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
|
||||
<solid
|
||||
android:color="@color/bg_widget_selected"
|
||||
/>
|
||||
|
||||
<corners
|
||||
android:bottomLeftRadius="10dp"
|
||||
android:topLeftRadius="10dp"
|
||||
android:topRightRadius="0dp"
|
||||
android:bottomRightRadius="0dp"/>
|
||||
|
||||
</shape>
|
||||
@@ -5,8 +5,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:animateLayoutChanges="true"
|
||||
tools:context=".DesignerActivity"
|
||||
tools:openDrawer="start">
|
||||
tools:context=".DesignerActivity">
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/main_container"
|
||||
@@ -35,13 +34,18 @@
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true"
|
||||
android:contentDescription="@string/label_ui_designer_content"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="32dp"
|
||||
android:paddingTop="32dp"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" />
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/bg_design_container_background"/>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
@@ -58,10 +62,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:weightSum="2.0">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
@@ -69,28 +69,27 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="0.7"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="0dp"
|
||||
android:paddingBottom="16dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/layout_simple_icon_text"
|
||||
tools:itemCount="1"/>
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="@color/primaryLightColor" />
|
||||
tools:itemCount="1"
|
||||
tools:listitem="@layout/layout_simple_icon_text" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/widget_items"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1.3"
|
||||
android:background="@color/bg_widget_selected"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingBottom="16dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
|
||||
tools:listitem="@layout/layout_simple_icon_text"
|
||||
tools:itemCount="3" />
|
||||
tools:itemCount="3"
|
||||
tools:listitem="@layout/layout_simple_icon_text" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_ripple"
|
||||
android:clickable="true"
|
||||
android:descendantFocusability="blocksDescendants"
|
||||
android:focusable="true"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingBottom="2dp"
|
||||
android:paddingStart="4dp"
|
||||
android:minHeight="35dp">
|
||||
|
||||
<ImageView
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<color name="diagnostic_warning">@color/log_warning</color>
|
||||
<color name="content_background">#212121</color>
|
||||
<color name="bg_green">#4CAF50</color>
|
||||
<color name="bg_widget_selected">#212121</color>
|
||||
<color name="transform_scrim">#70000000</color>
|
||||
|
||||
<color name="textActionNameColor">@android:color/tertiary_text_light</color>
|
||||
|
||||
@@ -303,4 +303,7 @@
|
||||
<string name="widget_radio_button">RadioButton</string>
|
||||
<string name="widget_seekbar">SeekBar</string>
|
||||
<string name="widget_spinner">Spinner</string>
|
||||
<string name="widget_group_layouts">Layouts</string>
|
||||
<string name="layout_linear">LinearLayout</string>
|
||||
<string name="layout_relative">RelativeLayout</string>
|
||||
</resources>
|
||||
|
||||
@@ -28,10 +28,6 @@ import com.itsaky.androidide.app.BaseApplication;
|
||||
import com.itsaky.androidide.ui.util.Preconditions;
|
||||
import com.itsaky.androidide.utils.Logger;
|
||||
import com.itsaky.attrinfo.AttrInfo;
|
||||
import com.itsaky.layoutinflater.IAttribute;
|
||||
import com.itsaky.layoutinflater.IAttributeAdapter;
|
||||
import com.itsaky.layoutinflater.IView;
|
||||
import com.itsaky.layoutinflater.IViewGroup;
|
||||
import com.itsaky.layoutinflater.adapters.android.view.ViewAttrAdapter;
|
||||
import com.itsaky.layoutinflater.adapters.android.view.ViewGroupAttrAdapter;
|
||||
import com.itsaky.layoutinflater.impl.BaseView;
|
||||
@@ -54,7 +50,7 @@ import org.jsoup.parser.Parser;
|
||||
|
||||
import static com.itsaky.androidide.ui.util.Preconditions.*;
|
||||
|
||||
class XMLLayoutInflater extends BaseLayoutInflater {
|
||||
public class XMLLayoutInflater extends BaseLayoutInflater {
|
||||
|
||||
private final Set<File> resDirs;
|
||||
private final AttrInfo attrInfo;
|
||||
@@ -67,10 +63,10 @@ class XMLLayoutInflater extends BaseLayoutInflater {
|
||||
public static final String ATTR_ADAPTER_SUFFIX = "AttrAdapter";
|
||||
|
||||
private XMLLayoutInflater () {
|
||||
throw new UnsupportedOperationException("Cannot instantiate inflater");
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
XMLLayoutInflater(LayoutInflaterConfiguration config) {
|
||||
public XMLLayoutInflater(LayoutInflaterConfiguration config) {
|
||||
this.resDirs = config.resDirs;
|
||||
this.attrInfo = config.attrInfo;
|
||||
this.widgetInfo = config.widgetInfo;
|
||||
@@ -263,9 +259,7 @@ class XMLLayoutInflater extends BaseLayoutInflater {
|
||||
|
||||
// TODO Try to load classes directly from .class files
|
||||
try {
|
||||
final Class<? extends View> loaded = Class.forName(name).asSubclass(View.class);
|
||||
final Constructor<? extends View> constructor = loaded.getConstructor(Context.class /*, AttributeSet.class, int.class*/);
|
||||
final View created = constructor.newInstance(contextProvider.getContext()/*, null, style*/);
|
||||
final View created = createAndroidViewForName(name);
|
||||
final BaseView view =
|
||||
created instanceof ViewGroup
|
||||
? new UiViewGroup (name, (ViewGroup) created)
|
||||
@@ -276,6 +270,14 @@ class XMLLayoutInflater extends BaseLayoutInflater {
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
protected View createAndroidViewForName(String name) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, java.lang.reflect.InvocationTargetException {
|
||||
final Class<? extends View> loaded = Class.forName(name).asSubclass(View.class);
|
||||
final Constructor<? extends View> constructor = loaded.getConstructor(Context.class /*, AttributeSet.class, int.class*/);
|
||||
final View created = constructor.newInstance(contextProvider.getContext()/*, null, style*/);
|
||||
return created;
|
||||
}
|
||||
|
||||
protected IView applyLayoutParams(IView view, ViewGroup parent) {
|
||||
final ViewGroup.LayoutParams params = generateLayoutParams(parent);
|
||||
view.asView().setLayoutParams(params);
|
||||
|
||||
Reference in New Issue
Block a user