From 45e9a6aec5f0c49a7eb1024ca054537d832bdcd4 Mon Sep 17 00:00:00 2001 From: m0nac0 <58807793+m0nac0@users.noreply.github.com> Date: Thu, 30 Dec 2021 13:19:08 +0100 Subject: [PATCH] add support for Clock Timer --- README.md | 2 +- lib/compiler/aia_compiler_constants.dart | 9 +++++ lib/compiler/aia_to_dart_compiler.dart | 13 +++---- lib/compiler/parse_component.dart | 44 ++++++++++++++++++++++++ lib/compiler/parsing_state.dart | 6 ++++ lib/compiler/util_parser.dart | 1 + 6 files changed, 68 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2a13286..f4021fd 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ building it in an admin shell! - VideoPlayer only supported on Android/iOS/web and only supports network files (http:// or https:// URLs) - Drawing/Animation: none - Maps: none -- Sensors: only Clock (no Timer) +- Sensors: only Clock (Timer never fires while app is in the background) - Social: Sharing, Texting and PhoneCall (but no direct messages/calls; no intercepting of messages/calls) - Storage: complete, except CloudDB - File does not have functionality for Delete, Append, LegacyMode diff --git a/lib/compiler/aia_compiler_constants.dart b/lib/compiler/aia_compiler_constants.dart index 1c5b3a8..f1fea5d 100644 --- a/lib/compiler/aia_compiler_constants.dart +++ b/lib/compiler/aia_compiler_constants.dart @@ -159,6 +159,12 @@ Map> properties = { ...visibleProperties, ...sizeProperties, }, + "Clock": { + "TimerEnabled": ltrue, + "TimerInterval": literalNum(1000), + //TODO implement TimerAlwaysFires + "TimerAlwaysFires": ltrue, + }, "PhoneCall": {"PhoneNumber": literalString("")}, "Texting": { "PhoneNumber": literalString(""), @@ -199,6 +205,9 @@ Map> events = { "VideoPlayer": [ Event("Completed"), ], + "Clock": [ + Event("Timer"), + ], "File": [ Event("AfterFileSaved", {"fileName": refer("String")}), Event("GotText", {"text": refer("String")}), diff --git a/lib/compiler/aia_to_dart_compiler.dart b/lib/compiler/aia_to_dart_compiler.dart index 36e1286..3fe113f 100644 --- a/lib/compiler/aia_to_dart_compiler.dart +++ b/lib/compiler/aia_to_dart_compiler.dart @@ -193,12 +193,7 @@ class AIAToDartCompiler { ..name = "sharedPrefs" ..type = r("SharedPreferences") ..modifier)); - b.methods.add(Method((m) => m - ..name = "initState" - ..body = Block.of([ - r("initSharedPrefs")([]).statement, - r("super.initState").statement - ]))); + state.addInitStateStatement(r("initSharedPrefs")([]).statement); b.methods.add(Method((m) => m ..name = "initSharedPrefs" ..modifier = MethodModifier.async @@ -209,6 +204,12 @@ class AIAToDartCompiler { .statement, ]))); } + if (state.initStateStatements.isNotEmpty) { + b.methods.add(Method((m) => m + ..name = "initState" + ..body = Block.of( + [...state.initStateStatements, r("super.initState").statement]))); + } if (state.usesEnsureNum) { b.methods.add(Method((m) => m ..name = "ensureNum" diff --git a/lib/compiler/parse_component.dart b/lib/compiler/parse_component.dart index 3ccd4dd..a1b8279 100644 --- a/lib/compiler/parse_component.dart +++ b/lib/compiler/parse_component.dart @@ -355,6 +355,50 @@ class ComponentParser { } case "Clock": { + var timer = getPropertyDartName(componentName, "Timer"); + var timerEnabled = getPropertyDartName(componentName, "TimerEnabled"); + state.ensureFieldExists(timer); + + state.addInitStateStatement(wrapWithSetState(r(timerEnabled) + .assign(getComponentBoolProperty(component, "TimerEnabled") ?? + defaultValues[ + getPropertyDartName(componentName, "TimerEnabled")]!) + .statement)); + + // get TimerEnabled => Timer != null; + state.gettersSetters.add(Method((m) => m + ..type = MethodType.getter + ..name = timerEnabled + ..returns = r("bool") + ..body = r(timer).notEqualTo(literalNull).code + ..lambda = true)); + + state.gettersSetters.add(Method((m) => m + ..type = MethodType.setter + ..name = timerEnabled + ..requiredParameters.add(Parameter((p) => p..name = "value")) + ..body = Block.of([ + r(timer).nullSafeProperty("cancel")([]).statement, + r(timer) + .assign(r("value").conditional( + r("Timer.periodic", asyncPackage)([ + r("Duration")([], { + "milliseconds": getDartExpressionForProperty( + propsDartNames, + "TimerInterval", + getComponentNumProperty( + component, "TimerInterval"), + defaultValues) + }), + Method((m) => m + ..requiredParameters + .add(Parameter((p) => p..name = "_")) + ..body = safeCallEventHandler(getDartEventHandler( + state, componentName, "Timer"))).closure + ]), + literalNull)) + .statement + ]))); return null; } case "Player": diff --git a/lib/compiler/parsing_state.dart b/lib/compiler/parsing_state.dart index ae6c4fc..3fa2c74 100644 --- a/lib/compiler/parsing_state.dart +++ b/lib/compiler/parsing_state.dart @@ -26,6 +26,8 @@ class ParsingState { bool usesSafeStringAddition = false; bool usesEnsureNum = false; + List initStateStatements = []; + // First all blocks are processed. We put an entry with value null for // all component-attribute-variables they need. E.g. if the user has a // PhoneCall1.MakePhoneCall block, that puts a <"PhoneCall1_PhoneNumber",null> @@ -51,4 +53,8 @@ class ParsingState { void ensureFieldExists(String name) { fields.putIfAbsent(name, () => null); } + + void addInitStateStatement(Code statement) { + initStateStatements.add(statement); + } } diff --git a/lib/compiler/util_parser.dart b/lib/compiler/util_parser.dart index 76f5d6a..630311e 100644 --- a/lib/compiler/util_parser.dart +++ b/lib/compiler/util_parser.dart @@ -28,6 +28,7 @@ const lfalse = literalFalse; const materialPackage = "package:flutter/material.dart"; const mathPackage = "dart:math"; const convertPackage = "dart:convert"; +const asyncPackage = "dart:async"; // packages supported by Dart/Flutter team const httpPackage = "package:http/http.dart";