diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c3f1408..a0f1e268 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -## [0.65.3](https://github.com/georgejecook/maestro-roku/compare/0.65.2...0.65.3) +## [0.65.4](https://github.com/georgejecook/maestro-roku/compare/0.65.3...0.65.4) + +### Merged + +- Fix/delayed task manager does not cancel tasks [`#376`](https://github.com/georgejecook/maestro-roku/pull/376) + +### Commits + +- fixes issues that prevented delayed task manager from removing a pending task [`a4b604e`](https://github.com/georgejecook/maestro-roku/commit/a4b604e9c139608399c13d42cd572ebb5d17b420) +- bump [`dad3a84`](https://github.com/georgejecook/maestro-roku/commit/dad3a843e5a01b7e6540b2bad79cb4c93d2016b6) + +## [0.65.3](https://github.com/georgejecook/maestro-roku/compare/0.65.2...0.65.3) - 2023-05-11 ### Merged diff --git a/README.md b/README.md index 1e322091..a13893db 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ try { if (filePath.endsWith('Task.xml')) { let text = fs.readFileSync(filePath, 'utf8'); - let r = /\/roku_modules\/undefined/gim; + let r = /\/roku_modules\/rokucommunity_bslib/gim; text = text.replace(r, '/roku_modules/maestro'); fs.writeFileSync(filePath, text); } diff --git a/package.json b/package.json index 30a2b9f4..ddeff29f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "maestro-roku", - "version": "0.65.3", + "version": "0.65.4", "description": "A development platform for building roku channels in brighterscript", "directories": { "doc": "docs" diff --git a/src/source/core/BaseClass.bs b/src/source/core/BaseClass.bs index ed1efb2f..0725ca99 100644 --- a/src/source/core/BaseClass.bs +++ b/src/source/core/BaseClass.bs @@ -72,6 +72,10 @@ namespace mc return mc.createSGNode(nodeType, parent, id, args, callInitialize, mTarget) end function + function createFragment(fragmentJson as dynamic, targetNode = invalid as mc.types.node, dataBindingContext = invalid as dynamic, assignViewsToM = false as boolean) + return mv.createFragment(fragmentJson, targetNode, dataBindingContext, assignViewsToM) + end function + protected function createViewsFromStyleJson(childrenJson as mc.types.array, targetNode = invalid as mc.types.node, assignViewsToM = true as boolean, mTarget = invalid as mc.types.assocarray) if mTarget = invalid mTarget = m @@ -81,7 +85,7 @@ namespace mc end if 'FIXME - maestro-bsc needs to understand overloaded namespaces 'bs:disable-next-line - mv.createViewsFromStyleJson(childrenJson, targetNode, assignViewsToM, mTarget, true) + return mv.createViewsFromStyleJson(childrenJson, targetNode, assignViewsToM, mTarget, true) end function protected function updateViewsWithStyleJson(json as dynamic, mTarget = invalid as mc.types.assocarray) diff --git a/src/source/ml/cells/BaseCell.bs b/src/source/ml/cells/BaseCell.bs index a8ae588d..6f130cdd 100644 --- a/src/source/ml/cells/BaseCell.bs +++ b/src/source/ml/cells/BaseCell.bs @@ -110,7 +110,7 @@ namespace ml end if 'FIXME - maestro-bsc needs to understand overloaded namespaces 'bs:disable-next-line - mv.createViewsFromStyleJson(childrenJson, targetNode, assignViewsToM, mTarget) + return mv.createViewsFromStyleJson(childrenJson, targetNode, assignViewsToM, mTarget) end function protected function updateViewsWithStyleJson(json as dynamic, mTarget = invalid as mc.types.assocarray) diff --git a/src/source/mx/BaseViewModel.bs b/src/source/mx/BaseViewModel.bs index b362106c..ecf3f27f 100644 --- a/src/source/mx/BaseViewModel.bs +++ b/src/source/mx/BaseViewModel.bs @@ -130,7 +130,7 @@ namespace mx end if 'FIXME - maestro-bsc needs to understand overloaded namespaces 'bs:disable-next-line - mv.createViewsFromStyleJson(childrenJson, targetNode, assignViewsToM, mTarget) + return mv.createViewsFromStyleJson(childrenJson, targetNode, assignViewsToM, mTarget) end function protected function updateViewsWithStyleJson(json as dynamic, mTarget = invalid as mc.types.assocarray) diff --git a/src/source/view/BaseCell.bs b/src/source/view/BaseCell.bs index 25b8e65e..c4f631aa 100644 --- a/src/source/view/BaseCell.bs +++ b/src/source/view/BaseCell.bs @@ -114,13 +114,17 @@ namespace mv.cells protected function _createView() end function + function createFragment(fragmentJson as dynamic, targetNode = invalid as mc.types.node, dataBindingContext = invalid as dynamic, assignViewsToM = false as boolean) + return mv.createFragment(fragmentJson, targetNode, dataBindingContext, assignViewsToM) + end function + protected function createViewsFromStyleJson(childrenJson as mc.types.array, targetNode = invalid as mc.types.node, assignViewsToM = true as boolean, mTarget = invalid as mc.types.assocarray) if mTarget = invalid mTarget = m end if 'FIXME - maestro-bsc needs to understand overloaded namespaces 'bs:disable-next-line - mv.createViewsFromStyleJson(childrenJson, targetNode, assignViewsToM, mTarget) + return mv.createViewsFromStyleJson(childrenJson, targetNode, assignViewsToM, mTarget) end function protected function updateViewsWithStyleJson(json as dynamic, mTarget = invalid as mc.types.assocarray) diff --git a/src/source/view/ViewUtils.bs b/src/source/view/ViewUtils.bs index ef7a7ec5..b0a1f889 100644 --- a/src/source/view/ViewUtils.bs +++ b/src/source/view/ViewUtils.bs @@ -53,13 +53,98 @@ namespace mv end if end function - function createViewsFromStyleJson(childrenJson as mc.types.array, targetNode = invalid as mc.types.node, assignViewsToM = true as boolean, mTarget = invalid as mc.types.assocarray, updateDataMappedIds = false as boolean) + function createFragment(fragmentJson as dynamic, targetNode = invalid as mc.types.node, dataBindingContext = invalid as dynamic, assignViewsToM = false as boolean) + mTarget = m + if targetNode = invalid + targetNode = m.top + end if + firstView = invalid + + if not mc.isArray(fragmentJson) and mc.isAACompatible(fragmentJson) + fragmentJson = [fragmentJson] + end if + + if mc.isArray(fragmentJson) + if type(targetNode) = "roSGNode" + for i = 0 to fragmentJson.count() - 1 + nodeJson = fragmentJson[i] + + nodeType = nodeJson._type + if nodeType <> invalid + children = nodeJson._children + id = nodeJson.id + _type = nodeJson._type + _children = nodeJson._children + _initializeAfterCreatingChildren = nodeJson._initializeAfterCreatingChildren = true + nodeJson.delete("id") + nodeJson.delete("_type") + nodeJson.delete("_children") + if dataBindingContext <> invalid + bindingFields = {} + for each field in nodeJson + value = nodeJson[field] + if mc.isString(value) and value.instr("${") = 0 + bindingFields[field] = value + if value.instr("[") <> -1 + value = value.replace("[", ".") + value = value.replace("]", "") + end if + nodeJson[field] = mc.getPath(dataBindingContext, value.mid(2, len(value) - 3)) + end if + end for + end if + view = mc.createSGNode(nodeType, targetNode, id, nodeJson, not _initializeAfterCreatingChildren, mTarget) + nodeJson.id = id + nodeJson._type = _type + nodeJson._children = _children + 'bs:disable-next-line + if dataBindingContext <> invalid and bindingFields.count() > 0 + 'bs:disable-next-line + nodeJson.append(bindingFields) + end if + if view <> invalid + if firstView = invalid + firstView = view + end if + + if children <> invalid + mv.createFragment(children, view, dataBindingContext, assignViewsToM) + end if + if assignViewsToM and id <> invalid + if mTarget[id] <> invalid + mc.private.logWarn("CREATE VIEW FROM STYLE JSON: Target view already had a view set for id", id) + end if + mTarget[id] = view + end if + else + mc.private.logError("CREATE VIEW FROM STYLE JSON: Could not create view ", id, "with type", nodeType) + end if + if _initializeAfterCreatingChildren + view@._initialize() + end if + else + mc.private.logError("CREATE VIEW FROM STYLE JSON: Could not create view ", nodeJson.id, "no _type specified") + end if + end for + else + mc.private.logError("CREATE VIEW FROM STYLE JSON: Could not create views from style Json: Target node was invalid") + end if + else + mc.private.logError("CREATE VIEW FROM STYLE JSON: Could not create view in targetNode", mc.dv(targetNode), "json was invalid") + end if + + return firstView + end function + + function createViewsFromStyleJson(childrenJson as mc.types.array, targetNode = invalid as mc.types.node, assignViewsToM = true as boolean, mTarget = invalid as mc.types.assocarray, updateDataMappedIds = false as boolean, dataBindingContext = invalid as dynamic) if mTarget = invalid mTarget = m end if if targetNode = invalid targetNode = m.top end if + firstView = invalid + 'TODO - convert this to use update api, for speed. if mc.isArray(childrenJson) if type(targetNode) = "roSGNode" @@ -83,6 +168,9 @@ namespace mv nodeJson._type = _type nodeJson._children = _children if view <> invalid + if firstView = invalid + firstView = view + end if if _dataMap <> invalid mc.setOrAddNodeField(view, "_dataMap", _dataMap) if updateDataMappedIds @@ -93,7 +181,7 @@ namespace mv end if end if if children <> invalid - mv.createViewsFromStyleJson(children, view, assignViewsToM, mTarget, updateDataMappedIds) + mv.createViewsFromStyleJson(children, view, assignViewsToM, mTarget, updateDataMappedIds, dataBindingContext) end if if assignViewsToM and id <> invalid if mTarget[id] <> invalid @@ -117,6 +205,8 @@ namespace mv else mc.private.logError("CREATE VIEW FROM STYLE JSON: Could not create view in targetNode", mc.dv(targetNode), "json was invalid") end if + + return firstView end function ' update views, which have fields mapped to the node ids with json of the form of: diff --git a/src/source/view/ViewUtils.spec.bs b/src/source/view/ViewUtils.spec.bs index 0ebfdefa..5ccfa07a 100644 --- a/src/source/view/ViewUtils.spec.bs +++ b/src/source/view/ViewUtils.spec.bs @@ -953,5 +953,234 @@ namespace tests m.assertEqual(label.text, "text_replaced") end function + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + @describe("createFragment") + '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + @it("creates a view fragment, with no bindings") + function _() + json = { + "_type": "Rectangle" + "id": "v1" + "height": 1.0 + } + view = mv.createFragment(json) + + m.assertSubType(view, "Rectangle") + m.assertEqual(view.id, "v1") + m.assertEqual(view.height, 1.0) + end function + + @it("creates a view fragment, with children, with no bindings") + function _() + json = { + "_type": "Rectangle" + "id": "v1" + "height": 1.0 + "_children": [ + { + "_type": "mv_Label" + "id": "v2" + "text": "a" + } + { + "_type": "mv_Label" + "id": "v3" + "text": "b" + "_children": [ + { + "_type": "mv_Label" + "id": "v4" + "text": "c" + } + ] + } + ] + } + view = mv.createFragment(json) + + m.assertSubType(view, "Rectangle") + m.assertEqual(view.id, "v1") + m.assertEqual(view.height, 1.0) + + child1 = view.getChild(0) + + m.assertSubType(child1, "mv_Label") + m.assertEqual(child1.id, "v2") + m.assertEqual(child1.text, "a") + + child2 = view.getChild(1) + + m.assertSubType(child2, "mv_Label") + m.assertEqual(child2.id, "v3") + m.assertEqual(child2.text, "b") + + child2_1 = child2.getChild(0) + + m.assertSubType(child2_1, "mv_Label") + m.assertEqual(child2_1.id, "v4") + m.assertEqual(child2_1.text, "c") + end function + + @it("creates a view fragment, with children, with bindings") + function _() + json = { + "_type": "Rectangle" + "id": "v1" + "height": "${json.height}" + "_children": [ + { + "_type": "mv_Label" + "id": "v2" + "text": "${json.item1.a}" + } + { + "_type": "mv_Label" + "id": "v3" + "text": "${json.item2.subItem.b}" + "_children": [ + { + "_type": "mv_Label" + "id": "v4" + "text": "${json.others[1]}" + } + ] + } + ] + } + + data = { + json: { + "height": 200.0 + item1: { + "a": "first" + } + item2: { + subItem: { + "b": "second" + } + } + others: [ + "third", "fourth" + ] + } + } + view = mv.createFragment(json, invalid, data) + + m.assertSubType(view, "Rectangle") + m.assertEqual(view.id, "v1") + m.assertEqual(view.height, 200.0) + + child1 = view.getChild(0) + + m.assertSubType(child1, "mv_Label") + m.assertEqual(child1.id, "v2") + m.assertEqual(child1.text, "first") + + child2 = view.getChild(1) + + m.assertSubType(child2, "mv_Label") + m.assertEqual(child2.id, "v3") + m.assertEqual(child2.text, "second") + + child2_1 = child2.getChild(0) + + m.assertSubType(child2_1, "mv_Label") + m.assertEqual(child2_1.id, "v4") + m.assertEqual(child2_1.text, "fourth") + end function + + @it("creates a view fragment, with children, with bindings, and works multiple times") + function _() + json = { + "_type": "Rectangle" + "id": "v1" + "height": "${json.height}" + "_children": [ + { + "_type": "mv_Label" + "id": "v2" + "text": "${json.item1.a}" + } + { + "_type": "mv_Label" + "id": "v3" + "text": "${json.item2.subItem.b}" + "_children": [ + { + "_type": "mv_Label" + "id": "v4" + "text": "${json.others[1]}" + } + ] + } + ] + } + + data = { + json: { + "height": 200.0 + item1: { + "a": "first" + } + item2: { + subItem: { + "b": "second" + } + } + others: [ + "third", "fourth" + ] + } + } + view = mv.createFragment(json, invalid, data) + + m.assertSubType(view, "Rectangle") + m.assertEqual(view.id, "v1") + m.assertEqual(view.height, 200.0) + + child1 = view.getChild(0) + + m.assertSubType(child1, "mv_Label") + m.assertEqual(child1.id, "v2") + m.assertEqual(child1.text, "first") + + child2 = view.getChild(1) + + m.assertSubType(child2, "mv_Label") + m.assertEqual(child2.id, "v3") + m.assertEqual(child2.text, "second") + + child2_1 = child2.getChild(0) + + m.assertSubType(child2_1, "mv_Label") + m.assertEqual(child2_1.id, "v4") + m.assertEqual(child2_1.text, "fourth") + + view = mv.createFragment(json, invalid, data) + + m.assertSubType(view, "Rectangle") + m.assertEqual(view.id, "v1") + m.assertEqual(view.height, 200.0) + + child1 = view.getChild(0) + + m.assertSubType(child1, "mv_Label") + m.assertEqual(child1.id, "v2") + m.assertEqual(child1.text, "first") + + child2 = view.getChild(1) + + m.assertSubType(child2, "mv_Label") + m.assertEqual(child2.id, "v3") + m.assertEqual(child2.text, "second") + + child2_1 = child2.getChild(0) + + m.assertSubType(child2_1, "mv_Label") + m.assertEqual(child2_1.id, "v4") + m.assertEqual(child2_1.text, "fourth") + end function + end class end namespace