Skip to content

Commit a354250

Browse files
Merge pull request #39 from Codelessly/claude/affectionate-knuth-n1ntdj
codelessly_api 6.2.0: line chart node, API call handlers, runtime UI styling, URL paths
2 parents 562614b + c00c02f commit a354250

74 files changed

Lines changed: 2669 additions & 68 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CHANGELOG.md‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,45 @@
3030
as its tallest item (like a `Row` in an `IntrinsicHeight`) instead of a
3131
fixed `mainAxisExtent` or `childAspectRatio`. Default false, left out of
3232
the JSON.
33+
- `CornerRadius.fromJson` accepts a bare number (a circular radius on every
34+
corner), like `EdgeInsetsModel` does.
35+
- `ApiCallAction.onSuccess` and `onError`: actions to run after the call
36+
answers with a 2xx status, or after it fails or answers with another.
37+
- `ActionModel.childActions` and `selfAndNestedActions` walk actions nested
38+
in conditionals, for-each loops and API call handlers.
39+
- `NavigationAction.destinationId` defaults to `''`: a pop needs none, and
40+
for a pop it names where to go when there is nothing to go back to. It is
41+
still always written, for SDKs that require it.
42+
- `PaintModel.saturation` (default 1, left out of the JSON when 1): an image
43+
fill's color saturation; 0 is greyscale.
44+
- `CanvasProperties.path`: an optional URL path for a screen, such as
45+
`journal` or `guide/:id`, for links that open it with its parameters.
46+
- Styling for the runtime's own UI, all optional and left out of the JSON
47+
when unset, so saved designs keep their look:
48+
- `ShowToastAction`: `actionColor`, `showClose`, `closeColor`,
49+
`border` (`BorderSideModel`), `shadows` (drop shadow
50+
`Effect`s), `padding`, `maxWidth`, `messageStyle`, `actionStyle`,
51+
`iconSize`, and `bottomOffsets` (per `ScreenBreakpoint`, e.g.
52+
`{"mobile": 84}`, see `bottomOffsetFor`).
53+
- `ConfirmAction`: `border`, `shadows`, `titleStyle`, `messageStyle`,
54+
`buttonStyle`, `buttonRadius`, `buttonBorder`, `buttonShadows`,
55+
`confirmTextColor`, `cancelColor`, `cancelTextColor`.
56+
- `DropdownProperties`: `menuStyle` (`DropdownMenuStyleModel`: an anchored
57+
menu card's color, border, radius, shadows, offset, sizes, paddings,
58+
selected and hover row colors, selected text style and check mark) and
59+
`itemImage` (a URL or item template such as `${item.image}`),
60+
`itemImageSize`, `itemImageRadius`.
61+
- `TextStyleModel`: a partial text style (font family, weight, italic,
62+
size, line height, letter spacing, color).
63+
- `LineChartNode` (`lineChart`) and `LineChartProperties`: a data-driven
64+
line chart. The series, domain, bands, grid lines, area bands, reference
65+
lines, x ticks, markers and vertical lines are bound through `variables`
66+
(see the class docs for their JSON shapes); colors, insets, curve style,
67+
text styles and the scrub readout are properties.
68+
- `BaseNode.squeezable` (`"squeezable": true`, default `false` and left out
69+
of the JSON): a node that wraps its content (`SizeFit.shrinkWrap`) on its
70+
Row/Column's main axis may shrink below it when the Row/Column runs out of
71+
space, like `Flexible(fit: FlexFit.loose)` around a shrink-wrapped child.
3372

3473
### Fixes
3574

‎lib/src/api/models/action/action.dart‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,3 +326,27 @@ abstract interface class DataOperationInterface {
326326
/// Operation to be performed on the int/double type variable.
327327
abstract final NumberOperation numberOperation;
328328
}
329+
330+
/// Walks the actions nested in other actions.
331+
extension NestedActions on ActionModel {
332+
/// The actions this action runs itself: a conditional's branches, a
333+
/// for-each body, an API call's onSuccess/onError, a confirm's or toast's
334+
/// buttons and a cloud files action's follow-ups.
335+
List<ActionModel> get childActions => switch (this) {
336+
final ConditionalAction a => [...a.actions, ...a.elseActions],
337+
final ForEachAction a => a.actions,
338+
final ApiCallAction a => [...a.onSuccess, ...a.onError],
339+
final ConfirmAction a => [...a.actions, ...a.cancelActions],
340+
final ShowToastAction a => a.actions,
341+
final CloudFilesAction a => a.actions,
342+
_ => const [],
343+
};
344+
345+
/// This action followed by every action nested in it, depth first.
346+
Iterable<ActionModel> get selfAndNestedActions sync* {
347+
yield this;
348+
for (final ActionModel child in childActions) {
349+
yield* child.selfAndNestedActions;
350+
}
351+
}
352+
}

‎lib/src/api/models/action/api_call_action.dart‎

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ import 'package:json_annotation/json_annotation.dart';
22
import 'package:equatable/equatable.dart';
33

44
import '../../mixins.dart';
5-
import '../condition.dart';
6-
import 'action.dart';
7-
import '../../json_defaults.dart';
5+
import '../models.dart';
86

97
part 'api_call_action.g.dart';
108

119
/// Holds information about an API call action to perform on a user interaction.
10+
///
11+
/// The response is the chain's `${result}` afterwards (`${result.data}`,
12+
/// `${result.isError}`, `${result.statusCode}`, ...). [onSuccess] runs after a
13+
/// 2xx response and [onError] after any other response or a failed request.
14+
/// With [onError] actions, a failed request doesn't stop the chain.
1215
@JsonSerializable()
1316
class ApiCallAction extends ActionModel with Equatable, SerializableMixin {
1417
/// ID of the API to call.
@@ -17,25 +20,43 @@ class ApiCallAction extends ActionModel with Equatable, SerializableMixin {
1720
/// Parameters to pass to the API.
1821
final Map<String, String> parameters;
1922

23+
/// Actions to run, in order, after a successful (2xx) response.
24+
final List<ActionModel> onSuccess;
25+
26+
/// Actions to run, in order, after an error response or a failed request.
27+
final List<ActionModel> onError;
28+
2029
/// Creates an [ApiCallAction] with the given data.
2130
ApiCallAction({
2231
this.apiId,
2332
Map<String, String>? parameters,
33+
List<ActionModel>? onSuccess,
34+
List<ActionModel>? onError,
2435
super.nonBlocking,
2536
super.enabled,
2637
}) : parameters = parameters ?? {},
38+
onSuccess = onSuccess ?? [],
39+
onError = onError ?? [],
2740
super(type: ActionType.callApi);
2841

2942
@override
30-
List<Object?> get props => [apiId, parameters];
43+
List<Object?> get props => [apiId, parameters, onSuccess, onError];
3144

3245
/// Creates a copy of this [ApiCallAction] but with the given fields replaced
3346
/// with the new values.
34-
ApiCallAction copyWith({String? apiId, Map<String, String>? parameters}) =>
35-
ApiCallAction(
36-
apiId: apiId ?? this.apiId,
37-
parameters: parameters ?? this.parameters,
38-
);
47+
ApiCallAction copyWith({
48+
String? apiId,
49+
Map<String, String>? parameters,
50+
List<ActionModel>? onSuccess,
51+
List<ActionModel>? onError,
52+
}) => ApiCallAction(
53+
apiId: apiId ?? this.apiId,
54+
parameters: parameters ?? this.parameters,
55+
onSuccess: onSuccess ?? this.onSuccess,
56+
onError: onError ?? this.onError,
57+
nonBlocking: nonBlocking,
58+
enabled: enabled,
59+
);
3960

4061
/// Creates a new [ApiCallAction] from a JSON object.
4162
factory ApiCallAction.fromJson(Map json) => _$ApiCallActionFromJson(json);

‎lib/src/api/models/action/api_call_action.g.dart‎

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎lib/src/api/models/action/confirm_action.dart‎

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ part 'confirm_action.g.dart';
1111
///
1212
/// By default the dialog is built by the runtime and takes the app's look:
1313
/// its font, primary color and surface come from the layout that shows it.
14-
/// The optional color and radius fields override that look.
14+
/// The optional color, radius, border, shadow and text style fields
15+
/// override that look.
1516
///
1617
/// With a [dialogId] the dialog is that canvas instead, like
1718
/// [ShowDialogAction]. A button in it answers the dialog with a "Navigate
@@ -74,6 +75,44 @@ class ConfirmAction extends ActionModel with Equatable, SerializableMixin {
7475
/// Corner radius of the built-in dialog. Null follows the app's buttons.
7576
final double? cornerRadius;
7677

78+
/// Outline of the built-in dialog. Null draws none.
79+
final BorderSideModel? border;
80+
81+
/// Drop shadows of the built-in dialog, e.g. a hard offset shadow (radius
82+
/// 0). Null keeps the default elevation shadow; an empty list draws none.
83+
final List<Effect>? shadows;
84+
85+
/// Font, size and color of the title. Unset values follow the app.
86+
final TextStyleModel? titleStyle;
87+
88+
/// Font, size and color of the message. Unset values follow the app.
89+
final TextStyleModel? messageStyle;
90+
91+
/// Font, size and color of both buttons' labels. Unset values follow the
92+
/// app; the label colors come from [confirmTextColor] and
93+
/// [cancelTextColor] when this sets none.
94+
final TextStyleModel? buttonStyle;
95+
96+
/// Corner radius of the buttons. Null follows the app's buttons.
97+
final double? buttonRadius;
98+
99+
/// Outline of both buttons. Null draws none.
100+
final BorderSideModel? buttonBorder;
101+
102+
/// Drop shadows of the confirm button, and of the cancel button when it
103+
/// has a [cancelColor]. Null draws none.
104+
final List<Effect>? buttonShadows;
105+
106+
/// Label color of the confirm button. Null picks one that reads on its
107+
/// fill.
108+
final ColorRGBA? confirmTextColor;
109+
110+
/// Fill of the cancel button. Null leaves it a text button.
111+
final ColorRGBA? cancelColor;
112+
113+
/// Label color of the cancel button. Null uses the dialog's text color.
114+
final ColorRGBA? cancelTextColor;
115+
77116
/// How the dialog is presented: centered, as a bottom sheet or as a side
78117
/// sheet. See [ShowDialogAction.presentation].
79118
@JsonKey(unknownEnumValue: DialogPresentation.dialog)
@@ -127,6 +166,17 @@ class ConfirmAction extends ActionModel with Equatable, SerializableMixin {
127166
this.textColor,
128167
this.confirmColor,
129168
this.cornerRadius,
169+
this.border,
170+
this.shadows,
171+
this.titleStyle,
172+
this.messageStyle,
173+
this.buttonStyle,
174+
this.buttonRadius,
175+
this.buttonBorder,
176+
this.buttonShadows,
177+
this.confirmTextColor,
178+
this.cancelColor,
179+
this.cancelTextColor,
130180
this.presentation = DialogPresentation.dialog,
131181
this.sheetWidth,
132182
this.maxHeightFactor = 1,
@@ -161,6 +211,28 @@ class ConfirmAction extends ActionModel with Equatable, SerializableMixin {
161211
bool clearConfirmColor = false,
162212
double? cornerRadius,
163213
bool clearCornerRadius = false,
214+
BorderSideModel? border,
215+
bool clearBorder = false,
216+
List<Effect>? shadows,
217+
bool clearShadows = false,
218+
TextStyleModel? titleStyle,
219+
bool clearTitleStyle = false,
220+
TextStyleModel? messageStyle,
221+
bool clearMessageStyle = false,
222+
TextStyleModel? buttonStyle,
223+
bool clearButtonStyle = false,
224+
double? buttonRadius,
225+
bool clearButtonRadius = false,
226+
BorderSideModel? buttonBorder,
227+
bool clearButtonBorder = false,
228+
List<Effect>? buttonShadows,
229+
bool clearButtonShadows = false,
230+
ColorRGBA? confirmTextColor,
231+
bool clearConfirmTextColor = false,
232+
ColorRGBA? cancelColor,
233+
bool clearCancelColor = false,
234+
ColorRGBA? cancelTextColor,
235+
bool clearCancelTextColor = false,
164236
DialogPresentation? presentation,
165237
double? sheetWidth,
166238
bool clearSheetWidth = false,
@@ -184,6 +256,23 @@ class ConfirmAction extends ActionModel with Equatable, SerializableMixin {
184256
textColor: clearTextColor ? null : textColor ?? this.textColor,
185257
confirmColor: clearConfirmColor ? null : confirmColor ?? this.confirmColor,
186258
cornerRadius: clearCornerRadius ? null : cornerRadius ?? this.cornerRadius,
259+
border: clearBorder ? null : border ?? this.border,
260+
shadows: clearShadows ? null : shadows ?? this.shadows,
261+
titleStyle: clearTitleStyle ? null : titleStyle ?? this.titleStyle,
262+
messageStyle: clearMessageStyle ? null : messageStyle ?? this.messageStyle,
263+
buttonStyle: clearButtonStyle ? null : buttonStyle ?? this.buttonStyle,
264+
buttonRadius: clearButtonRadius ? null : buttonRadius ?? this.buttonRadius,
265+
buttonBorder: clearButtonBorder ? null : buttonBorder ?? this.buttonBorder,
266+
buttonShadows: clearButtonShadows
267+
? null
268+
: buttonShadows ?? this.buttonShadows,
269+
confirmTextColor: clearConfirmTextColor
270+
? null
271+
: confirmTextColor ?? this.confirmTextColor,
272+
cancelColor: clearCancelColor ? null : cancelColor ?? this.cancelColor,
273+
cancelTextColor: clearCancelTextColor
274+
? null
275+
: cancelTextColor ?? this.cancelTextColor,
187276
presentation: presentation ?? this.presentation,
188277
sheetWidth: clearSheetWidth ? null : sheetWidth ?? this.sheetWidth,
189278
maxHeightFactor: maxHeightFactor ?? this.maxHeightFactor,
@@ -209,6 +298,17 @@ class ConfirmAction extends ActionModel with Equatable, SerializableMixin {
209298
textColor,
210299
confirmColor,
211300
cornerRadius,
301+
border,
302+
shadows,
303+
titleStyle,
304+
messageStyle,
305+
buttonStyle,
306+
buttonRadius,
307+
buttonBorder,
308+
buttonShadows,
309+
confirmTextColor,
310+
cancelColor,
311+
cancelTextColor,
212312
presentation,
213313
sheetWidth,
214314
maxHeightFactor,

‎lib/src/api/models/action/confirm_action.g.dart‎

Lines changed: 42 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎lib/src/api/models/action/navigation_action.dart‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,10 @@ class NavigationAction extends ActionModel with Equatable, SerializableMixin {
3838
/// Defines how the navigation should be performed.
3939
final NavigationType navigationType;
4040

41-
/// Destination canvas node's ID.
41+
/// Destination canvas node's ID. For a pop it's optional: where to go
42+
/// instead when there is no previous screen to go back to.
43+
// Always written: SDKs before the '' default require the key.
44+
@JsonLegacyDefault(null)
4245
final String destinationId;
4346

4447
/// Parameters to pass to the destination page.
@@ -47,7 +50,7 @@ class NavigationAction extends ActionModel with Equatable, SerializableMixin {
4750
/// Creates a new [NavigationAction].
4851
NavigationAction({
4952
this.navigationType = NavigationType.push,
50-
required this.destinationId,
53+
this.destinationId = '',
5154
Map<String, dynamic>? params,
5255
super.nonBlocking,
5356
super.enabled,

0 commit comments

Comments
 (0)