Skip to content

Commit

Permalink
v0.2.0:
Browse files Browse the repository at this point in the history
- Button: no padding if image
- pass unconstrainedWidth/Height; if unconstrainedWidth && fill_parent, wrap with Expanded; (for Image also if automatic width);
- Image: always BoxFit.contain
- HorizontalArrangement/VerticalArrangement: add sizeProperties
- parseComponent: set width/height null if unconstrained instead of using Expanded
- parseComponent: use IntrinsicWidth for Arrangements (goal: ignore children with size=fill_parent when own size is automatic)
- Bugfix: handle empty Arrangements
- Bugfix: "items", not "count", in "lists_create_with"
- Bugfix: wrong for-each Syntax
- Add missing built-in text_compare
- Bugfix: "lists_length" and "lists_is_empty"
- Bugfix: handle empty AppName / Title
- try to parse numbers as int before parsing as double
- add support for Web component (missing some more advanced features)
- safer String addition with % operator
- add Player
  • Loading branch information
m0nac0 committed Dec 27, 2021
1 parent 980fcd9 commit a8264b6
Show file tree
Hide file tree
Showing 10 changed files with 600 additions and 120 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ comfortable building it in an admin shell!

- UI: complete except ListPicker, WebViewer & possibly some attributes on some components.
- Layout: complete (Change: TableArrangement is scrollable)
- Media: only Camera, Camcorder, ImagePicker
- Media: only Camera, Camcorder, ImagePicker, Player
- Drawing/Animation: none
- Maps: none
- Sensors: only Clock (limited)
Expand All @@ -126,7 +126,7 @@ comfortable building it in an admin shell!
- File does not have functionality for Delete, Append, LegacyMode
- NB TinyWebDB may not work correctly in web browsers, if the used web service does not run on https
(like the default one)
- Connectivity: none
- Connectivity: only Web (no sending/saving files, no cookies, no header/timeout control, no decoding with dictionaries)
- Mindstorms: none (will not implement due to lack of Mindstorms equipment)
- Experimental: none
- Extensions: not yet supported
Expand Down
39 changes: 36 additions & 3 deletions lib/compiler/aia_compiler_constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

import 'package:code_builder/code_builder.dart';
import 'package:xaif/compiler/util_parser.dart';

/// Contains constant data on AI-components' different properties and events
Expand Down Expand Up @@ -91,12 +92,14 @@ Map<String, Map<String, Expression>> properties = {
"HorizontalArrangement": {
...visibleProperties,
"AlignVertical": literalNum(1),
"AlignHorizontal": literalNum(1)
"AlignHorizontal": literalNum(1),
...sizeProperties,
},
"VerticalArrangement": {
...visibleProperties,
"AlignHorizontal": literalNum(1),
"AlignVertical": literalNum(1)
"AlignVertical": literalNum(1),
...sizeProperties,
},
"VerticalScrollArrangement": visibleProperties..addAll(sizeProperties),
"HorizontalScrollArrangement": visibleProperties..addAll(sizeProperties),
Expand Down Expand Up @@ -132,14 +135,23 @@ Map<String, Map<String, Expression>> properties = {
...visibleProperties,
...sizeProperties,
},
"Player": {
"IsPlaying": lfalse,
"Loop": lfalse,
"Source": literalString(""),
"Volume": literalNum(50),
},
"PhoneCall": {"PhoneNumber": literalString("")},
"Texting": {
"PhoneNumber": literalString(""),
"Message": literalString(""),
},
"TinyWebDB": {
"ServiceUrl": literalString("http://tinywebdb.appinventor.mit.edu")
}
},
"Web": {
"Url": literalString(""),
},
};

Map<String, List<Event>> events = {
Expand All @@ -160,6 +172,9 @@ Map<String, List<Event>> events = {
"ListView": [
Event("AfterPicking"),
],
"Player": [
Event("Completed"),
],
"File": [
Event("AfterFileSaved", {"fileName": refer("String")}),
Event("GotText", {"text": refer("String")}),
Expand All @@ -175,6 +190,24 @@ Map<String, List<Event>> events = {
Event("GotValue",
{"tagFromWebDB": refer("String"), "valueFromWebDB": refer("dynamic")}),
],
"Web": [
Event("GotFile", {
"url": r("String"),
"responseCode": r("double"),
"responseType": r("String"),
"fileName": r("String")
}),
Event("GotText", {
"url": r("String"),
"responseCode": r("int"),
"responseType": r("String"),
"responseContent": r("String")
}),
Event("TimedOut", {
"url": r("String"),
}),
],

// Not yet implemented:
"BarcodeScanner": [
Event("AfterScan", {"result": refer("String")})
Expand Down
42 changes: 35 additions & 7 deletions lib/compiler/aia_to_dart_compiler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ class AIAToDartCompiler {
final jsonString = scheme.substring(9, scheme.length - 3);
final decoded = jsonDecode(jsonString);

state.appName = decoded["Properties"]["AppName"];
state.screenName = decoded["Properties"]["Title"];
state.appName = decoded["Properties"]["AppName"] ?? "";
state.screenName = decoded["Properties"]["Title"] ?? "";
state.aboutMessage = decoded["Properties"]["AboutScreen"] ?? "";

final xml = blockly.isEmpty ? XmlDocument() : XmlDocument.parse(blockly);
Expand All @@ -74,7 +74,8 @@ class AIAToDartCompiler {
var componentParser = ComponentParser(state);
List<Expression> children =
(decoded["Properties"]["\$Components"] as Iterable)
.map((component) => componentParser.parseComponent(component))
.map((component) =>
componentParser.parseComponent(component, false, true))
.whereNotNull()
.toList();

Expand All @@ -86,7 +87,10 @@ class AIAToDartCompiler {
.map((e) => Field((b) => b
..name = e.key
..assignment = e.value?.code ?? literalNull.code))
.toList())
.toList()
.where((element) =>
state.gettersSetters.none((p0) => p0.name == element.name)))
..methods.addAll(state.gettersSetters)
..methods.add(Method((b) => b
..name = 'build'
..requiredParameters.add(Parameter((b) => b
Expand Down Expand Up @@ -205,6 +209,17 @@ class AIAToDartCompiler {
.statement,
])));
}
if (state.usesEnsureNum) {
b.methods.add(Method((m) => m
..name = "ensureNum"
..requiredParameters.add(Parameter((p) => p..name = "value"))
..lambda = true
..body = r("value")
.isA(r("num"))
.conditional(r("value"),
r("num.parse")([r("value").property("toString")([])]))
.code));
}
});

var myAppClass = Class((b) => b
Expand Down Expand Up @@ -232,12 +247,25 @@ class AIAToDartCompiler {
const dartVersion = "// @dart=2.9\r\n"; // no sound null safety
const linterHints =
"// ignore_for_file: non_constant_identifier_names\r\n// ignore_for_file: prefer_const_constructors\r\n";
var dartCode = DartFormatter()
.format(dartVersion + linterHints + library.accept(emitter).toString());
//possibly instead call toString() in text_join for every argument
const safePlusExtension = r'''extension SafePlus on String{
/// A safer String addition, that automatically calls toString() for
/// every added object (like AI does). Allows e.g. "a" + ["b"]
String operator % (dynamic a){
return this + a.toString();
}
}''';
var sourceString =
dartVersion + linterHints + library.accept(emitter).toString();
if (state.usesSafeStringAddition) {
sourceString += safePlusExtension;
}
var dartCode = DartFormatter().format(sourceString);
var packageRegex = RegExp(r"package:(\w+)\/[\w\/]+\.dart");
var imports = allocator.imports
.map((import) => packageRegex.firstMatch(import.url)?.group(1))
.whereNotNull();
.whereNotNull()
.toList();
return CompilationResult(dartCode, PubspecBuilder.getPubspec(imports));
}

Expand Down
Loading

0 comments on commit a8264b6

Please sign in to comment.