Hey there, This is my first post here and will not be the last, I want to document my journey into making one of my dream projects in quite some time, and it's making some "IDE" for flutter development. It is something like FlutterFlow
but with better customization in a desktop format and more of a license payment structure rather than a subscription model.
The Start
Before Flutter
I always liked the idea of drag and drop to build UI, I got introduced to this concept with Visual Basic
I remember watching youtube on how to make a calculator or how to make a browser and I did make them but they were very limited as I was a noob in software development, but the thing that attracted me into Visual Basic
and later C#
window development was that you can just drag a UI component and drop it into view and then add some logic and voila you got an application.
In 2019 I found Flutter
which I just watched live when they announced version 1.0, and started learning it, it was the first time I started learning mobile development and I loved it, the language Dart
was very simple, and Flutter
itself was simple. But after using it for some time I wanted a tool that allowed me to just drag and drop but Flutter
was new and a tool like that didn't exist.
After some time a tool called FlutterFlow
was created, I was hyped when I heard about it so I tested it and then I started to see some things that I didn't enjoy that much, One that it's web-only and because my internet is not the best the site felt very slow and clunky to use, and also the payment method, they use a subscription model which I understand that the best choice for web-hosted software but it was just too expensive for me, and also it was very complex to learn and the code generation wasn't the best so I stopped using and kinda lost hope for a drag and drop tool for Flutter
.
As much as I wanted to build my version of FlutterFlow
I didn't have the technical skills to do so, so I just used Flutter
as is until about 2 weeks ago when I started thinking about such a tool again.
Prototyping
2 weeks ago I started thinking about building a no-code tool for Flutter
so I started researching what are the parts that make such software work, I found packages for different aspects of the app so I started testing them in isolation to see how easy or hard to use them and was able to build a drag and drop system and code generation and everything started to look more possible tried to see what technologies FlutterFlow
are using but found nothing I'm assuming it Flutter
but who knows, so in this devlog and many to come I was to document my journey in how I'm making a no-code tool for Flutter
.
The structure
The core functionality of this app is that you drag an element and drop it into the editor and should be able to change widget properties.
Now the data structure I made might not be the best but for now, it's working, what I did was create an abstract class called Component
and this component has a getter for the preview and a function called build, the getter is for the widget that gets drawn in the editor most of them have a DragTarget
as the top widget so it can detect when components are dropped into it and can update the child, and the build function only returns the string that this component will generate.
Now to make component properties easy and flexible I created an abstract class called ComponentProperty<T>
it takes a generic type so I can have access to methods and parameters of those types
now each property would created separately and extend ComponentProperty<T>
class, this is an example of a property of type double that can be used for the width, height..etc of a component
class DoubleComponentProperty extends ComponentProperty<double> {
DoubleComponentProperty(super.name, super.value);
@override
Widget get preview => ListTile(
title: Text(name.capitalize()),
subtitle: description == null ? null : Text(description ?? ""),
trailing: SizedBox(
width: 100,
child: InputField(
initialValue: value.toString().replaceAll(RegExp(r'([.]*0)(?!.*\d)'), ""),
onChanged: (value) {
valueSetter = double.tryParse(value) ?? 0;
update();
},
),
),
);
}
now each property has a name and value and a setter for the value this will later show the preview in the inspector when you select a component on the editor.
And for the components we create a component for each Widget
in Flutter
I know it takes time to support all widgets but it's the best I can think of
and here is an example code for a container component
class ContainerComponent extends Component {
ContainerComponent()
: super(
TextComponentProperty("name", "Container"),
Icons.rectangle_rounded,
);
Component? child;
DoubleComponentProperty width = DoubleComponentProperty("width", 100);
DoubleComponentProperty height = DoubleComponentProperty("height", 100);
ColorComponentProperty color = ColorComponentProperty(Colors.red);
AlginmentComponentProperty alginment = AlginmentComponentProperty("alignment", AlignmentType.topLeft);
DoubleComponentProperty radius = DoubleComponentProperty("radius", 0);
@override
List<ComponentProperty> get properties => [
alginment,
color,
width,
height,
radius,
];
@override
String build() {
if (child == null) {
return """
Container(
alignment: ${alginment.value.toString()},
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(${radius.value}),
color: Color(0x${color.value.value.toRadixString(16)}),
),
width: ${width.value},
height: ${height.value},
)
""";
}
return """
Container(
alignment: ${alginment.value.toString()},
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(${radius.value}),
color: Color(0x${color.value.value.toRadixString(16)}),
),
width: ${width.value},
height: ${height.value},
child: ${child?.build()},
)
""";
}
@override
Component get object => ContainerComponent();
@override
Widget get preview => DragTarget<Component>(
onAcceptWithDetails: (details) {
child = details.data;
},
builder: (context, candidateData, rejectedData) {
return GestureDetector(
onTap: () => onSelect(),
child: Container(
alignment: alginment.value.alignment,
height: height.value,
width: width.value,
decoration: BoxDecoration(
color: color.value,
borderRadius: BorderRadius.circular(radius.value),
),
child: child?.preview,
),
);
},
);
}
this is the widget responsible for drawing a container on the editor and generating the code for it later.
For dragging I'm using Draggable
widget that comes with Flutter
it does the job very well.
Code Generation
For this in each component there is a build function that returns the string of the component, but I also use a package made by the dart team called code_builder
for generating the stateless widget that wraps everything, and dart_style
to do code formatting.
Now this shows the basic structure of my data for the moment although I'm thinking about changing the component system at the moment this is how I store things. the UI of the app is still experimental it's not the best but it does the job for the moment.
Top comments (0)