Skip to content

Commit

Permalink
Merge pull request #1073 from EnsembleUI/calendar-enhance
Browse files Browse the repository at this point in the history
added templated to rowspan
  • Loading branch information
snehmehta authored Dec 20, 2023
2 parents dee89c0 + c39758a commit 55f2283
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 3 deletions.
39 changes: 39 additions & 0 deletions assets/schema/ensemble_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -6103,6 +6103,45 @@
"$ref": "#/$defs/Widget",
"description": "If spans per row overflow based on spanPerRow than overflowWidget will render"
},
"span-template": {
"type": "object",
"required": [
"data",
"name",
"span"
],
"properties": {
"data": {
"type": "string",
"description": "Bind the rowspan list to the data e.g. myAPI.body.items"
},
"name": {
"type": "string",
"description": "Give this a name. This is the bindable data for each rowspan."
},
"span": {
"type": "object",
"required": [
"start",
"end",
"widget"
],
"properties": {
"start": {
"type": "string",
"description": "Starting date of the rowspan in ISO format"
},
"end": {
"type": "string",
"description": "Ending date of the rowspan in ISO format"
},
"widget": {
"$ref": "#/$defs/Widget"
}
}
}
}
},
"children": {
"type": "array",
"items": {
Expand Down
3 changes: 2 additions & 1 deletion lib/framework/action.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ class ShowDialogAction extends EnsembleAction {
options: Utils.getMap(payload['options']),
onDialogDismiss: payload['onDialogDismiss'] == null
? null
: EnsembleAction.fromYaml(Utils.maybeYamlMap(payload['onDialogDismiss'])),
: EnsembleAction.fromYaml(
Utils.maybeYamlMap(payload['onDialogDismiss'])),
);
}
}
Expand Down
4 changes: 3 additions & 1 deletion lib/util/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -316,13 +316,15 @@ class Utils {
Map? map = getMap(value);
return map != null ? YamlMap.wrap(map) : null;
}

//this is semantically different from the methods above as it is doesn't return null when value is not a map
static dynamic maybeYamlMap(dynamic value) {
if ( value is Map ) {
if (value is Map) {
return YamlMap.wrap(value);
}
return value;
}

static Color? getColor(dynamic value) {
if (value is String) {
switch (value) {
Expand Down
109 changes: 108 additions & 1 deletion lib/widget/calendar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import 'package:ensemble/framework/model.dart';
import 'package:ensemble/framework/scope.dart';
import 'package:ensemble/framework/view/data_scope_widget.dart';
import 'package:ensemble/framework/widget/widget.dart';
import 'package:ensemble/layout/templated.dart';
import 'package:ensemble/page_model.dart';
import 'package:ensemble/screen_controller.dart';
import 'package:ensemble/util/extensions.dart';
import 'package:ensemble/util/utils.dart';
import 'package:ensemble/widget/helpers/controllers.dart';
import 'package:ensemble_ts_interpreter/extensions.dart';
import 'package:ensemble_ts_interpreter/invokables/invokable.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
Expand Down Expand Up @@ -91,6 +94,12 @@ class EnsembleCalendar extends StatefulWidget
Utils.getInt(value['spanPerRow'], fallback: -1);
_controller.overlapOverflowBuilder = value['overflowWidget'];
_controller.topMargin = Utils.getInt(value['topMargin'], fallback: 0);

if (value['span-template'] is YamlMap ||
value['span-template'] is Map) {
setRowSpanItemTemplate(value['span-template']);
}

if (value['children'] is List) {
for (var span in value['children']) {
setRowSpan(span['span']);
Expand All @@ -106,6 +115,30 @@ class EnsembleCalendar extends StatefulWidget
};
}

void setRowSpanItemTemplate(dynamic rowSpanData) {
try {
if (rowSpanData is! Map ||
rowSpanData is! YamlMap ||
rowSpanData['span'] is! Map ||
rowSpanData['span'] is! YamlMap) {
return;
}

final rowSpanTemplate = RowSpanTemplate(
data: rowSpanData['data'],
name: rowSpanData['name'],
spanTemplate: SpanTemplate(
start: rowSpanData['span']['start'],
end: rowSpanData['span']['end'],
widget: rowSpanData['span']['widget'],
),
);
_controller.rowSpanTemplate = rowSpanTemplate;
} on Exception catch (_) {
//noop
}
}

setTooltip(value) {
_controller.tooltip = Utils.optionalString(value?['text']);
_controller.tooltipBackgroundColor =
Expand Down Expand Up @@ -386,6 +419,7 @@ class EnsembleCalendar extends StatefulWidget
}

class RowSpanConfig {
ScopeManager? scope;
DateTime? startDay;
DateTime? endDay;
dynamic widget;
Expand All @@ -398,6 +432,7 @@ class RowSpanConfig {
this.widget,
this.inputs,
required this.id,
this.scope,
});

bool get isValid => startDay != null && endDay != null;
Expand Down Expand Up @@ -457,6 +492,7 @@ class CalendarController extends WidgetController {
int topMargin = 0;
dynamic overlapOverflowBuilder;

RowSpanTemplate? rowSpanTemplate;
DateTime? selectedDate;
DateTime? disabledDate;

Expand Down Expand Up @@ -506,8 +542,10 @@ int getHashCode(DateTime key) {
return key.day * 1000000 + key.month * 10000 + key.year;
}

class CalendarState extends WidgetState<EnsembleCalendar> {
class CalendarState extends WidgetState<EnsembleCalendar>
with TemplatedWidgetState {
final CalendarFormat _calendarFormat = CalendarFormat.month;
ItemTemplate? itemTemplate;

@override
void initState() {
Expand All @@ -522,6 +560,51 @@ class CalendarState extends WidgetState<EnsembleCalendar> {
setState(() {});
}

@override
void didChangeDependencies() {
_registerRowSpanListener(context);
super.didChangeDependencies();
}

void _registerRowSpanListener(BuildContext context) {
if (widget.controller.rowSpanTemplate != null) {
registerItemTemplate(context, widget.controller.rowSpanTemplate!,
evaluateInitialValue: true, onDataChanged: (dataList) {
if (dataList is List) {
final configs = _builRowSpanConfigs(context, dataList);
widget._controller.rowSpans.value = configs;
setState(() {});
}
});
}
}

_builRowSpanConfigs(BuildContext context, List dataList) {
List<RowSpanConfig> rowSpanConfigs = [];

RowSpanTemplate? itemTemplate = widget.controller.rowSpanTemplate;
ScopeManager? myScope = DataScopeWidget.getScope(context);
if (myScope != null && itemTemplate != null) {
for (dynamic dataItem in dataList) {
ScopeManager dataScope = myScope.createChildScope();
dataScope.dataContext.addDataContextById(itemTemplate.name, dataItem);

rowSpanConfigs.add(
RowSpanConfig(
id: Utils.generateRandomId(6),
startDay: Utils.getDate(
dataScope.dataContext.eval(itemTemplate.spanTemplate.start)),
endDay: Utils.getDate(
dataScope.dataContext.eval(itemTemplate.spanTemplate.end)),
scope: dataScope,
widget: itemTemplate.spanTemplate.widget,
),
);
}
}
return rowSpanConfigs;
}

@override
void dispose() {
widget._controller.selectedDays.removeListener(listener);
Expand Down Expand Up @@ -683,6 +766,11 @@ class CalendarState extends WidgetState<EnsembleCalendar> {
final span = spans.value
.firstWhereOrNull((element) => element.id == range.id);
if (span != null) {
if (span.scope != null) {
final child =
span.scope?.buildWidgetFromDefinition(span.widget);
return child;
}
return widgetBuilder(
context,
span.widget,
Expand Down Expand Up @@ -918,3 +1006,22 @@ class _CalendarHeader extends StatelessWidget {
);
}
}

class RowSpanTemplate extends ItemTemplate {
RowSpanTemplate({
required String data,
required String name,
dynamic template,
required this.spanTemplate,
}) : super(data, name, template);

final SpanTemplate spanTemplate;
}

class SpanTemplate {
final String start;
final String end;
final dynamic widget;

SpanTemplate({required this.start, required this.end, this.widget});
}

0 comments on commit 55f2283

Please sign in to comment.