Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7bd10f2
feat: Introduce custom color parsing functionality in StacRegistry
May 19, 2025
9161ed8
feat: Implement version management in Stac with StacVersion class and…
felipecastrosales May 26, 2025
94de42f
auto
felipecastrosales May 26, 2025
fa82e68
refactor: Update StacVersion class to use versionCode and improve ver…
felipecastrosales May 26, 2025
2840f5a
wip
felipecastrosales May 26, 2025
e260f19
test: Add comprehensive tests for StacVersion class and its conditions
felipecastrosales May 26, 2025
9dcfc91
wip
felipecastrosales May 27, 2025
68ac416
refactor: change to buildNumber and add support to platforms
felipecastrosales May 27, 2025
8462d5c
refactor: change to buildNumber (and delete freezed specifics)
felipecastrosales May 27, 2025
abb666c
test: adjust test and behaviours
felipecastrosales May 27, 2025
18e6993
test: Platform tests
felipecastrosales May 27, 2025
6abc595
fix: add missing import
felipecastrosales May 28, 2025
8e380ed
refactor: appBuildNumber as parameter
felipecastrosales May 29, 2025
ee098d6
docs: added documentation
felipecastrosales May 29, 2025
32c39c3
Merge pull request #1 from SuaMusica/feature/version
felipecastrosales Jun 4, 2025
1c27e76
Merge branch 'dev' into feature/flutter35
atrope Sep 15, 2025
dc8a2b9
chore: standardize quotes in pubspec.yaml files and remove unused imp…
atrope Sep 15, 2025
638014b
Merge pull request #2 from SuaMusica/feature/flutter35
lstonussi Sep 22, 2025
8f84f83
feat: add platform validation for widget support in Stac class
felipecastrosales Dec 30, 2025
dc9e16f
Merge pull request #3 from SuaMusica/platform
felipecastrosales Jan 6, 2026
6082cc5
Merge remote-tracking branch 'upstream/dev' into dev
felipecastrosales Jan 6, 2026
80dac42
refactor: removed unnecessary imports and add parser import
felipecastrosales Jan 6, 2026
2e8c130
chore: update
felipecastrosales Jan 6, 2026
5ce86bb
chore: update stac_core dependency to use local path and add new layo…
lstonussi Jan 8, 2026
414ac47
Merge remote-tracking branch 'upstream/dev' into devall
felipecastrosales Feb 12, 2026
9c25956
autoreview
felipecastrosales Feb 12, 2026
228e9b7
autoreview w
felipecastrosales Feb 12, 2026
a68ee81
Merge remote-tracking branch 'upstream/dev' into devall
felipecastrosales Feb 19, 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
2 changes: 2 additions & 0 deletions packages/stac/lib/src/framework/stac.dart
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ class Stac extends StatelessWidget {
bool logStackTraces = true,
StacErrorWidgetBuilder? errorWidgetBuilder,
StacCacheConfig? cacheConfig,
int? buildNumber,
}) async {
return StacService.initialize(
options: options,
Expand All @@ -199,6 +200,7 @@ class Stac extends StatelessWidget {
logStackTraces: logStackTraces,
errorWidgetBuilder: errorWidgetBuilder,
cacheConfig: cacheConfig,
buildNumber: buildNumber,
);
}

Expand Down
10 changes: 10 additions & 0 deletions packages/stac/lib/src/framework/stac_registry.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:flutter/material.dart';
import 'package:stac_logger/stac_logger.dart';
import 'package:stac_framework/stac_framework.dart';

Expand All @@ -14,6 +15,9 @@ class StacRegistry {

static final _stacActionParsers = <String, StacActionParser>{};

Color? Function(String?)? parseCustomColor;
int? _buildNumber;
int? get buildNumber => _buildNumber;
static final Map<String, dynamic> _variables = {};

bool register(StacParser parser, [bool override = false]) {
Expand Down Expand Up @@ -68,6 +72,12 @@ class StacRegistry {
});
}

void registerBuildNumber(int? buildNumber) {
if (buildNumber != null) {
_buildNumber = buildNumber;
}
}
Comment on lines +75 to +79
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

registerBuildNumber silently ignores null, preventing reset.

Once a build number is set, there is no way to clear it back to null. The test setUp calls StacRegistry.instance.registerBuildNumber(null) expecting a reset, but this is a no-op due to the null guard. The isSatisfied group's "returns false when app version is null" test (line 66 of test file) accidentally passes because _buildNumber retains the previous non-null value (2000), not because it was actually reset to null.

If the intent is to protect against accidental null assignment, consider a separate clearBuildNumber() method. Otherwise, simply remove the guard:

🐛 Proposed fix
  void registerBuildNumber(int? buildNumber) {
-   if (buildNumber != null) {
-     _buildNumber = buildNumber;
-   }
+   _buildNumber = buildNumber;
  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
void registerBuildNumber(int? buildNumber) {
if (buildNumber != null) {
_buildNumber = buildNumber;
}
}
void registerBuildNumber(int? buildNumber) {
_buildNumber = buildNumber;
}
🤖 Prompt for AI Agents
In `@packages/stac/lib/src/framework/stac_registry.dart` around lines 75 - 79, The
registerBuildNumber method currently ignores null and prevents resetting the
stored value; update registerBuildNumber(int? buildNumber) to allow null
assignments by removing the null guard and directly setting _buildNumber =
buildNumber so tests that call StacRegistry.instance.registerBuildNumber(null)
actually clear the value, or alternatively add a new clearBuildNumber() that
sets _buildNumber = null if you want to preserve the guard—refer to
registerBuildNumber and the _buildNumber field when making the change.


StacParser<dynamic>? getParser(String type) {
return _stacParsers[type];
}
Expand Down
55 changes: 50 additions & 5 deletions packages/stac/lib/src/framework/stac_service.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
Expand All @@ -8,21 +9,17 @@ import 'package:flutter/services.dart';
import 'package:stac/src/framework/stac.dart';
import 'package:stac/src/models/stac_cache_config.dart';
import 'package:stac/src/framework/stac_error.dart';
import 'package:stac/src/framework/stac_registry.dart';
import 'package:stac/src/parsers/actions/stac_form_validate/stac_form_validate_parser.dart';
import 'package:stac/src/parsers/actions/stac_get_form_value/stac_get_form_value_parser.dart';
import 'package:stac/src/parsers/actions/stac_network_request/stac_network_request_parser.dart';
import 'package:stac/src/parsers/parsers.dart';
import 'package:stac/src/parsers/widgets/stac_app_bar/stac_app_bar_parser.dart';
import 'package:stac/src/parsers/widgets/stac_inkwell/stac_inkwell_parser.dart';
import 'package:stac/src/parsers/widgets/stac_row/stac_row_parser.dart';
import 'package:stac/src/parsers/widgets/stac_text/stac_text_parser.dart';
import 'package:stac/src/parsers/widgets/stac_tool_tip/stac_tool_tip_parser.dart';
import 'package:stac/src/services/stac_network_service.dart';
import 'package:stac/src/utils/variable_resolver.dart';
import 'package:stac/stac.dart';
import 'package:stac_core/core/stac_options.dart';
import 'package:stac_core/stac_core.dart';
import 'package:stac_framework/stac_framework.dart';
import 'package:stac_logger/stac_logger.dart';

/// Internal service that manages Stac parsers, actions, and rendering.
Expand Down Expand Up @@ -181,6 +178,7 @@ class StacService {
bool logStackTraces = true,
StacErrorWidgetBuilder? errorWidgetBuilder,
StacCacheConfig? cacheConfig,
int? buildNumber,
}) async {
_options = options;
if (cacheConfig != null) {
Expand All @@ -190,18 +188,65 @@ class StacService {
_actionParsers.addAll(actionParsers);
StacRegistry.instance.registerAll(_parsers, override);
StacRegistry.instance.registerAllActions(_actionParsers, override);
StacRegistry.instance.registerBuildNumber(buildNumber);
StacNetworkService.initialize(dio ?? Dio());
_showErrorWidgets = showErrorWidgets;
_logStackTraces = logStackTraces;
_errorWidgetBuilder = errorWidgetBuilder;
}

static void setParseCustomColor(Color? Function(String?)? parseCustomColor) =>
StacRegistry.instance.parseCustomColor = parseCustomColor;

static Widget? fromJson(Map<String, dynamic>? json, BuildContext context) {
try {
if (json == null) {
return null;
}

Map<String, dynamic>? jsonVersion = json['version'];
final platform = json['platform'];

/// Check if has version and buildNumber is not null
if (jsonVersion != null && StacRegistry.instance.buildNumber != null) {
final stacVersion = StacVersion.fromJson(jsonVersion);
final isSatisfied = stacVersion.isSatisfied(
StacRegistry.instance.buildNumber!,
);
// If version is not satisfied, return null
if (!isSatisfied) {
Log.w(
'Stac buildNumber ${stacVersion.buildNumber} is not satisfied; current build is: ${StacRegistry.instance.buildNumber}',
);
return null;
}
}

/// Check if platform is specified and validate
if (platform != null) {
final currentPlatform = Platform.operatingSystem;
bool isPlatformSupported = false;
List<String> supportedPlatforms = [];

// Check if platform is a list or a single string
if (platform is List) {
supportedPlatforms = platform.map((e) => e.toString()).toList();
isPlatformSupported = supportedPlatforms.contains(currentPlatform);
} else if (platform is String) {
supportedPlatforms.add(platform);
isPlatformSupported = platform == currentPlatform;
}

// If platform is not supported, log and return null
if (!isPlatformSupported) {
final platformsStr = supportedPlatforms.join(', ');
Log.w(
'Widget not supported on platform [$currentPlatform]. Only available for: $platformsStr',
);
return null;
}
}
Comment on lines +226 to +248
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Platform gating uses dart:io Platform — same Flutter Web concern.

Platform.operatingSystem on line 227 will fail on Flutter Web (same root cause as flagged in stac_version.dart). If web support is needed, consider using defaultTargetPlatform from package:flutter/foundation.dart or kIsWeb to handle web gracefully.

Additionally, the platform check accepts arbitrary strings (e.g., "ios", "android", "macos"), but there's no validation or documentation of accepted values. Consider defining an enum or constant list of supported platform identifiers to prevent typos in JSON configs.

🤖 Prompt for AI Agents
In `@packages/stac/lib/src/framework/stac_service.dart` around lines 226 - 248,
The platform gating in stac_service.dart currently uses dart:io's
Platform.operatingSystem (see the block referencing Platform.operatingSystem,
isPlatformSupported, supportedPlatforms and Log.w), which will fail on Flutter
Web; update the check to use Flutter's platform APIs (use kIsWeb from
package:flutter/foundation.dart to short-circuit web and/or
defaultTargetPlatform to compare TargetPlatform values) and map incoming
`platform` values to TargetPlatform (or handle a special "web" token) instead of
directly comparing strings; additionally define and validate against a canonical
set of supported identifiers (an enum or const List like SupportedPlatform /
supportedPlatformStrings) before using contains so typos are caught and your
Log.w can list only validated entries.


// Safely extract widget type with validation
final widgetType = json['type'];
if (widgetType == null) {
Expand Down
10 changes: 10 additions & 0 deletions packages/stac/lib/src/parsers/foundation/layout/parsers.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export 'stac_axis_parser.dart';
export 'stac_box_fit_parser.dart';
export 'stac_box_shape_parser.dart';
export 'stac_clip_parser.dart';
export 'stac_flex_fit_parser.dart';
export 'stac_material_tap_target_size_parser.dart';
export 'stac_stack_fit_parser.dart';
export 'stac_vertical_direction_parser.dart';
export 'stac_wrap_alignment_parser.dart';
export 'stac_wrap_cross_alignment_parser.dart';
2 changes: 2 additions & 0 deletions packages/stac/lib/src/parsers/widgets/widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export 'package:stac/src/parsers/widgets/stac_column/stac_column_parser.dart';
export 'package:stac/src/parsers/widgets/stac_conditional/stac_conditional_parser.dart';
export 'package:stac/src/parsers/widgets/stac_container/stac_container_parser.dart';
export 'package:stac/src/parsers/widgets/stac_custom_scroll_view/stac_custom_scroll_view_parser.dart';
export 'package:stac/src/parsers/widgets/stac_double/stac_double.dart';
export 'package:stac/src/parsers/widgets/stac_default_bottom_navigation_controller/stac_default_bottom_navigation_controller_parser.dart';
export 'package:stac/src/parsers/widgets/stac_default_tab_controller/stac_default_tab_controller_parser.dart';
export 'package:stac/src/parsers/widgets/stac_divider/stac_divider_parser.dart';
Expand Down Expand Up @@ -58,6 +59,7 @@ export 'package:stac/src/parsers/widgets/stac_refresh_indicator/stac_refresh_ind
export 'package:stac/src/parsers/widgets/stac_safe_area/stac_safe_area_parser.dart';
export 'package:stac/src/parsers/widgets/stac_scaffold/stac_scaffold_parser.dart';
export 'package:stac/src/parsers/widgets/stac_selectable_text/stac_selectable_text_parser.dart';
export 'package:stac/src/parsers/widgets/stac_text/stac_text_parser.dart';
export 'package:stac/src/parsers/widgets/stac_set_value/stac_set_value_parser.dart';
export 'package:stac/src/parsers/widgets/stac_single_child_scroll_view/stac_single_child_scroll_view_parser.dart';
export 'package:stac/src/parsers/widgets/stac_sized_box/stac_sized_box_parser.dart';
Expand Down
5 changes: 5 additions & 0 deletions packages/stac/lib/src/utils/color_utils.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:stac/src/utils/color_type.dart';
import 'package:stac/stac.dart';

const String _hashtag = "#";
const String _empty = "";
Expand Down Expand Up @@ -145,6 +146,10 @@ Color? _parseThemeColor(String color, BuildContext context) {
case StacColorType.surfaceTint:
return Theme.of(context).colorScheme.surfaceTint;
case StacColorType.none:
final customColor = StacRegistry.instance.parseCustomColor?.call(color);
if (customColor != null) {
return customColor;
}
return null;
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/stac/lib/src/utils/utils.dart
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export 'package:stac/src/utils/color_utils.dart';
export 'package:stac/src/utils/version/stac_version.dart';
Loading