Skip to content

Commit

Permalink
CupertinoListTile control (#2487)
Browse files Browse the repository at this point in the history
* initial commit

* leading, title, subtitle, trailing, on_click

* additional_info property

* bgcolor and bgcolor_activated properties

* leading_size and leading_to_title properties

* padding property

* padding property

* clean up

* bgcolor to ListTile

* adaptive property for ListTile

* notched property for CupertinoListTile

* toggle_inputs property for CupertinoListTile

* clean up

* FletControlStatelessMixin

* List Tile to use withPagePlatform()

---------

Co-authored-by: Feodor Fitsner <feodor@appveyor.com>
  • Loading branch information
InesaFitsner and FeodorFitsner committed Jan 26, 2024
1 parent 1af2e72 commit e07a272
Show file tree
Hide file tree
Showing 6 changed files with 563 additions and 70 deletions.
8 changes: 8 additions & 0 deletions package/lib/src/controls/create_control.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import 'container.dart';
import 'cupertino_alert_dialog.dart';
import 'cupertino_checkbox.dart';
import 'cupertino_dialog_action.dart';
import 'cupertino_list_tile.dart';
import 'cupertino_navigation_bar.dart';
import 'cupertino_radio.dart';
import 'cupertino_slider.dart';
Expand Down Expand Up @@ -498,6 +499,13 @@ Widget createWidget(Key? key, ControlViewModel controlView, Control? parent,
control: controlView.control,
children: controlView.children,
parentDisabled: parentDisabled);
case "cupertinolisttile":
return CupertinoListTileControl(
key: key,
parent: parent,
control: controlView.control,
children: controlView.children,
parentDisabled: parentDisabled);
case "expansiontile":
return ExpansionTileControl(
key: key,
Expand Down
122 changes: 122 additions & 0 deletions package/lib/src/controls/cupertino_list_tile.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

import '../models/control.dart';
import '../utils/colors.dart';
import '../utils/edge_insets.dart';
import '../utils/launch_url.dart';
import 'create_control.dart';
import 'flet_control_stateless_mixin.dart';
import 'list_tile.dart';

class CupertinoListTileControl extends StatelessWidget
with FletControlStatelessMixin {
final Control? parent;
final Control control;
final List<Control> children;
final bool parentDisabled;
final ListTileClickNotifier _clickNotifier = ListTileClickNotifier();

CupertinoListTileControl(
{super.key,
this.parent,
required this.control,
required this.children,
required this.parentDisabled});

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

var leadingCtrls =
children.where((c) => c.name == "leading" && c.isVisible);
var titleCtrls = children.where((c) => c.name == "title" && c.isVisible);
var subtitleCtrls =
children.where((c) => c.name == "subtitle" && c.isVisible);
var trailingCtrls =
children.where((c) => c.name == "trailing" && c.isVisible);
var additionalInfoCtrls =
children.where((c) => c.name == "additionalInfo" && c.isVisible);

bool notched = control.attrBool("notched", false)!;
bool onclick = control.attrBool("onclick", false)!;
bool toggleInputs = control.attrBool("toggleInputs", false)!;
String url = control.attrString("url", "")!;
String? urlTarget = control.attrString("urlTarget");
bool disabled = control.isDisabled || parentDisabled;

Widget? additionalInfo = additionalInfoCtrls.isNotEmpty
? createControl(control, additionalInfoCtrls.first.id, disabled)
: null;
Widget? leading = leadingCtrls.isNotEmpty
? createControl(control, leadingCtrls.first.id, disabled)
: null;

Widget? title = titleCtrls.isNotEmpty
? createControl(control, titleCtrls.first.id, disabled)
: const Text("");

Widget? subtitle = subtitleCtrls.isNotEmpty
? createControl(control, subtitleCtrls.first.id, disabled)
: null;

Widget? trailing = trailingCtrls.isNotEmpty
? createControl(control, trailingCtrls.first.id, disabled)
: null;

Color? backgroundColor = HexColor.fromString(
Theme.of(context), control.attrString("bgcolor", "")!);
Color? bgcolorActivated = HexColor.fromString(
Theme.of(context), control.attrString("bgcolorActivated", "")!);

var padding = parseEdgeInsets(control, "contentPadding");

Function()? onPressed = (onclick || toggleInputs || url != "") && !disabled
? () {
debugPrint("CupertinoListTile ${control.id} clicked!");
if (toggleInputs) {
_clickNotifier.onClick();
}
if (url != "") {
openWebBrowser(url, webWindowName: urlTarget);
}
if (onclick) {
sendControlEvent(context, control.id, "click", "");
}
}
: null;

Widget tile;
!notched
? tile = CupertinoListTile(
onTap: onPressed,
additionalInfo: additionalInfo,
backgroundColor: backgroundColor,
backgroundColorActivated: bgcolorActivated,
leading: leading,
leadingSize: control.attrDouble("leadingSize", 28.0)!,
leadingToTitle: control.attrDouble("leadingToTitle", 16.0)!,
padding: padding,
title: title,
subtitle: subtitle,
trailing: trailing,
)
: tile = CupertinoListTile.notched(
onTap: onPressed,
additionalInfo: additionalInfo,
backgroundColor: backgroundColor,
backgroundColorActivated: bgcolorActivated,
leading: leading,
padding: padding,
title: title,
subtitle: subtitle,
trailing: trailing,
);

if (toggleInputs) {
tile = ListTileClicks(notifier: _clickNotifier, child: tile);
}

return constrainedControl(context, tile, parent, control);
}
}
161 changes: 91 additions & 70 deletions package/lib/src/controls/list_tile.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import 'package:flutter/material.dart';

import '../models/control.dart';
import '../utils/colors.dart';
import '../utils/edge_insets.dart';
import '../utils/launch_url.dart';
import 'create_control.dart';
import 'cupertino_list_tile.dart';
import 'flet_control_stateless_mixin.dart';
import 'flet_store_mixin.dart';

class ListTileClicks extends InheritedWidget {
const ListTileClicks({
Expand All @@ -23,7 +26,8 @@ class ListTileClicks extends InheritedWidget {
bool updateShouldNotify(ListTileClicks oldWidget) => true;
}

class ListTileControl extends StatelessWidget with FletControlStatelessMixin {
class ListTileControl extends StatelessWidget
with FletControlStatelessMixin, FletStoreMixin {
final Control? parent;
final Control control;
final List<Control> children;
Expand All @@ -40,76 +44,93 @@ class ListTileControl extends StatelessWidget with FletControlStatelessMixin {
@override
Widget build(BuildContext context) {
debugPrint("ListTile build: ${control.id}");

var leadingCtrls =
children.where((c) => c.name == "leading" && c.isVisible);
var titleCtrls = children.where((c) => c.name == "title" && c.isVisible);
var subtitleCtrls =
children.where((c) => c.name == "subtitle" && c.isVisible);
var trailingCtrls =
children.where((c) => c.name == "trailing" && c.isVisible);

bool selected = control.attrBool("selected", false)!;
bool dense = control.attrBool("dense", false)!;
bool isThreeLine = control.attrBool("isThreeLine", false)!;
bool autofocus = control.attrBool("autofocus", false)!;
bool onclick = control.attrBool("onclick", false)!;
bool toggleInputs = control.attrBool("toggleInputs", false)!;
bool onLongPressDefined = control.attrBool("onLongPress", false)!;
String url = control.attrString("url", "")!;
String? urlTarget = control.attrString("urlTarget");
bool disabled = control.isDisabled || parentDisabled;

Function()? onPressed = (onclick || toggleInputs || url != "") && !disabled
? () {
debugPrint("ListTile ${control.id} clicked!");
if (toggleInputs) {
_clickNotifier.onClick();
}
if (url != "") {
openWebBrowser(url, webWindowName: urlTarget);
}
if (onclick) {
sendControlEvent(context, control.id, "click", "");
return withPagePlatform((context, platform) {
bool adaptive = control.attrBool("adaptive", false)!;
if (adaptive &&
(platform == TargetPlatform.iOS ||
platform == TargetPlatform.macOS)) {
return CupertinoListTileControl(
control: control,
parent: parent,
parentDisabled: parentDisabled,
children: children);
}

var leadingCtrls =
children.where((c) => c.name == "leading" && c.isVisible);
var titleCtrls = children.where((c) => c.name == "title" && c.isVisible);
var subtitleCtrls =
children.where((c) => c.name == "subtitle" && c.isVisible);
var trailingCtrls =
children.where((c) => c.name == "trailing" && c.isVisible);

bool selected = control.attrBool("selected", false)!;
bool dense = control.attrBool("dense", false)!;
bool isThreeLine = control.attrBool("isThreeLine", false)!;
bool autofocus = control.attrBool("autofocus", false)!;
bool onclick = control.attrBool("onclick", false)!;
bool toggleInputs = control.attrBool("toggleInputs", false)!;
bool onLongPressDefined = control.attrBool("onLongPress", false)!;
String url = control.attrString("url", "")!;
String? urlTarget = control.attrString("urlTarget");
bool disabled = control.isDisabled || parentDisabled;

Function()? onPressed =
(onclick || toggleInputs || url != "") && !disabled
? () {
debugPrint("ListTile ${control.id} clicked!");
if (toggleInputs) {
_clickNotifier.onClick();
}
if (url != "") {
openWebBrowser(url, webWindowName: urlTarget);
}
if (onclick) {
sendControlEvent(context, control.id, "click", "");
}
}
: null;

Function()? onLongPress = onLongPressDefined && !disabled
? () {
debugPrint("Button ${control.id} clicked!");
sendControlEvent(context, control.id, "long_press", "");
}
}
: null;

Function()? onLongPress = onLongPressDefined && !disabled
? () {
debugPrint("Button ${control.id} clicked!");
sendControlEvent(context, control.id, "long_press", "");
}
: null;

Widget tile = ListTile(
autofocus: autofocus,
contentPadding: parseEdgeInsets(control, "contentPadding"),
isThreeLine: isThreeLine,
selected: selected,
dense: dense,
onTap: onPressed,
onLongPress: onLongPress,
enabled: !disabled,
leading: leadingCtrls.isNotEmpty
? createControl(control, leadingCtrls.first.id, disabled)
: null,
title: titleCtrls.isNotEmpty
? createControl(control, titleCtrls.first.id, disabled)
: null,
subtitle: subtitleCtrls.isNotEmpty
? createControl(control, subtitleCtrls.first.id, disabled)
: null,
trailing: trailingCtrls.isNotEmpty
? createControl(control, trailingCtrls.first.id, disabled)
: null,
);

if (toggleInputs) {
tile = ListTileClicks(notifier: _clickNotifier, child: tile);
}

return constrainedControl(context, tile, parent, control);
: null;

Widget tile = ListTile(
autofocus: autofocus,
contentPadding: parseEdgeInsets(control, "contentPadding"),
isThreeLine: isThreeLine,
selected: selected,
dense: dense,
onTap: onPressed,
onLongPress: onLongPress,
enabled: !disabled,
tileColor: HexColor.fromString(
Theme.of(context), control.attrString("bgcolor", "")!),
splashColor: HexColor.fromString(
Theme.of(context), control.attrString("bgcolorActivated", "")!),
leading: leadingCtrls.isNotEmpty
? createControl(control, leadingCtrls.first.id, disabled)
: null,
title: titleCtrls.isNotEmpty
? createControl(control, titleCtrls.first.id, disabled)
: null,
subtitle: subtitleCtrls.isNotEmpty
? createControl(control, subtitleCtrls.first.id, disabled)
: null,
trailing: trailingCtrls.isNotEmpty
? createControl(control, trailingCtrls.first.id, disabled)
: null,
);

if (toggleInputs) {
tile = ListTileClicks(notifier: _clickNotifier, child: tile);
}

return constrainedControl(context, tile, parent, control);
});
}
}

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 @@ -68,6 +68,7 @@
from flet_core.cupertino_app_bar import CupertinoAppBar
from flet_core.cupertino_checkbox import CupertinoCheckbox
from flet_core.cupertino_dialog_action import CupertinoDialogAction
from flet_core.cupertino_list_tile import CupertinoListTile
from flet_core.cupertino_navigation_bar import CupertinoNavigationBar
from flet_core.cupertino_radio import CupertinoRadio
from flet_core.cupertino_slider import CupertinoSlider
Expand Down

0 comments on commit e07a272

Please sign in to comment.