Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2ffdfe3
Migrate to codelessly_api 5 and upstream JSON codegen
claude Oct 13, 2026
92dfbca
Render the new AppBar and TabBar properties from codelessly_api 5
claude Oct 13, 2026
8b583f1
Replace deprecated Flutter APIs and clear analyzer findings
claude Oct 13, 2026
dbd017f
Render the remaining API 5 parameters and fix two runtime errors
claude Oct 13, 2026
0846530
Render ExpansionTile shape and collapsedShape
claude Oct 13, 2026
cc07bbe
Render PageView allowImplicitScrolling and Text textScaleFactor
claude Oct 13, 2026
b2ef500
Use the web webview implementation under WebAssembly
claude Oct 13, 2026
ff8cafa
Fix crashes and hangs in auth, startup, data streams and widgets
claude Oct 13, 2026
4832bfd
Render Material Symbols and Cupertino icons
claude Oct 13, 2026
86a8928
Let apps opt layouts into their theme and text scaling
claude Oct 13, 2026
d475ab1
Reload web views on data changes and route output through the logger
claude Oct 13, 2026
66541b4
Harden link taps and disposal; drop unused dependencies
claude Oct 13, 2026
5240fd3
Degrade failed SVG loads and add transformer smoke tests
claude Oct 13, 2026
423a600
Prepare 7.0.0: changelog, README fixes and pubspec metadata
claude Oct 13, 2026
793609a
Add CI: analyze, test and a WebAssembly build of the example
claude Oct 13, 2026
445edc5
Resolve codelessly_api from its master branch
claude Oct 13, 2026
d3801c4
Depend on codelessly_api 5.0.0 from pub.dev
claude Oct 13, 2026
6089b31
Add regression tests for the auth and data-layer fixes
claude Oct 13, 2026
3707d68
Await app functions in Call Function actions
claude Oct 13, 2026
2ddb3d5
Keep native web view plugins out of web builds of embedded video
claude Oct 13, 2026
3ed8bc4
Apply the current Dart formatter and check formatting in CI
claude Oct 13, 2026
04fce8f
Note WebAssembly compatibility in the changelog
claude Oct 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: CI

on:
push:
pull_request:

jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v7
- uses: subosito/flutter-action@v2
with:
channel: stable
flutter-version: 3.47.7
cache: true
- run: flutter pub get
- run: dart format --set-exit-if-changed --output=none lib test tool
- run: flutter analyze
- run: flutter test
- name: Build the example for the web (WebAssembly)
working-directory: example
run: flutter build web --wasm
74 changes: 74 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,77 @@
## 7.0.0

### Breaking changes

- Require Dart 3.13 and Flutter 3.47.
- Migrate to codelessly_api 5.0.0, json_annotation and json_serializable,
replacing the forked codegen that no longer builds on current Dart.
- Remove the `staggerDownloadQueue` argument of `CodelesslyConfig.copyWith`,
which had no effect, and the font parser's command-line `main()`.

### New

- Material Symbols render, including fill, weight, grade and optical size.
Cupertino icons render from the cupertino_icons font. Two-tone Material
icons load again.
- `DebugLogger` and `ErrorLogger` are exported; `DataManager`'s public
constructor already required an `ErrorLogger`.
- `AuthManager` takes a `claimsPropagationTimeout`.
- `CodelesslyConfig.useHostTheme` and `maxTextScaleFactor` let layouts
follow the app's theme and, within a bound, the system text size.
- Web views reload when their bound URL changes.
- Placeholder nodes deserialize (codelessly_api 5).

### Fixes

- Authentication no longer hangs when project claims never arrive or the
token refresh fails, and works on Windows (it decoded the wrong string).
- Initialization no longer hangs when the publish model stream errors.
- Cloud database variables keep one Firestore listener each instead of
accumulating them, so earlier queries can't overwrite newer results.
- Failed onLoad API calls and non-blocking actions are reported instead of
surfacing as uncaught errors.
- Call Function actions now wait for the app's function (unless marked
non-blocking) and report its errors; before, the next action started
immediately and async errors went uncaught.
- `CodelesslyWidget` handles removing an explicit context or controller,
and a missing breakpoint, without throwing.
- PageView, TabBar and Accordion edge cases that threw are fixed;
Accordion respects `isExpanded` and `enabled`, and TabBar `showDivider`.
- Malformed links and failed SVG downloads no longer throw.
- The web view works in WebAssembly builds, and embedded video no longer
pulls native web view plugins into web builds; the package is fully
WebAssembly-compatible.
- The auth token and auth response body are no longer logged, and library
code logs through `DebugLogger` instead of `print`.

### Other changes

- Require Dart 3.13 and Flutter 3.47.
- Migrate to codelessly_api 5.0.0, json_annotation and json_serializable,
replacing the forked codegen that no longer builds on current Dart.
- Upgrade dependencies, including Firebase, google_fonts, equatable 3 and
json_path.
- Render the new API values: FilledButton and FilledButton.tonal buttons,
RoundedSuperellipseBorder shapes, TextAlign start/end, the
`endContained` FAB location, `webSearch`/`twitter` keyboards, and the
`onUnfocus`/`onUserInteractionIfError` autovalidate modes.
- Render the new AppBar `foregroundColor`/`scrolledUnderElevation` and
TabBar `tabAlignment`/`dividerHeight` properties.
- Render the other parameters added in codelessly_api 5: Radio side,
inner radius and background, Slider value indicator modes, secondary
track and padding, ListTile minimum height and title alignment,
CircularProgressIndicator stroke alignment and track gap, ExpansionTile
trailing icon visibility and shapes, Text soft wrapping and scaling, and
PageView implicit scrolling.
- Render the gapped slider track and the drop and rounded rectangle value
indicators; these previously fell back to other shapes.
- Replace deprecated Flutter APIs: scrollCacheExtent, RadioGroup,
ShowValueIndicator.onDrag, Switch activeThumbColor and the new Color
component accessors.
- Fix a LateInitializationError when a node widget is built without a
CodelesslyContext above it.
- Fix cache writes whose failures escaped the error handler.

## 6.2.0

- Create dynamic settings architecture.
Expand Down
52 changes: 29 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
![Codelessly Logo](packages/Codelessly-Logo-Text.png)
![Codelessly Logo](https://raw.githubusercontent.com/Codelessly/CodelesslySDK/master/packages/Codelessly-Logo-Text.png)

# Codelessly CloudUI™ SDK

[![Pub release](https://img.shields.io/pub/v/codelessly_sdk.svg?style=flat-square)](https://pub.dev/packages/codelessly_sdk) [![GitHub Release Date](https://img.shields.io/github/release-date/Codelessly/CodelesslySDK.svg?style=flat-square)](https://github.com/Codelessly/CodelesslySDK) [![GitHub issues](https://img.shields.io/github/issues/Codelessly/CodelesslySDK.svg?style=flat-square)](https://github.com/Codelessly/CodelesslySDK/issues) [![GitHub top language](https://img.shields.io/github/languages/top/Codelessly/CodelesslySDK.svg?style=flat-square)](https://github.com/Codelessly/CodelesslySDK)

> ### Dynamic UI and real-time updates for Flutter apps

![Codelessly Publish UI](packages/Codelessly-Cover.png)
![Codelessly Publish UI](https://raw.githubusercontent.com/Codelessly/CodelesslySDK/master/packages/Codelessly-Cover.png)

Supercharge your Flutter apps with dynamic UI and real-time updates. Build and publish UI without code!

Expand Down Expand Up @@ -60,10 +60,10 @@ CodelesslyWidget(
**How to obtain a Layout ID**

1. In the Codelessly Editor, select the **canvas** of your layout.
2. Press the **Preview Icon** in the toolbar. ![CloudUI Preview Icon](packages/preview_icon.png)
2. Press the **Preview Icon** in the toolbar. ![CloudUI Preview Icon](https://raw.githubusercontent.com/Codelessly/CodelesslySDK/master/packages/preview_icon.png)
3. Copy the **layoutID**.

![Codelessly Widget Code](packages/codelessly_widget_code.png)
![Codelessly Widget Code](https://raw.githubusercontent.com/Codelessly/CodelesslySDK/master/packages/codelessly_widget_code.png)

### Complete Example

Expand All @@ -73,7 +73,7 @@ Here is a complete example:
import 'package:codelessly_sdk/codelessly_sdk.dart';

class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
const MyApp({super.key});

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -114,7 +114,7 @@ CodelesslyWidget(

Use the `${}` templating syntax in input fields to link data from the Codelessly editor to layouts as shown below.

![Data](packages/ui_with_data_linking.png)
![Data](https://raw.githubusercontent.com/Codelessly/CodelesslySDK/master/packages/ui_with_data_linking.png)

To link the title of a text widget to the `title` variable in the Codelessly editor, put `${title}` in the text widget’s
text field.
Expand Down Expand Up @@ -144,7 +144,7 @@ the `data` is updated.

This how it looks with populated data:

![Data](packages/ui_with_populated_data.png)
![Data](https://raw.githubusercontent.com/Codelessly/CodelesslySDK/master/packages/ui_with_populated_data.png)

## Functions

Expand All @@ -156,7 +156,7 @@ CodelesslyWidget(
functions: {
'functionName': (context, reference, params) {
// TODO: Implement your function here
}),
},
},
),
```
Expand All @@ -165,7 +165,7 @@ CodelesslyWidget(

Here, we tell the button to call the native `onNextButtonClicked` function when pressed.

![Defining call function action](packages/defining_call_function_action.png)
![Defining call function action](https://raw.githubusercontent.com/Codelessly/CodelesslySDK/master/packages/defining_call_function_action.png)

In the Codelessly Editor, you can easily add an Action to a widget. Use the `Call Function` action to invoke
`onNextButtonClicked`.
Expand All @@ -187,22 +187,22 @@ to all `CodelesslyWidget`s.

```dart
CodelesslyWidget(
layoutID: '0R0Qe7wgeAJMnj3MGW4l',
isPreview: kDebugMode,
layoutID: LAYOUT_ID,
publishSource: kDebugMode ? PublishSource.preview : PublishSource.publish,
config: CodelesslyConfig(
authToken: 'LCVyNTxyLCVxQXh3WDc5MFowLjApQXJfWyNdSnlAQjphLyN1',
authToken: AUTH_TOKEN,
),
)
```

- `layoutID`: The ID of the published canvas. The ID can be found in Quick Preview or under
`Publish > Settings > Published Layouts`.

![Codelessly Published Layout ID](packages/codelessly_published_layout_id.png)
![Codelessly Published Layout ID](https://raw.githubusercontent.com/Codelessly/CodelesslySDK/master/packages/codelessly_published_layout_id.png)

- `isPreview`: Whether the layout is in preview or production mode. Preview mode is meant for debugging the layout and
syncs with the changes made in the editor. Widgets in production mode are only updated when published using the
Publish button.
- `publishSource`: Whether the layout loads from preview or production. Preview mode is meant for debugging the layout
and syncs with the changes made in the editor. Widgets in production mode are only updated when published using the
Publish button. Defaults to the global config's setting.
- `config`: An optional `CodelesslyConfig` that holds the information required to authenticate your layout from the
server.

Expand All @@ -211,7 +211,8 @@ lets you embed layouts from other projects with different auth tokens.

## Environment Configuration

The CodelesslyWidget supports **Preview** and **Published** environments via the `isPreview` boolean.
The CodelesslyWidget supports **Preview** and **Published** environments, set globally with `isPreview` or per widget
with `publishSource`.

```dart
// Global config.
Expand All @@ -223,7 +224,8 @@ Codelessly.instance.initialize(

// Widget level. Overrides global settings for this widget.
CodelesslyWidget(
isPreview: true
layoutID: LAYOUT_ID,
publishSource: PublishSource.preview,
);
```

Expand Down Expand Up @@ -275,7 +277,7 @@ Codelessly.instance.initialize(
authToken: AUTH_TOKEN,
isPreview: kDebugMode,
preload: true,
automaticallyCollectCrashReports: true,
automaticallySendCrashReports: true,
),
);
```
Expand All @@ -285,8 +287,12 @@ CodelesslyConfig supports the following configuration capabilities.
* `isPreview`: Global enable or disable preview-mode setting.
* `preload`: Preload layouts to improve performance. When layouts are preloaded, they load instantly and behave like
local widgets. `true` by default.
* `automaticallyCollectCrashReports`: Report SDK crashes to Codelessly. `true` by default. You can optionally disable
this behavior.
* `automaticallySendCrashReports`: Report SDK crashes to Codelessly. `false` by default. Only the error and stack trace
are sent, no device data.
* `useHostTheme`: Render layouts with your app's `Theme` instead of a default `ThemeData`. Layouts are styled in the
editor, so they use a default theme by default to look exactly as designed.
* `maxTextScaleFactor`: The largest system text scale layouts follow. `1` by default, which keeps layouts at their
designed size; raise it to let text grow with the user's accessibility settings.

### Global Data and Functions

Expand All @@ -296,8 +302,8 @@ Data and functions registered in the global `Codelessly.instance` are available
Codelessly.instance.initialize(
data: {'username': 'Sample User', 'paid': false},
functions: {
'openPurchasePage': CodelesslyFunction(
(context) => Navigator.pushNamed(context, "PurchasePage")),
'openPurchasePage': (context, reference, params) =>
Navigator.pushNamed(context, 'PurchasePage'),
},
);
```
Expand Down
4 changes: 4 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,17 @@ analyzer:
exclude:
- lib/**/*.pb*.dart
- lib/**/*.g.dart
- build/**
errors:
# treat missing required parameters as a warning (not a hint)
missing_required_param: warning
# treat missing returns as a warning (not a hint)
missing_return: warning
# allow having TODOs in the code
todo: ignore
# Models are mutable by design. Equatable 3 marks itself @immutable,
# which would flag every one of them.
must_be_immutable: ignore

linter:
rules:
Expand Down
2 changes: 1 addition & 1 deletion build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ targets:
exclude:
- example/**
builders:
codelessly_json_serializable:
json_serializable:
options:
# The other properties are the same as default (https://pub.dev/packages/json_serializable#build-configuration).
# explicit_to_json must be true for nested properties to work (like a Paint inside a Frame, toJson must be called in both)
Expand Down
9 changes: 9 additions & 0 deletions example/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@

# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
analyzer:
exclude:
- build/**
- android/**
- ios/**
- web/**
- windows/**
- macos/**
- linux/**
include: package:flutter_lints/flutter.yaml

linter:
Expand Down
8 changes: 0 additions & 8 deletions example/linux/flutter/generated_plugin_registrant.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,9 @@

#include "generated_plugin_registrant.h"

#include <irondash_engine_context/irondash_engine_context_plugin.h>
#include <super_native_extensions/super_native_extensions_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>

void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) irondash_engine_context_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "IrondashEngineContextPlugin");
irondash_engine_context_plugin_register_with_registrar(irondash_engine_context_registrar);
g_autoptr(FlPluginRegistrar) super_native_extensions_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "SuperNativeExtensionsPlugin");
super_native_extensions_plugin_register_with_registrar(super_native_extensions_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
Expand Down
3 changes: 1 addition & 2 deletions example/linux/flutter/generated_plugins.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
#

list(APPEND FLUTTER_PLUGIN_LIST
irondash_engine_context
super_native_extensions
url_launcher_linux
)

list(APPEND FLUTTER_FFI_PLUGIN_LIST
jni
)

set(PLUGIN_BUNDLED_LIBRARIES)
Expand Down
24 changes: 0 additions & 24 deletions example/macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,17 @@ import FlutterMacOS
import Foundation

import cloud_firestore
import cloud_functions
import connectivity_plus
import device_info_plus
import file_picker
import firebase_analytics
import firebase_auth
import firebase_core
import firebase_crashlytics
import firebase_database
import firebase_storage
import google_sign_in_ios
import irondash_engine_context
import path_provider_foundation
import shared_preferences_foundation
import super_native_extensions
import url_launcher_macos
import webview_flutter_wkwebview

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin"))
FLTFirebaseFunctionsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFunctionsPlugin"))
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
FLTFirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAnalyticsPlugin"))
FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin"))
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
FLTFirebaseCrashlyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCrashlyticsPlugin"))
FLTFirebaseDatabasePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseDatabasePlugin"))
FLTFirebaseStoragePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseStoragePlugin"))
FLTGoogleSignInPlugin.register(with: registry.registrar(forPlugin: "FLTGoogleSignInPlugin"))
IrondashEngineContextPlugin.register(with: registry.registrar(forPlugin: "IrondashEngineContextPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SuperNativeExtensionsPlugin.register(with: registry.registrar(forPlugin: "SuperNativeExtensionsPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
}
6 changes: 3 additions & 3 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1

environment:
sdk: ">=3.6.0 <4.0.0"
flutter: ">=3.24.0"
sdk: ^3.13.0
flutter: ">=3.47.0"

dependencies:
flutter:
Expand All @@ -19,7 +19,7 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^5.0.0
flutter_lints: ^6.0.0

flutter:
uses-material-design: true
Loading
Loading