Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ class _CupertinoNavigationBarControlState
border: widget.control.getBorder("border", Theme.of(context)),
onTap: widget.control.disabled ? null : _onTap,
items: widget.control.children("destinations").map((dest) {
dest.notifyParent = true;
return BottomNavigationBarItem(
tooltip: !dest.disabled ? dest.getString("tooltip") : null,
backgroundColor: dest.getColor("bgcolor", context),
Expand Down
1 change: 1 addition & 0 deletions packages/flet/lib/src/controls/dropdown.dart
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ class _DropdownControlState extends State<DropdownControl> {
var options = widget.control
.children("options")
.map<DropdownMenuEntry<String>?>((Control itemCtrl) {
itemCtrl.notifyParent = true;
bool itemDisabled = widget.control.disabled || itemCtrl.disabled;
ButtonStyle? style = itemCtrl.getButtonStyle("style", theme);

Expand Down
1 change: 1 addition & 0 deletions packages/flet/lib/src/controls/dropdownm2.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ class _DropdownM2ControlState extends State<DropdownM2Control> {
var items = widget.control
.children("options")
.map<DropdownMenuItem<String>>((Control item) {
item.notifyParent = true;
var textStyle = item.getTextStyle("text_style", Theme.of(context));
if (item.disabled && textStyle != null) {
textStyle = textStyle.apply(color: Theme.of(context).disabledColor);
Expand Down
1 change: 1 addition & 0 deletions packages/flet/lib/src/controls/segmented_button.dart
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class _SegmentedButtonControlState extends State<SegmentedButtonControl>
direction: widget.control.getAxis("direction", Axis.horizontal)!,
expandedInsets: widget.control.getPadding("padding"),
segments: segments.map((segment) {
segment.notifyParent = true;
return ButtonSegment(
value: segment.getString("value")!,
enabled: !segment.disabled,
Expand Down
19 changes: 16 additions & 3 deletions packages/flet/lib/src/models/control.dart
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,16 @@ class Control extends ChangeNotifier {
return backend.triggerControlEvent(this, eventName, data);
}

/// Whether this control currently has a handler subscribed to [eventName].
///
/// Accepts both `"event_name"` and `"on_event_name"` forms.
/// Internally this checks the boolean `on_<eventName>` property.
bool hasEventHandler(String eventName) {
final String propName =
eventName.startsWith("on_") ? eventName : "on_$eventName";
return get<bool>(propName, false)!;
}

/// Triggers a control event without checking for subscribers.
///
/// This method directly triggers the event for the control identified by its
Expand Down Expand Up @@ -374,7 +384,8 @@ class Control extends ChangeNotifier {
if (node.obj is Map) {
node.obj[index] = _transformIfControl(value, node.control, backend);
} else if (node.obj is List) {
node.obj.insert(index, _transformIfControl(value, node.control, backend));
node.obj
.insert(index, _transformIfControl(value, node.control, backend));
} else {
throw Exception("Add operation can be applied to lists or maps: $op");
}
Expand All @@ -388,7 +399,8 @@ class Control extends ChangeNotifier {
} else if (node.obj is Map) {
node.obj.remove(index);
} else {
throw Exception("Remove operation can be applied to lists or maps: $op");
throw Exception(
"Remove operation can be applied to lists or maps: $op");
}
if (shouldNotify) node.control.notify();
} else if (opType == OperationType.move) {
Expand All @@ -402,7 +414,8 @@ class Control extends ChangeNotifier {
} else if (fromNode.obj is Map && toNode.obj is Map) {
toNode.obj[toIndex] = fromNode.obj.remove(fromIndex);
} else {
throw Exception("Move operation can only be applied to lists or maps: $op");
throw Exception(
"Move operation can only be applied to lists or maps: $op");
}
if (shouldNotify) {
if (fromNode.control.id != toNode.control.id) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ AxisTitles parseAxisTitles(Control? control) {
return const AxisTitles(sideTitles: SideTitles(showTitles: false));
}

control.notifyParent = true;
final labels = control.children("labels");
for (final label in labels) {
label.notifyParent = true;
}

return AxisTitles(
axisNameWidget: control.buildWidget("title"),
axisNameSize: control.getDouble("title_size", 16)!,
Expand All @@ -147,11 +153,10 @@ AxisTitles parseAxisTitles(Control? control) {
interval: control.getDouble("label_spacing"),
minIncluded: control.getBool("show_min", true)!,
maxIncluded: control.getBool("show_max", true)!,
getTitlesWidget: control.children("labels").isEmpty
getTitlesWidget: labels.isEmpty
? defaultGetTitle
: (double value, TitleMeta meta) {
var label = control
.children("labels")
var label = labels
.firstWhereOrNull((l) => l.getDouble("value") == value);
return label?.buildTextOrWidget("label") ??
const SizedBox.shrink();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class CircleLayerControl extends StatelessWidget with FletStoreMixin {
.children("circles")
.where((c) => c.type == "CircleMarker")
.map((circle) {
circle.notifyParent = true;
return CircleMarker(
point: parseLatLng(circle.get("coordinates"))!,
color: circle.getColor("color", context, const Color(0xFF00FF00))!,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class MarkerLayerControl extends StatelessWidget with FletStoreMixin {
.children("markers")
.where((c) => c.type == "Marker")
.map((marker) {
marker.notifyParent = true;
return AnimatedMarker(
point: parseLatLng(marker.get("coordinates"))!,
rotate: marker.getBool("rotate"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class PolygonLayerControl extends StatelessWidget with FletStoreMixin {
.children("polygons")
.where((c) => c.type == "PolygonMarker")
.map((polygon) {
polygon.notifyParent = true;
return Polygon(
borderStrokeWidth: polygon.getDouble("border_stroke_width", 0)!,
borderColor: polygon.getColor("border_color", context, Colors.green)!,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class PolylineLayerControl extends StatelessWidget with FletStoreMixin {
.children("polylines")
.where((c) => c.type == "PolylineMarker")
.map((polyline) {
polyline.notifyParent = true;
return Polyline(
borderStrokeWidth: polyline.getDouble("border_stroke_width", 0)!,
borderColor:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class _RichAttributionControlState extends State<RichAttributionControl>
var attributions = widget.control
.children("attributions")
.map((Control c) {
c.notifyParent = true;
if (c.type == "TextSourceAttribution") {
return TextSourceAttribution(
c.getString("text", "Placeholder Text")!,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ class WebView(ft.LayoutControl):
Fires when the web page's scroll position changes.

Note:
Works only on the following platforms: iOS, Android and macOS.
Works only on the following platforms: iOS and Android.
Copy link
Contributor

Choose a reason for hiding this comment

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

So, macOS is not supported?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah. has no platform implementation for this.

"""

on_console_message: Optional[ft.EventHandler[WebViewConsoleMessageEvent]] = None
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
import 'package:collection/collection.dart';
import 'package:flet/flet.dart';
import 'package:webview_flutter/webview_flutter.dart';

LoadRequestMethod? parseLoadRequestMethod(String? value,
[LoadRequestMethod? defaultValue]) {
if (value == null) return defaultValue;
return LoadRequestMethod.values.firstWhereOrNull(
(e) => e.name.toLowerCase() == value.toLowerCase()) ??
defaultValue;
return parseEnum(LoadRequestMethod.values, value);
}

JavaScriptMode? parseJavaScriptMode(String? value,
[JavaScriptMode? defaultValue]) {
if (value == null) return defaultValue;
return JavaScriptMode.values.firstWhereOrNull(
(e) => e.name.toLowerCase() == value.toLowerCase()) ??
defaultValue;
return parseEnum(JavaScriptMode.values, value);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,65 @@ class WebviewMobileAndMac extends StatefulWidget {

class _WebviewMobileAndMacState extends State<WebviewMobileAndMac> {
late WebViewController controller;
bool _scrollHandlerRegistered = false;
bool _consoleHandlerRegistered = false;
bool _alertHandlerRegistered = false;

bool _shouldPreventNavigation(String url) {
final links = widget.control.get<List>("prevent_links");
if (links == null || links.isEmpty) return false;
return links.any((link) => link is String && url.startsWith(link));
}

void _setOptionalEventHandlers() {
// macOS currently does not surface scroll callbacks via webview_flutter.
if (!isMacOSDesktop() &&
!_scrollHandlerRegistered &&
widget.control.hasEventHandler("scroll")) {
try {
controller.setOnScrollPositionChange((ScrollPositionChange position) {
widget.control
.triggerEvent("scroll", {"x": position.x, "y": position.y});
});
_scrollHandlerRegistered = true;
} catch (e) {
debugPrint("WebView.on_scroll is not available on this platform: $e");
}
}

if (!_consoleHandlerRegistered &&
widget.control.hasEventHandler("console_message")) {
try {
controller.setOnConsoleMessage((JavaScriptConsoleMessage message) {
widget.control.triggerEvent("console_message", {
"message": message.message,
"severity_level": message.level.name,
});
});
_consoleHandlerRegistered = true;
} catch (e) {
debugPrint(
"WebView.on_console_message is not available on this platform: $e");
}
}

if (!_alertHandlerRegistered &&
widget.control.hasEventHandler("javascript_alert_dialog")) {
try {
controller.setOnJavaScriptAlertDialog(
(JavaScriptAlertDialogRequest request) async {
widget.control.triggerEvent(
"javascript_alert_dialog",
{"message": request.message, "url": request.url},
);
});
_alertHandlerRegistered = true;
} catch (e) {
debugPrint(
"WebView.on_javascript_alert_dialog is not available on this platform: $e");
}
}
}

@override
void initState() {
Expand Down Expand Up @@ -41,11 +100,7 @@ class _WebviewMobileAndMacState extends State<WebviewMobileAndMac> {
widget.control.triggerEvent("web_resource_error", error.description);
},
onNavigationRequest: (NavigationRequest request) {
var links = widget.control.get("prevent_link");
var prevent = links is List &&
links.isNotEmpty &&
links.any((l) => request.url.startsWith(l));
return prevent
return _shouldPreventNavigation(request.url)
? NavigationDecision.prevent
: NavigationDecision.navigate;
},
Expand All @@ -58,26 +113,7 @@ class _WebviewMobileAndMacState extends State<WebviewMobileAndMac> {
method: parseLoadRequestMethod(
widget.control.getString("method"), LoadRequestMethod.get)!);

// scroll
if (!isMacOSDesktop()) {
controller.setOnScrollPositionChange((ScrollPositionChange position) {
widget.control
.triggerEvent("scroll", {"x": position.x, "y": position.y});
});
}

// console
controller.setOnConsoleMessage((JavaScriptConsoleMessage message) {
widget.control.triggerEvent("console_message",
{"message": message.message, "level": message.level.name});
});

// alert
controller.setOnJavaScriptAlertDialog(
(JavaScriptAlertDialogRequest request) async {
widget.control.triggerEvent("javascript_alert_dialog",
{"message": request.message, "url": request.url});
});
_setOptionalEventHandlers();
}

Future<dynamic> _invokeMethod(String name, dynamic args) async {
Expand All @@ -87,9 +123,9 @@ class _WebviewMobileAndMacState extends State<WebviewMobileAndMac> {
await controller.reload();
break;
case "can_go_back":
return controller.canGoBack().toString();
return controller.canGoBack();
case "can_go_forward":
return controller.canGoForward().toString();
return controller.canGoForward();
case "go_back":
if (await controller.canGoBack()) {
await controller.goBack();
Expand Down Expand Up @@ -175,6 +211,8 @@ class _WebviewMobileAndMacState extends State<WebviewMobileAndMac> {
Widget build(BuildContext context) {
debugPrint("WebViewControl build: ${widget.control.id}");

_setOptionalEventHandlers();

var bgcolor = widget.control.getColor("bgcolor", context);

if (bgcolor != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ dependencies:
sdk: flutter

collection: ^1.16.0
webview_flutter: ^4.13.0
webview_flutter: ^4.13.1
webview_flutter_web: 0.2.3+4
webview_flutter_platform_interface: 2.14.0

Expand Down
Loading