Skip to content
11 changes: 9 additions & 2 deletions package/lib/src/controls/create_control.dart
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ import 'vertical_divider.dart';
import 'webview.dart';
import 'window_drag_area.dart';
import 'cupertino_checkbox.dart';
import 'cupertino_switch.dart';

Widget createControl(Control? parent, String id, bool parentDisabled,
{Widget? nextChild}) {
Expand Down Expand Up @@ -334,8 +335,7 @@ Widget createWidget(Key? key, ControlViewModel controlView, Control? parent,
control: controlView.control,
children: controlView.children,
parentDisabled: parentDisabled,
dispatch: controlView.dispatch
);
dispatch: controlView.dispatch);
case "stack":
return StackControl(
key: key,
Expand Down Expand Up @@ -502,6 +502,13 @@ Widget createWidget(Key? key, ControlViewModel controlView, Control? parent,
control: controlView.control,
parentDisabled: parentDisabled,
dispatch: controlView.dispatch);
case "cupertinoswitch":
return CupertinoSwitchControl(
key: key,
parent: parent,
control: controlView.control,
parentDisabled: parentDisabled,
dispatch: controlView.dispatch);
case "slider":
return SliderControl(
key: key,
Expand Down
150 changes: 150 additions & 0 deletions package/lib/src/controls/cupertino_switch.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';

import '../actions.dart';
import '../flet_app_services.dart';
import '../models/app_state.dart';
import '../models/control.dart';
import '../protocol/update_control_props_payload.dart';
import '../utils/buttons.dart';
import '../utils/colors.dart';
import 'create_control.dart';
import 'list_tile.dart';

enum LabelPosition { right, left }

class CupertinoSwitchControl extends StatefulWidget {
final Control? parent;
final Control control;
final bool parentDisabled;
final dynamic dispatch;

const CupertinoSwitchControl(
{super.key,
this.parent,
required this.control,
required this.parentDisabled,
required this.dispatch});

@override
State<CupertinoSwitchControl> createState() => _CupertinoSwitchControlState();
}

class _CupertinoSwitchControlState extends State<CupertinoSwitchControl> {
bool _value = false;
late final FocusNode _focusNode;

@override
void initState() {
super.initState();
_focusNode = FocusNode();
_focusNode.addListener(_onFocusChange);
}

@override
void dispose() {
_focusNode.removeListener(_onFocusChange);
_focusNode.dispose();
super.dispose();
}

void _onChange(bool value) {
var svalue = value.toString();
debugPrint(svalue);
setState(() {
_value = value;
});
List<Map<String, String>> props = [
{"i": widget.control.id, "value": svalue}
];
widget.dispatch(
UpdateControlPropsAction(UpdateControlPropsPayload(props: props)));
final server = FletAppServices.of(context).server;
server.updateControlProps(props: props);
server.sendPageEvent(
eventTarget: widget.control.id, eventName: "change", eventData: svalue);
}

void _onFocusChange() {
FletAppServices.of(context).server.sendPageEvent(
eventTarget: widget.control.id,
eventName: _focusNode.hasFocus ? "focus" : "blur",
eventData: "");
}

@override
Widget build(BuildContext context) {
debugPrint("CupertinoSwitchControl build: ${widget.control.id}");

String label = widget.control.attrString("label", "")!;
LabelPosition labelPosition = LabelPosition.values.firstWhere(
(p) =>
p.name.toLowerCase() ==
widget.control.attrString("labelPosition", "")!.toLowerCase(),
orElse: () => LabelPosition.right);
bool autofocus = widget.control.attrBool("autofocus", false)!;
bool disabled = widget.control.isDisabled || widget.parentDisabled;

return StoreConnector<AppState, Function>(
distinct: true,
converter: (store) => store.dispatch,
builder: (context, dispatch) {
debugPrint(
"CupertinoSwitch StoreConnector build: ${widget.control.id}");

bool value = widget.control.attrBool("value", false)!;
if (_value != value) {
_value = value;
}

var materialThumbColor = parseMaterialStateColor(
Theme.of(context), widget.control, "thumbColor");

var materialTrackColor = parseMaterialStateColor(
Theme.of(context), widget.control, "trackColor");

var swtch = CupertinoSwitch(
autofocus: autofocus,
focusNode: _focusNode,
activeColor: HexColor.fromString(Theme.of(context),
widget.control.attrString("activeColor", "")!),
thumbColor: materialThumbColor?.resolve({}),
trackColor: materialTrackColor?.resolve({}),
focusColor: HexColor.fromString(Theme.of(context),
widget.control.attrString("focusColor", "")!),
value: _value,
onChanged: !disabled
? (bool value) {
_onChange(value);
}
: null);

ListTileClicks.of(context)?.notifier.addListener(() {
_onChange(!_value);
});

Widget result = swtch;
if (label != "") {
var labelWidget = disabled
? Text(label,
style: TextStyle(color: Theme.of(context).disabledColor))
: MouseRegion(
cursor: SystemMouseCursors.click, child: Text(label));
result = MergeSemantics(
child: GestureDetector(
onTap: !disabled
? () {
_onChange(!_value);
}
: null,
child: labelPosition == LabelPosition.right
? Row(children: [swtch, labelWidget])
: Row(children: [labelWidget, swtch])));
}

return constrainedControl(
context, result, widget.parent, widget.control);
});
}
}
16 changes: 15 additions & 1 deletion package/lib/src/controls/switch.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';

Expand All @@ -11,6 +12,7 @@ import '../utils/colors.dart';
import '../utils/icons.dart';
import 'create_control.dart';
import 'list_tile.dart';
import 'cupertino_switch.dart';

enum LabelPosition { right, left }

Expand Down Expand Up @@ -78,6 +80,16 @@ class _SwitchControlState extends State<SwitchControl> {
Widget build(BuildContext context) {
debugPrint("SwitchControl build: ${widget.control.id}");

bool adaptive = widget.control.attrBool("adaptive", false)!;
if (adaptive &&
(defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS)) {
return CupertinoSwitchControl(
control: widget.control,
parentDisabled: widget.parentDisabled,
dispatch: widget.dispatch);
}

String label = widget.control.attrString("label", "")!;
LabelPosition labelPosition = LabelPosition.values.firstWhere(
(p) =>
Expand All @@ -91,7 +103,7 @@ class _SwitchControlState extends State<SwitchControl> {
distinct: true,
converter: (store) => store.dispatch,
builder: (context, dispatch) {
debugPrint("Checkbox StoreConnector build: ${widget.control.id}");
debugPrint("Switch StoreConnector build: ${widget.control.id}");

bool value = widget.control.attrBool("value", false)!;
if (_value != value) {
Expand All @@ -115,6 +127,8 @@ class _SwitchControlState extends State<SwitchControl> {
Theme.of(context), widget.control, "thumbIcon"),
trackColor: parseMaterialStateColor(
Theme.of(context), widget.control, "trackColor"),
focusColor: HexColor.fromString(Theme.of(context),
widget.control.attrString("focusColor", "")!),
value: _value,
onChanged: !disabled
? (bool value) {
Expand Down
1 change: 1 addition & 0 deletions sdk/python/packages/flet-core/src/flet_core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,4 @@
from flet_core.navigation_drawer import NavigationDrawer, NavigationDrawerDestination
from flet_core.selection_area import SelectionArea
from flet_core.cupertino_checkbox import CupertinoCheckbox
from flet_core.cupertino_switch import CupertinoSwitch
Loading