diff --git a/CHANGELOG.md b/CHANGELOG.md index 52b67b9..038fa50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.16.0 +- Add complex example of an Observer pattern, connected to a Flutter application. +- Add new branch "web-demos" for online examples. + ## 0.15.0 - Add second "Observer" example. This example was created to be used in a more complex example. diff --git a/README.md b/README.md index c7cbbda..3e1ca32 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ It contains **Dart** examples for all classic **GoF** design patterns. - [ ] [**Iterator**](https://refactoring.guru/design-patterns/iterator) - [ ] [**Mediator**](https://refactoring.guru/design-patterns/mediator) - [x] [**Memento**](https://refactoring.guru/design-patterns/memento) - [[Conceptual](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/memento/conceptual)] - - [x] [**Observer**](https://refactoring.guru/design-patterns/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)] + - [x] [**Observer**](https://refactoring.guru/design-patterns/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**](https://refactoring.guru/design-patterns/state) - [ ] [**Template Method**](https://refactoring.guru/design-patterns/template-method) - [ ] [**Visitor**](https://refactoring.guru/design-patterns/visitor) @@ -33,6 +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**. ## Contributor's Guide @@ -65,6 +66,12 @@ Here's a style guide which might help you to keep your changes consistent with o Don't be scared and ignore the non-English part of such comments. If you want to change something in a comment like this, then do it. Even if you do it wrong, we'll tell you how to fix it during the Pull Request. +### Build Flutter examples +```batch +cd root directory +flutter build web -t bin\main.dart --web-renderer html +``` + ## License This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License. diff --git a/bin/main.dart b/bin/main.dart index 3865bb7..cff5656 100644 --- a/bin/main.dart +++ b/bin/main.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; +import '../patterns/observer/subscriber_flutter_widget/main.dart'; void main() { - runApp(const MyApp()); + runApp(MyApp()); } class MyApp extends StatelessWidget { @@ -11,10 +12,11 @@ class MyApp extends StatelessWidget { Widget build(BuildContext context) { return MaterialApp( title: 'Refactoring Guru: Flutter launcher', - theme: ThemeData( - primarySwatch: Colors.pink - ), - home: Container(), + theme: ThemeData(primarySwatch: Colors.pink), + initialRoute: '/observer/subscriber_flutter_widget', + routes: { + '/observer/subscriber_flutter_widget': (_) => SubscriberFlutterApp(), + }, ); } } diff --git a/patterns/observer/subscriber_flutter_widget/README.md b/patterns/observer/subscriber_flutter_widget/README.md new file mode 100644 index 0000000..71ca3b9 --- /dev/null +++ b/patterns/observer/subscriber_flutter_widget/README.md @@ -0,0 +1,44 @@ +# Observer pattern +**Observer** is a behavioral design pattern that lets you define a subscription mechanism to notify +multiple objects about any events that happen to the object they’re observing. + +Tutorial: [here](https://refactoring.guru/design-patterns/observer). + +## Subscriber Flutter Widget example +This is a complex example of an Observer pattern, connected to a Flutter application. The example includes, +the previously implemented **AppObserver** example pattern, which you can see [here](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/observer/app_observer). + +### Diagram: +![image](https://user-images.githubusercontent.com/8049534/152418114-f040bcb4-3bf5-4581-8b9b-a264e103ff76.png) + +### Sequence +![image](https://user-images.githubusercontent.com/8049534/152418299-3f6f3e5d-7132-42bc-9b27-11ed53ca6434.png) + +### Client code: +```dart +void main() { + // widget that generates a new event + ElevatedButton( + child: Text('Generate new hash'), + onPressed: () { + final hash = 'some hash'; + observer.notify(NewHashEvent(hash)); + }, + ); + + // widget event consumer NewHashEvent + SubscriberWidget( + observer: observer, + builder: (context, event) { + return Text( + event?.newHash ?? 'Hash no generated' , + ); + }, + ); +} +``` + +### Online demo: +Click on the picture to see a [demo](https://ilopx.github.io/design-patterns-dart/#/observer/subscriber_flutter_widget). + +[![image](https://user-images.githubusercontent.com/8049534/152419178-f40a07fd-728d-4f99-befa-0935bbdd7b71.png)](https://ilopx.github.io/design-patterns-dart/#/observer/subscriber_flutter_widget) diff --git a/patterns/observer/subscriber_flutter_widget/events/new_hash_event.dart b/patterns/observer/subscriber_flutter_widget/events/new_hash_event.dart new file mode 100644 index 0000000..0cbf2f5 --- /dev/null +++ b/patterns/observer/subscriber_flutter_widget/events/new_hash_event.dart @@ -0,0 +1,7 @@ +import '../../app_observer/observer/event.dart'; + +class NewHashEvent extends Event { + final String newHash; + + NewHashEvent(this.newHash); +} diff --git a/patterns/observer/subscriber_flutter_widget/main.dart b/patterns/observer/subscriber_flutter_widget/main.dart new file mode 100644 index 0000000..87f7e35 --- /dev/null +++ b/patterns/observer/subscriber_flutter_widget/main.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import '../app_observer/observer/app_observer.dart'; +import 'widgets/hash_generator_widget.dart'; +import 'widgets/hash_user_widget.dart'; + +class SubscriberFlutterApp extends StatefulWidget { + @override + State createState() => _SubscriberFlutterAppState(); +} + +class _SubscriberFlutterAppState extends State { + final observer = AppObserver(); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + HashUserWidget(observer: observer), + HashGeneratorWidget(observer: observer), + ], + ), + ), + ); + } +} diff --git a/patterns/observer/subscriber_flutter_widget/subscriber/subscriber_widget.dart b/patterns/observer/subscriber_flutter_widget/subscriber/subscriber_widget.dart new file mode 100644 index 0000000..daef892 --- /dev/null +++ b/patterns/observer/subscriber_flutter_widget/subscriber/subscriber_widget.dart @@ -0,0 +1,46 @@ +import 'package:flutter/widgets.dart'; + +import '../../app_observer/observer/app_observer.dart'; +import '../../app_observer/observer/event.dart'; + +class SubscriberWidget extends StatefulWidget { + final AppObserver observer; + final Widget Function(BuildContext buildContext, T? event) builder; + + const SubscriberWidget({ + Key? key, + required this.builder, + required this.observer, + }) : super(key: key); + + @override + State> createState() { + return _SubscriberWidgetState(); + } +} + +class _SubscriberWidgetState + extends State> { + T? _event; + + @override + void initState() { + widget.observer.subscribe(update); + super.initState(); + } + + @override + void dispose() { + widget.observer.unsubscribe(update); + super.dispose(); + } + + void update(T event) { + setState(() => _event = event); + } + + @override + Widget build(BuildContext context) { + return widget.builder(context, _event); + } +} diff --git a/patterns/observer/subscriber_flutter_widget/widgets/hash_generator_widget.dart b/patterns/observer/subscriber_flutter_widget/widgets/hash_generator_widget.dart new file mode 100644 index 0000000..e19caa2 --- /dev/null +++ b/patterns/observer/subscriber_flutter_widget/widgets/hash_generator_widget.dart @@ -0,0 +1,28 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; + +import '../../app_observer/observer/app_observer.dart'; +import '../events/new_hash_event.dart'; + +class HashGeneratorWidget extends StatelessWidget { + final AppObserver observer; + + const HashGeneratorWidget({ + Key? key, + required this.observer, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return ElevatedButton( + child: Text('Generate new hash'), + onPressed: onHashGenerate, + ); + } + + void onHashGenerate() { + final hash = Random().nextDouble().hashCode.toString(); + observer.notify(NewHashEvent(hash)); + } +} diff --git a/patterns/observer/subscriber_flutter_widget/widgets/hash_user_widget.dart b/patterns/observer/subscriber_flutter_widget/widgets/hash_user_widget.dart new file mode 100644 index 0000000..0b6458c --- /dev/null +++ b/patterns/observer/subscriber_flutter_widget/widgets/hash_user_widget.dart @@ -0,0 +1,23 @@ +import 'package:flutter/widgets.dart'; + +import '../../app_observer/observer/app_observer.dart'; +import '../events/new_hash_event.dart'; +import '../subscriber/subscriber_widget.dart'; + +class HashUserWidget extends StatelessWidget { + final AppObserver observer; + + const HashUserWidget({Key? key, required this.observer}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SubscriberWidget( + observer: observer, + builder: (context, event) { + return Text( + event?.newHash ?? 'Hash no generated', + ); + }, + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index c516e54..fcabe61 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: design_patterns_dart description: Dart examples for all classic GoF design patterns. -version: 0.15.0 +version: 0.16.0 homepage: https://refactoring.guru/design-patterns repository: https://github.com/RefactoringGuru/design-patterns-dart issue_tracker: https://github.com/RefactoringGuru/design-patterns-dart/issue diff --git a/web/index.html b/web/index.html index 0e76fb2..d2d6493 100644 --- a/web/index.html +++ b/web/index.html @@ -1,104 +1,140 @@ - + + + + - This is a placeholder for base href that will be replaced by the value of - the `--base-href` argument provided to `flutter build`. - --> - + + - - - + flutter_launcher + + - - + }); + + // If service worker doesn't succeed in a reasonable amount of time, + // fallback to plaint + diff --git a/web/logo-screen.png b/web/logo-screen.png new file mode 100644 index 0000000..d5c9c2f Binary files /dev/null and b/web/logo-screen.png differ