Skip to content

Commit ebdb8c3

Browse files
committed
Add property bar listenable.
1 parent 1922eb6 commit ebdb8c3

File tree

5 files changed

+155
-24
lines changed

5 files changed

+155
-24
lines changed

patterns/abstract_factory/tool_panel_factory/app/app.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class App {
1212

1313
void addShape(double x, double y) {
1414
final activeColor = tools.activeColor.value;
15-
final activeFactory = tools.activeFactory.value!;
15+
final activeFactory = tools.activeFactory.value;
1616

1717
final newShape = activeFactory.createShape(x, y, activeColor);
1818
newShape.centerToFit();

patterns/abstract_factory/tool_panel_factory/app/tools.dart

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,18 @@ class Tools {
1010
final List<ToolFactory> factories;
1111
final List<Color> colors;
1212

13-
final activeFactory = ValueNotifier<ToolFactory?>(null);
13+
late final ValueNotifier<ToolFactory> activeFactory;
1414

15-
final activeColor = ValueNotifier(Color(0x0FFFFFFFF));
15+
late final ValueNotifier<Color> activeColor;
1616

1717
Future<bool> get iconsReady => _iconsInitCompleter.future;
1818

19-
Tools({required this.factories, required this.colors}) {
19+
Tools({required this.factories, required this.colors})
20+
: assert(factories.isNotEmpty),
21+
assert(colors.isNotEmpty) {
22+
activeFactory = ValueNotifier(factories.first);
23+
activeColor = ValueNotifier(colors.first);
2024
_initIconsFromShapes();
21-
22-
if (factories.isNotEmpty) {
23-
activeFactory.value = factories.first;
24-
}
25-
26-
if (colors.isNotEmpty) {
27-
activeColor.value = colors.first;
28-
}
2925
}
3026

3127
final _iconsInitCompleter = Completer<bool>();

patterns/abstract_factory/tool_panel_factory/main.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'factories/star_factory.dart';
99
import 'factories/triangle_factory.dart';
1010
import 'factories/text_factory.dart';
1111
import 'widgets/drawing_board.dart';
12+
import 'widgets/property_bar.dart';
1213
import 'widgets/tool_panel.dart';
1314

1415
class ToolPanelFactoryApp extends StatefulWidget {
@@ -49,6 +50,9 @@ class _ToolPanelFactoryAppState extends State<ToolPanelFactoryApp> {
4950
ToolPanel(
5051
tools: app.tools,
5152
),
53+
PropertyPanel(
54+
tools: app.tools,
55+
),
5256
],
5357
);
5458
}

patterns/abstract_factory/tool_panel_factory/widgets/independent/panel.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import 'package:flutter/material.dart';
22

33
class Panel extends StatelessWidget {
4-
static const thickness = 64.0;
4+
static const thicknessWidth = 64.0;
5+
static const thicknessHeight = 48.0;
56

67
final Axis direction;
78
final Widget child;
@@ -15,8 +16,8 @@ class Panel extends StatelessWidget {
1516
@override
1617
Widget build(BuildContext context) {
1718
return Container(
18-
height: direction == Axis.horizontal ? thickness : null,
19-
width: direction == Axis.vertical ? thickness : null,
19+
height: direction == Axis.horizontal ? thicknessHeight : null,
20+
width: direction == Axis.vertical ? thicknessWidth : null,
2021
clipBehavior: Clip.antiAlias,
2122
decoration: BoxDecoration(
2223
color: Color(0xFF3B3B3B),
Lines changed: 139 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,153 @@
11
import 'package:flutter/material.dart';
22

3+
import '../app/tools.dart';
4+
import '../pattern/property.dart';
5+
import '../pattern/tool_factory.dart';
36
import 'independent/panel.dart';
47

5-
class PropertyBar extends StatelessWidget {
6-
const PropertyBar({Key? key}) : super(key: key);
8+
class PropertyPanel extends StatelessWidget {
9+
final Tools tools;
10+
11+
const PropertyPanel({
12+
Key? key,
13+
required this.tools,
14+
}) : super(key: key);
715

816
@override
917
Widget build(BuildContext context) {
1018
return Positioned(
1119
top: 12,
12-
left: 200,
13-
child: Panel(
14-
direction: Axis.horizontal,
15-
child: Row(
16-
children: [
17-
Text('Hello'),
18-
],
20+
left: 12 + 64 + 8 + 12,
21+
child: _buildTheme(
22+
child: Panel(
23+
direction: Axis.horizontal,
24+
child: ValueListenableBuilder<ToolFactory>(
25+
valueListenable: tools.activeFactory,
26+
builder: (_, activeFactory, __) {
27+
return Row(
28+
children: [
29+
for (final prop in activeFactory.properties)
30+
_buildProperty(prop),
31+
],
32+
);
33+
},
34+
),
35+
),
36+
),
37+
);
38+
}
39+
40+
Widget _buildTheme({required Widget child}) {
41+
return Material(
42+
color: Colors.transparent,
43+
textStyle: TextStyle(
44+
color: Colors.white,
45+
fontSize: 18,
46+
fontWeight: FontWeight.w600,
47+
),
48+
child: child);
49+
}
50+
51+
Widget _buildProperty(Property prop) {
52+
switch (prop.value().runtimeType) {
53+
case String:
54+
return StringPropertyWidget(property: prop);
55+
case double:
56+
return DoublePropertyWidget(property: prop);
57+
}
58+
59+
throw 'Type(${prop.value().runtimeType}) of property is not support';
60+
}
61+
}
62+
63+
class _FieldLabel extends StatelessWidget {
64+
final String text;
65+
final Widget child;
66+
67+
const _FieldLabel({
68+
Key? key,
69+
required this.text,
70+
required this.child,
71+
}) : super(key: key);
72+
73+
@override
74+
Widget build(BuildContext context) {
75+
return Row(
76+
children: [
77+
SizedBox(width: 10),
78+
Text(text + ':'),
79+
SizedBox(width: 10),
80+
child,
81+
SizedBox(width: 20),
82+
],
83+
);
84+
}
85+
}
86+
87+
class StringPropertyWidget extends StatelessWidget {
88+
final Property property;
89+
90+
const StringPropertyWidget({Key? key, required this.property}) : super(key: key);
91+
92+
@override
93+
Widget build(BuildContext context) {
94+
return _FieldLabel(
95+
text: property.name,
96+
child: Container(
97+
color: Colors.white12,
98+
width: 120,
99+
height: 32,
100+
child: TextFormField(
101+
style: TextStyle(fontSize: 18, color: Colors.white70),
102+
decoration: InputDecoration(
103+
contentPadding: const EdgeInsets.only(left: 5.0, bottom: 14.0),
104+
border: UnderlineInputBorder(),
105+
),
106+
initialValue: property.value(),
107+
onChanged: property.onChange,
19108
),
20109
),
21110
);
22111
}
23112
}
113+
114+
115+
class DoublePropertyWidget extends StatefulWidget {
116+
final Property property;
117+
118+
const DoublePropertyWidget({Key? key, required this.property})
119+
: super(key: key);
120+
121+
@override
122+
_DoublePropertyWidgetState createState() => _DoublePropertyWidgetState();
123+
}
124+
125+
class _DoublePropertyWidgetState extends State<DoublePropertyWidget> {
126+
@override
127+
Widget build(BuildContext context) {
128+
return _FieldLabel(
129+
text: widget.property.name,
130+
child: Row(
131+
children: [
132+
Slider(
133+
min: 4,
134+
max: 150,
135+
value: widget.property.value() as double,
136+
onChanged: (val) {
137+
setState(() {
138+
widget.property.onChange(val);
139+
});
140+
},
141+
),
142+
SizedBox(
143+
width: 32,
144+
child: Text(
145+
(widget.property.value() as double).toStringAsFixed(0),
146+
textAlign: TextAlign.right,
147+
),
148+
)
149+
],
150+
),
151+
);
152+
}
153+
}

0 commit comments

Comments
 (0)