Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
b1dbf93
Add empty classic flutter app.
ilopX Feb 13, 2022
087e7c9
Add flutter right panel properties.
ilopX Feb 13, 2022
026ea37
Add fake shape painter.
ilopX Feb 13, 2022
4b9695b
Add mouseUp & mouseMove events.
ilopX Feb 14, 2022
a515748
Create Editor class.
ilopX Feb 14, 2022
6b89245
Add black color to palette.
ilopX Feb 14, 2022
301906e
Add shape class.
ilopX Feb 14, 2022
3a5bb4a
Add Shapes.
ilopX Feb 14, 2022
95ff8c6
Add Manipulator.
ilopX Feb 14, 2022
4676aa4
Add ColorsWidget.
ilopX Feb 14, 2022
879e467
Add SubscriberWidget to property panel.
ilopX Feb 14, 2022
a60f741
Format main.dart.
ilopX Feb 14, 2022
4e83787
Move Manipulator and Shape out of Editor.
ilopX Feb 14, 2022
b5246bf
Add visible args to Shape.
ilopX Feb 14, 2022
04dd1d6
Add backup & replace editor to app.
ilopX Feb 14, 2022
6edfaf2
Fix deploy_flutter: remove "&" from commit text.
ilopX Feb 15, 2022
7d03cfd
Add separate project directories.
ilopX Feb 15, 2022
843bb16
Add SelectedShape class.
ilopX Feb 15, 2022
04a4d26
Move "paintSelectFrame" from manipulator to "SelectedShape" class.
ilopX Feb 15, 2022
bf9d0e9
Add SnapshotWidget.
ilopX Feb 16, 2022
95f88e7
Fix vertical space.
ilopX Feb 16, 2022
cb0c152
Fix right panel width & add space line.
ilopX Feb 16, 2022
086add1
Remove SubscriberWidget from ShapeProperties.
ilopX Feb 16, 2022
dcb5559
Add separate method: "_buildSaveStateButton", "_buildDescription" to …
ilopX Feb 16, 2022
f6f0223
Add separate class Snapshot.
ilopX Feb 16, 2022
46283bb
Remove initialization to MementoEditorApplication.
ilopX Feb 16, 2022
c26c817
Rename SnapshotWidget to MementoWidget.
ilopX Feb 16, 2022
57802be
Add "Caretaker".
ilopX Apr 26, 2022
a56469f
add: save/restore selected shape.
ilopX Apr 26, 2022
22359db
Refactoring originator.
ilopX Apr 26, 2022
1552c21
Rename variable selected to selectedShape.
ilopX Apr 26, 2022
89bee4e
Make Shape setter fields is private.
ilopX Apr 26, 2022
aa2e582
Rename SelectedShape to ActiveShape.
ilopX Apr 26, 2022
2b74748
Rename memento event.
ilopX Apr 26, 2022
3ae4283
Add README.md.
ilopX Apr 26, 2022
849a2c0
Bump version 0.18.0.
ilopX Apr 26, 2022
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 0.18.0
- Add Memento Editor.

## 0.17.16 - refactoring
- Simplifying the ternary construction.
- Remove multiline comment from main README.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ It contains **Dart** examples for all classic **GoF** design patterns.
- [ ] Interpreter
- [ ] **Iterator**
- [ ] **Mediator**
- [x] **Memento** - [[Conceptual](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/memento/conceptual)]
- [x] **Memento** - [[Conceptual](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/memento/conceptual)] [[Memento Editor](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/memento/memento_editor)]
- [x] **Observer** - [[Open-Close Editor Events](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/observer/open_close_editor_events)] [[AppObserver](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/observer/app_observer)] [[Subscriber Flutter Widget](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/observer/subscriber_flutter_widget)]
- [ ] **State**
- [ ] **Template Method**
Expand All @@ -33,7 +33,7 @@ It contains **Dart** examples for all classic **GoF** design patterns.
## Requirements

The examples were written in **Dart 2.15**.
Some complex examples require **Flutter 2.15.0**.
Some complex examples require **Flutter 2.12**.

## Contributor's Guide

Expand Down
2 changes: 1 addition & 1 deletion bin/deploy_flutter_demos.dart
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ Future<String> repositoryOriginUrl(Directory workingDir) async {
Future<String> lastProjectCommit() async {
final rawCommit =
await cmd('git log -1 --pretty=%B', workingDirectory: projectDir);
final formatCommit = rawCommit.replaceAll(' ', '_');
final formatCommit = rawCommit.replaceAll(' ', '_').replaceAll('&', '');
return 'auto_commit:_$formatCommit';
}

Expand Down
4 changes: 3 additions & 1 deletion bin/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import '../patterns/observer/subscriber_flutter_widget/main.dart';
import '../patterns/adapter/flutter_adapter/main.dart';
import '../patterns/memento/memento_editor/main.dart';

void main() {
runApp(MyApp());
Expand All @@ -12,10 +13,11 @@ class MyApp extends StatelessWidget {
return MaterialApp(
title: 'Refactoring Guru: Flutter launcher',
theme: ThemeData(primarySwatch: Colors.pink),
initialRoute: '/adapter/flutter_adapter',
initialRoute: '/memento/flutter_memento_editor',
routes: {
'/observer/subscriber_flutter_widget': (_) => SubscriberFlutterApp(),
'/adapter/flutter_adapter': (_) => FlutterAdapterApp(),
'/memento/flutter_memento_editor': (_) => FlutterMementoEditorApp(),
},
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,16 @@ class ClassicAppRenderObject extends RenderBox {
@override
void handleEvent(PointerEvent event, covariant BoxHitTestEntry entry) {
if (event is PointerHoverEvent || event is PointerMoveEvent) {
} else if (event is PointerDownEvent) {
if (event.buttons == kPrimaryMouseButton) {
_classicApp.onMouseDown();
} else if (event.buttons == kSecondaryMouseButton) {}
else if (event.buttons == kMiddleMouseButton) {}
_classicApp.onMouseMove(event.position.dx, event.position.dy);
} else if (event is PointerScrollEvent) {
_classicApp.onPointerWheel(event.scrollDelta.dx, event.scrollDelta.dy);
} else if (event is PointerDownEvent) {
if (event.buttons == kPrimaryMouseButton) {
_classicApp.onMouseDown(event.position.dx, event.position.dy);
} else if (event.buttons == kSecondaryMouseButton) {
} else if (event.buttons == kMiddleMouseButton) {}
} else if (event is PointerUpEvent) {
_classicApp.onMouseUp();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import 'repaint_compatible.dart';
abstract class ClassicApp implements RepaintCompatible {
final events = AppObserver();

void onMouseDown() {}
void onMouseDown(double x, double y) {}

void onMouseUp() {}

void onMouseMove(double x, double y) {}

void onPointerWheel(double deltaX, double deltaY) {}

Expand Down
2 changes: 1 addition & 1 deletion patterns/adapter/flutter_adapter/client_app/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class App extends ClassicApp {
}

@override
void onMouseDown() {
void onMouseDown(_, __) {
textColoring.color = colorRules.nextColor(textColoring.color);
}

Expand Down
48 changes: 48 additions & 0 deletions patterns/memento/memento_editor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Memento pattern
Memento is a behavioral design pattern that lets you save and restore the previous state of an
object without revealing the details of its implementation.

Tutorial: [here](https://refactoring.guru/design-patterns/memento).

### Online demo:
Click on the picture to see a [demo](https://RefactoringGuru.github.io/design-patterns-dart/#/memento/flutter_memento_editor).

[![image](https://user-images.githubusercontent.com/8049534/165401175-88bc4593-4624-45b4-8c03-6f1390ed771a.png)](https://refactoringguru.github.io/design-patterns-dart/#/memento/flutter_memento_editor)


### Dependency Patterns
This complex example includes these implementations:
- [[AppObserver](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/observer/app_observer)]
- [[SubscriberWidget](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/observer/subscriber_flutter_widget)]

### Diagram:
![image](https://user-images.githubusercontent.com/8049534/165399085-06835617-8ef1-4e2f-930f-03d730433afb.png)

### Client code:
```dart
class MementoEditorApplication {
final editor = Editor();
final caretaker = Caretaker();

void createDefaultShapes() {/*...*/}

void saveState() {
final snapshot = editor.backup();

if (caretaker.isSnapshotExists(snapshot)) {
return;
}

final memento = Memento(DateTime.now(), snapshot);
caretaker.addMemento(memento);
editor.events.notify(MementoCreateEvent());
}

void restoreState(Memento memento) {
editor
..unSelect()
..restore(memento.snapshot)
..repaint();
}
}
```
44 changes: 44 additions & 0 deletions patterns/memento/memento_editor/application.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import 'dart:math';

import 'editor/memento_create_event.dart';
import 'editor/editor.dart';
import 'memento_pattern/caretaker.dart';
import 'memento_pattern/memento.dart';
import 'shapes/shape.dart';

class MementoEditorApplication {
final editor = Editor();
final caretaker = Caretaker();

MementoEditorApplication() {
createDefaultShapes();
}

void createDefaultShapes() {
const radius = 300.0;
for (var i = 0; i < 7; i++) {
final x = 60 + radius + cos(i / 1.15) * radius;
final y = 60 + radius + sin(i / 1.15) * radius;
editor.shapes.add(Shape(x, y));
}
}

void saveState() {
final snapshot = editor.backup();

if (caretaker.isSnapshotExists(snapshot)) {
return;
}

final memento = Memento(DateTime.now(), snapshot);
caretaker.addMemento(memento);
editor.events.notify(MementoCreateEvent());
}

void restoreState(Memento memento) {
editor
..unSelect()
..restore(memento.snapshot)
..repaint();
}
}
22 changes: 22 additions & 0 deletions patterns/memento/memento_editor/editor/editor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'dart:ui';

import '../../../adapter/flutter_adapter/classic_app/classic_app.dart';
import '../memento_pattern/originator.dart';
import '../shapes/shapes.dart';
import 'manipulator.dart';

class Editor extends ClassicApp with Manipulator, Shapes, Originator {
@override
void onPaint(Canvas canvas, Size canvasSize) {
_paintBackground(canvas, canvasSize);
paintShapes(canvas);
activeShape?.paintSelectionBox(canvas);
}

void _paintBackground(Canvas canvas, Size canvasSize) {
canvas.drawRect(
Offset.zero & canvasSize,
Paint()..color = Color(0xff404040),
);
}
}
42 changes: 42 additions & 0 deletions patterns/memento/memento_editor/editor/manipulator.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import '../../../adapter/flutter_adapter/classic_app/classic_app.dart';
import '../shapes/shapes.dart';

mixin Manipulator implements ClassicApp, Shapes {
var _isMouseDown = false;

@override
void onMouseDown(double x, double y) {
_isMouseDown = true;
final currSelection = activeShape;

select(x, y);

if (currSelection == activeShape) {
return;
}

if (activeShape == null) {
unSelect();
}

repaint();
}

@override
void onMouseMove(double x, double y) {
if (_isMouseDown) {
activeShape?.dragTo(x, y);
repaint();
}
}

@override
void onPointerWheel(double deltaX, double deltaY) {
activeShape?.changeSize(deltaY / 5);
}

@override
void onMouseUp() {
_isMouseDown = false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import '../../../observer/app_observer/observer/event.dart';

class MementoCreateEvent extends Event {}
33 changes: 33 additions & 0 deletions patterns/memento/memento_editor/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:flutter/material.dart';

import '../../adapter/flutter_adapter/adapter/classic_app_adapter_widget.dart'
as adapter;
import 'application.dart';
import 'widgets/right_panel_widget.dart';


class FlutterMementoEditorApp extends StatefulWidget {
@override
State<FlutterMementoEditorApp> createState() =>
_FlutterMementoEditorAppState();
}

class _FlutterMementoEditorAppState extends State<FlutterMementoEditorApp> {
final app = MementoEditorApplication();

@override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: [
Expanded(
child: adapter.ClassicAppAdapterWidget(
classicApp: app.editor,
),
),
RightPanelWidget(app: app),
],
),
);
}
}
18 changes: 18 additions & 0 deletions patterns/memento/memento_editor/memento_pattern/caretaker.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import 'memento.dart';
import 'snapshot.dart';

class Caretaker {
final _mementoList = <Memento>[];

List<Memento> get list => List<Memento>.unmodifiable(_mementoList);

void addMemento(Memento memento) {
_mementoList.add(memento);
}

bool isSnapshotExists(Snapshot snapshot) {
return list.any(
(e) => e.snapshot == snapshot,
);
}
}
9 changes: 9 additions & 0 deletions patterns/memento/memento_editor/memento_pattern/memento.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

import 'snapshot.dart';

class Memento {
final DateTime time;
final Snapshot snapshot;

Memento(this.time, this.snapshot);
}
Loading