Skip to content
Merged
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
63 changes: 63 additions & 0 deletions client/lib/controls/animated_switcher.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import 'package:flet_view/controls/error.dart';
import 'package:flet_view/utils/animations.dart';
import 'package:flet_view/utils/gradient.dart';
import 'package:flutter/material.dart';

import '../models/control.dart';
import '../utils/borders.dart';
import 'create_control.dart';

class AnimatedSwitcherControl extends StatelessWidget {
final Control? parent;
final Control control;
final List<Control> children;
final bool parentDisabled;

const AnimatedSwitcherControl(
{Key? key,
this.parent,
required this.control,
required this.children,
required this.parentDisabled})
: super(key: key);

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

var contentCtrls =
children.where((c) => c.name == "content" && c.isVisible);

var switchInCurve = parseCurve(control.attrString("switchInCurve", "")!);
var switchOutCurve = parseCurve(control.attrString("switchOutCurve", "")!);
var duration = control.attrInt("duration", 1000)!;
var reverseDuration = control.attrInt("reverseDuration", 1000)!;
bool disabled = control.isDisabled || parentDisabled;

if (contentCtrls.isEmpty) {
return const ErrorControl("Content is not set.");
}

var child = createControl(control, contentCtrls.first.id, disabled);

return constrainedControl(
AnimatedSwitcher(
duration: Duration(milliseconds: duration),
reverseDuration: Duration(milliseconds: reverseDuration),
switchInCurve: switchInCurve,
switchOutCurve: switchOutCurve,
transitionBuilder: (child, animation) {
switch (control.attrString("transition", "")!.toLowerCase()) {
case "rotation":
return RotationTransition(turns: animation, child: child);
case "scale":
return ScaleTransition(scale: animation, child: child);
default:
return FadeTransition(opacity: animation, child: child);
}
},
child: child),
parent,
control);
}
}
212 changes: 141 additions & 71 deletions client/lib/controls/container.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import 'dart:convert';
import 'dart:typed_data';

import 'package:flet_view/utils/animations.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';

import '../models/app_state.dart';
import '../models/control.dart';
import '../utils/alignment.dart';
import '../utils/borders.dart';
import '../utils/colors.dart';
import '../utils/edge_insets.dart';
import '../utils/gradient.dart';
import '../utils/images.dart';
import '../utils/uri.dart';
import '../web_socket_client.dart';
import 'create_control.dart';
import 'error.dart';

class ContainerControl extends StatelessWidget {
final Control? parent;
Expand Down Expand Up @@ -37,23 +46,58 @@ class ContainerControl extends StatelessWidget {
bool onHover = control.attrBool("onHover", false)!;
bool disabled = control.isDisabled || parentDisabled;

var boxDecor = BoxDecoration(
color: bgColor,
gradient: parseGradient(Theme.of(context), control, "gradient"),
border: parseBorder(Theme.of(context), control, "border"),
borderRadius: parseBorderRadius(control, "borderRadius"));
var imageSrc = control.attrString("imageSrc", "")!;
var imageSrcBase64 = control.attrString("imageSrcBase64", "")!;
var imageRepeat = parseImageRepeat(control, "imageRepeat");
var imageFit = parseBoxFit(control, "imageFit");
var imageOpacity = control.attrDouble("imageOpacity", 1)!;

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

if ((onClick || onLongPress || onHover) && ink) {
return constrainedControl(
Container(
margin: parseEdgeInsets(control, "margin"),
child: Ink(
var animation = parseAnimation(control, "animate");

return StoreConnector<AppState, Uri?>(
distinct: true,
converter: (store) => store.state.pageUri,
builder: (context, pageUri) {
DecorationImage? image;

if (imageSrcBase64 != "") {
try {
Uint8List bytes = base64Decode(imageSrcBase64);
image = DecorationImage(
image: MemoryImage(bytes),
repeat: imageRepeat,
fit: imageFit,
opacity: imageOpacity);
} catch (ex) {
return ErrorControl("Error decoding base64: ${ex.toString()}");
}
} else if (imageSrc != "") {
var uri = Uri.parse(imageSrc);
image = DecorationImage(
image: NetworkImage(uri.hasAuthority
? imageSrc
: getAssetUri(pageUri!, imageSrc).toString()),
repeat: imageRepeat,
fit: imageFit,
opacity: imageOpacity);
}

var boxDecor = BoxDecoration(
color: bgColor,
gradient: parseGradient(Theme.of(context), control, "gradient"),
image: image,
backgroundBlendMode: BlendMode.modulate,
border: parseBorder(Theme.of(context), control, "border"),
borderRadius: parseBorderRadius(control, "borderRadius"));

if ((onClick || onLongPress || onHover) && ink) {
var ink = Ink(
child: InkWell(
onTap: onClick || onHover
onTap: !disabled && (onClick || onHover)
? () {
debugPrint("Container ${control.id} clicked!");
ws.pageEventFromWeb(
Expand All @@ -62,7 +106,7 @@ class ContainerControl extends StatelessWidget {
eventData: control.attrs["data"] ?? "");
}
: null,
onLongPress: onLongPress || onHover
onLongPress: !disabled && (onLongPress || onHover)
? () {
debugPrint("Container ${control.id} long pressed!");
ws.pageEventFromWeb(
Expand All @@ -71,7 +115,7 @@ class ContainerControl extends StatelessWidget {
eventData: control.attrs["data"] ?? "");
}
: null,
onHover: onHover
onHover: !disabled && onHover
? (value) {
debugPrint("Container ${control.id} hovered!");
ws.pageEventFromWeb(
Expand All @@ -86,64 +130,90 @@ class ContainerControl extends StatelessWidget {
alignment: parseAlignment(control, "alignment"),
),
borderRadius: parseBorderRadius(control, "borderRadius")),
decoration: boxDecor),
),
parent,
control);
} else {
Widget container = Container(
padding: parseEdgeInsets(control, "padding"),
margin: parseEdgeInsets(control, "margin"),
alignment: parseAlignment(control, "alignment"),
decoration: boxDecor,
child: child);
decoration: boxDecor);
return constrainedControl(
animation == null
? Container(
margin: parseEdgeInsets(control, "margin"),
child: ink,
)
: AnimatedContainer(
duration: animation.duration,
curve: animation.curve,
margin: parseEdgeInsets(control, "margin"),
child: ink),
parent,
control);
} else {
Widget container = animation == null
? Container(
width: control.attrDouble("width"),
height: control.attrDouble("height"),
padding: parseEdgeInsets(control, "padding"),
margin: parseEdgeInsets(control, "margin"),
alignment: parseAlignment(control, "alignment"),
decoration: boxDecor,
child: child)
: AnimatedContainer(
duration: animation.duration,
curve: animation.curve,
width: control.attrDouble("width"),
height: control.attrDouble("height"),
padding: parseEdgeInsets(control, "padding"),
margin: parseEdgeInsets(control, "margin"),
alignment: parseAlignment(control, "alignment"),
decoration: boxDecor,
child: child);

if (onClick || onLongPress || onHover) {
container = MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: onHover
? (value) {
debugPrint("Container's mouse region ${control.id} entered!");
ws.pageEventFromWeb(
eventTarget: control.id,
eventName: "hover",
eventData: "true");
}
: null,
onExit: onHover
? (value) {
debugPrint("Container's mouse region ${control.id} exited!");
ws.pageEventFromWeb(
eventTarget: control.id,
eventName: "hover",
eventData: "false");
}
: null,
child: GestureDetector(
child: container,
onTapDown: onClick
? (details) {
debugPrint("Container ${control.id} clicked!");
ws.pageEventFromWeb(
eventTarget: control.id,
eventName: "click",
eventData: control.attrString("data", "")! +
"${details.localPosition.dx}:${details.localPosition.dy} ${details.globalPosition.dx}:${details.globalPosition.dy}");
}
: null,
onLongPress: onLongPress
? () {
debugPrint("Container ${control.id} clicked!");
ws.pageEventFromWeb(
eventTarget: control.id,
eventName: "long_press",
eventData: control.attrs["data"] ?? "");
}
: null,
),
);
}
return constrainedControl(container, parent, control);
}
if (onClick || onLongPress || onHover) {
container = MouseRegion(
cursor: SystemMouseCursors.click,
onEnter: !disabled && onHover
? (value) {
debugPrint(
"Container's mouse region ${control.id} entered!");
ws.pageEventFromWeb(
eventTarget: control.id,
eventName: "hover",
eventData: "true");
}
: null,
onExit: !disabled && onHover
? (value) {
debugPrint(
"Container's mouse region ${control.id} exited!");
ws.pageEventFromWeb(
eventTarget: control.id,
eventName: "hover",
eventData: "false");
}
: null,
child: GestureDetector(
child: container,
onTapDown: !disabled && onClick
? (details) {
debugPrint("Container ${control.id} clicked!");
ws.pageEventFromWeb(
eventTarget: control.id,
eventName: "click",
eventData: control.attrString("data", "")! +
"${details.localPosition.dx}:${details.localPosition.dy} ${details.globalPosition.dx}:${details.globalPosition.dy}");
}
: null,
onLongPress: !disabled && onLongPress
? () {
debugPrint("Container ${control.id} clicked!");
ws.pageEventFromWeb(
eventTarget: control.id,
eventName: "long_press",
eventData: control.attrs["data"] ?? "");
}
: null,
),
);
}
return constrainedControl(container, parent, control);
}
});
}
}
Loading