Skip to content

Commit f3d74d6

Browse files
authored
Merge pull request #48 from ilopX/too_panel
Add "Tool Panel Factory" - flutter example.
2 parents 30c49b3 + 8859d33 commit f3d74d6

31 files changed

+1001
-3
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 0.23.0
2+
- Add "Tool Panel Factory" flutter example
3+
14
## 0.22.0
25
- Add visitor pattern: "Shape Xml Export".
36

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ It contains **Dart** examples for all classic **GoF** design patterns.
44

55
# Implementation checklist:
66
- [ ] **Creation**
7-
- [x] **Abstract Factory** [[Conceptual Gui Factory](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/abstract_factory/conceptual_gui_factory)]
7+
- [x] **Abstract Factory** [[Conceptual Gui Factory](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/abstract_factory/conceptual_gui_factory)] [[Tool Panel Factory](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/abstract_factory/tool_panel_factory)]
88
- [x] **Builder** - [[Color Text Format](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/builder/color_text_format)]
99
- [x] **Factory Method** [[Conceptual Platform Dialog](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/factory_method/conceptual_platform_dialog)]
1010
- [x] **Prototype** - [[Shapes](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/prototype/shapes)]

bin/main.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:flutter/material.dart';
2+
import '../patterns/abstract_factory/tool_panel_factory/main.dart';
23
import '../patterns/observer/subscriber_flutter_widget/main.dart';
34
import '../patterns/adapter/flutter_adapter/main.dart';
45
import '../patterns/memento/memento_editor/main.dart';
@@ -13,11 +14,12 @@ class MyApp extends StatelessWidget {
1314
return MaterialApp(
1415
title: 'Refactoring Guru: Flutter launcher',
1516
theme: ThemeData(primarySwatch: Colors.pink),
16-
initialRoute: '/memento/flutter_memento_editor',
17+
initialRoute: '/abstract_factory/tool_panel',
1718
routes: {
1819
'/observer/subscriber_flutter_widget': (_) => SubscriberFlutterApp(),
1920
'/adapter/flutter_adapter': (_) => FlutterAdapterApp(),
2021
'/memento/flutter_memento_editor': (_) => FlutterMementoEditorApp(),
22+
'/abstract_factory/tool_panel_factory': (_) => ToolPanelFactoryApp(),
2123
},
2224
);
2325
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Abstract Factory Pattern
2+
Abstract Factory is a creational design pattern that lets you produce families of related objects
3+
without specifying their concrete classes.
4+
5+
Tutorial: [here](https://refactoring.guru/design-patterns/abstract-factory).
6+
7+
### Online demo:
8+
Click on the picture to see the [demo](https://RefactoringGuru.github.io/design-patterns-dart/#/abstract_factory/tool_panel_factory).
9+
10+
[![image](https://user-images.githubusercontent.com/8049534/168668992-369a1bab-9f97-4333-a20e-ffd06bf91b54.png)](https://refactoringguru.github.io/design-patterns-dart/#/abstract_factory/tool_panel_factory)
11+
12+
### Diagram:
13+
![image](https://user-images.githubusercontent.com/8049534/168672053-73ae1c9c-8fad-45ae-9247-429f7b5da565.png)
14+
15+
### Client code (using the "createShape" method):
16+
```dart
17+
final app = App(
18+
tools: Tools(
19+
factories: [
20+
TxtFactory(),
21+
LineFactory(),
22+
CircleFactory(),
23+
TriangleFactory(),
24+
StarFactory(),
25+
],
26+
),
27+
);
28+
29+
class App {
30+
void addShape(double x, double y) {
31+
final newShape = activeFactory.createShape(x, y, activeColor);
32+
shapes.add(newShape);
33+
}
34+
}
35+
36+
mixin IconBoxMixin implements FactoryTool {
37+
Image? _icon;
38+
39+
@override
40+
Image get icon => _icon!;
41+
42+
Future<void> updateIcon(Color color) async {
43+
final shape = createShape(0, 0, color);
44+
final pngBytes = await _pngImageFromShape(shape);
45+
_icon = Image.memory(pngBytes);
46+
}
47+
}
48+
```
49+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import '../app/tools.dart';
2+
import 'shapes.dart';
3+
4+
class App {
5+
final Tools tools;
6+
final Shapes shapes;
7+
8+
App({
9+
required this.tools,
10+
required this.shapes,
11+
});
12+
13+
void addShape(double x, double y) {
14+
final activeColor = tools.activeColor.value;
15+
final activeFactory = tools.activeFactory.value!;
16+
17+
final newShape = activeFactory.createShape(x, y, activeColor);
18+
newShape.centerToFit();
19+
shapes.add(newShape);
20+
}
21+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import 'dart:collection';
2+
3+
import 'package:flutter/foundation.dart';
4+
5+
import '../pattern/shape.dart';
6+
7+
class Shapes with IterableMixin<Shape> {
8+
final List<Shape> _shapes;
9+
10+
Shapes(this._shapes);
11+
12+
void add(Shape shape) {
13+
_shapes.add(shape);
14+
onAddShapeEvent._emit();
15+
}
16+
17+
@override
18+
Iterator<Shape> get iterator => _shapes.iterator;
19+
20+
final onAddShapeEvent = Event();
21+
}
22+
23+
class Event extends ChangeNotifier {
24+
void _emit() => notifyListeners();
25+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import 'dart:async';
2+
import 'dart:ui';
3+
4+
import 'package:flutter/foundation.dart';
5+
6+
import '../mixin/icon_box_mixin.dart';
7+
import '../pattern/tool_factory.dart';
8+
9+
class Tools {
10+
final List<ToolFactory> factories;
11+
final List<Color> colors;
12+
13+
final activeFactory = ValueNotifier<ToolFactory?>(null);
14+
15+
final activeColor = ValueNotifier(Color(0x0FFFFFFFF));
16+
17+
Future<bool> get iconsReady => _iconsInitCompleter.future;
18+
19+
Tools({required this.factories, required this.colors}) {
20+
_initIconsFromShapes();
21+
22+
if (factories.isNotEmpty) {
23+
activeFactory.value = factories.first;
24+
}
25+
26+
if (colors.isNotEmpty) {
27+
activeColor.value = colors.first;
28+
}
29+
}
30+
31+
final _iconsInitCompleter = Completer<bool>();
32+
33+
void _initIconsFromShapes() async {
34+
await Future.wait([
35+
for (final factory in factories)
36+
(factory as IconBoxMixin).updateIcon(activeColor.value),
37+
]);
38+
_iconsInitCompleter.complete(Future.value(true));
39+
}
40+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import 'dart:ui';
2+
3+
import '../mixin/icon_box_mixin.dart';
4+
import '../pattern/tool_factory.dart';
5+
import '../shapes/circle_shape.dart';
6+
import '../pattern/shape.dart';
7+
8+
class CircleFactory extends ToolFactory with IconBoxMixin {
9+
@override
10+
Shape createShape(double x, double y, Color color) {
11+
return CircleShape(
12+
radius: 50,
13+
x: x,
14+
y: y,
15+
color: color,
16+
);
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import 'dart:ui';
2+
3+
import '../mixin/icon_box_mixin.dart';
4+
import '../pattern/tool_factory.dart';
5+
import '../pattern/shape.dart';
6+
import '../shapes/line_shape.dart';
7+
8+
class LineFactory extends ToolFactory with IconBoxMixin {
9+
@override
10+
Shape createShape(double x, double y, Color color) {
11+
return LineShape(
12+
length: 100,
13+
x: x,
14+
y: y,
15+
color: color,
16+
);
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import 'dart:ui';
2+
3+
import '../mixin/icon_box_mixin.dart';
4+
import '../pattern/tool_factory.dart';
5+
import '../pattern/shape.dart';
6+
import '../shapes/star_shape.dart';
7+
8+
class StarFactory extends ToolFactory with IconBoxMixin {
9+
@override
10+
Shape createShape(double x, double y, Color color) {
11+
return StarShape(
12+
radius: 80,
13+
x: x,
14+
y: y,
15+
color: color,
16+
);
17+
}
18+
}

0 commit comments

Comments
 (0)