Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
753f2b5
PaginatedDataTable (part 1) (#4306)
Hixie Jun 1, 2016
ddb441d
Improve change notifier (#4747)
abarth Jun 24, 2016
70d66bc
Extract a Listenable base class from Animation and ChangeNotifier (#5…
abarth Sep 15, 2016
b928281
Listenable.merge (#7256)
Hixie Dec 15, 2016
23dda28
Allow nulls in `Listenable.merge` (#7355)
Hixie Jan 5, 2017
5a09f6c
Fix several minor bugs and add many tests (#7506)
abarth Jan 17, 2017
ed19257
Add more asserts and docs to ChangeNotifier. (#7513)
Hixie Jan 17, 2017
8659b4b
Strengthen animation listener iteration patterns (#7537)
abarth Jan 19, 2017
9be184a
Revert "Strengthen animation listener iteration patterns" (#7552)
abarth Jan 19, 2017
b3b3ff8
Strengthen animation listener iteration patterns (#7566)
abarth Jan 20, 2017
f758e93
Various documentation fixes. (#7726)
Hixie Jan 30, 2017
4adb1f3
Add ValueNotifier (#8463)
abarth Feb 28, 2017
3a4717c
Animation Demo performance tweaks (#8586)
Mar 6, 2017
cea97ac
Remove imports of meta (#9081)
xster Mar 29, 2017
aa8474e
Change foundation references in foundation to meta (#9107)
xster Mar 31, 2017
bd82d72
Rationalize text input widgets (#9119)
abarth Apr 2, 2017
5b6a595
Better toStrings for Listenable subclasses (#9244)
Hixie Apr 6, 2017
75fd887
Simplify change notifier toString and handle nulls (#9368)
xster Apr 13, 2017
2521f2e
More docs. (#10214)
Hixie May 24, 2017
1d927b5
More documentation (#10589)
Hixie Jun 9, 2017
fbc785f
Change all ocurrences of '$runtimeType#$hashCode' to use the idAndTyp…
jacob314 Jun 21, 2017
f3fe60a
Revert "Change all ocurrences of '$runtimeType#$hashCode' to use the …
jacob314 Jun 21, 2017
0370c2c
Change all occurrences of '$runtimeType#$hashCode' to use the describ…
jacob314 Jun 21, 2017
bd4b999
Add Diagnosticable base class and add documentation. (#11458)
jacob314 Aug 3, 2017
02e2d32
use bool in assert (#12170)
a14n Sep 21, 2017
19a9b1b
Fix spelling errors in all the dartdocs. (#13061)
gspencergoog Nov 17, 2017
8aa7aca
Fix the confusing-zero case with NestedScrollView. (#14133)
Hixie Jan 19, 2018
f9d12c6
some whitespace cleanup (#14443)
a14n Feb 2, 2018
c8ae2f8
Add a hasListeners to ChangeNotifier (#14946)
Hixie Mar 1, 2018
e0105b9
Unnecessary new (#20138)
a14n Sep 12, 2018
84440f2
[H] Created a variant of InheritedWidget specifically for Listenables…
Hixie Oct 27, 2018
8b034f2
Allow ChangeNotifier to be mixed in again (#23631)
Hixie Oct 30, 2018
3cd601c
make see also sections uniform (#25513)
a14n Dec 18, 2018
003ce83
Fix Listenable.merge to not leak (#26313)
goderbauer Jan 10, 2019
2dca3d3
Remove all obsolete "// ignore:" (#27271)
goderbauer Jan 30, 2019
e3335e8
[H] Add ImageStreamCompleter.hasListeners (and cleanup) (#25865)
Hixie Jan 31, 2019
e75fc4e
Add missing trailing commas (#28673)
a14n Mar 1, 2019
407052a
fix block formatting (#29051)
a14n Mar 9, 2019
592b64b
some spaces formatting (#29452)
a14n Mar 20, 2019
bd2c3ff
Be more explicit when ValueNotifier notifies (#30461)
goderbauer Apr 4, 2019
1064ef9
Refactor core uses of FlutterError. (#30983)
jacob314 May 1, 2019
599a359
Enable web foundation tests (#34032)
Jun 9, 2019
a1dc2dd
fix some bad indentations (#41172)
a14n Sep 24, 2019
5f22f52
Add more structure to errors (continuation of #34684) (#42640)
Oct 28, 2019
075b144
License update (#45373)
Hixie Nov 27, 2019
46c3bbe
enable lint prefer_final_in_for_each (#47724)
a14n Jan 7, 2020
120772a
Avoid using FlutterError.fromParts when possible (#43696)
albertusdev Feb 20, 2020
2c68313
Add sample for InheritedNotifier, convert two others to DartPa… (#52349)
gspencergoog Mar 10, 2020
4ee3d62
Revise Action API (#42940)
gspencergoog Apr 7, 2020
18139a9
Skip Audits (2) (#53837)
Piinks Apr 8, 2020
4ef2c3b
Opt out nnbd in packages/flutter (#59186)
a14n Jun 11, 2020
2180621
migrate foundation to nullsafety (#61188)
a14n Jul 15, 2020
d9976c4
Minor doc updates (#62008)
tvolkert Jul 23, 2020
2538ba6
[null-safety] update to several framework test cases/APIs for null as…
Aug 12, 2020
9e3eaf5
Use a LinkedList to improve the performance of ChangeNotifier (#62330)
rrousselGit Aug 26, 2020
caaf888
Migrate foundation test to nullsafety (#62616)
dkwingsmt Oct 5, 2020
049ecbd
Mark keys that match a shortcut, but have no action defined as "not h…
gspencergoog Oct 19, 2020
af72157
enable prefer_function_declarations_over_variables lint (#77398)
goderbauer Mar 6, 2021
70a1d53
add missing trailing commas (#79299)
a14n Mar 30, 2021
bcfd499
Improve the performances of ChangeNotifier (#71947)
letsar Apr 14, 2021
77d3dc2
Treat some exceptions as unhandled when a debugger is attached (#78649)
goderbauer Apr 15, 2021
f476d22
add trailing commas in flutter/test/{foundation,gestures} (#80926)
a14n Apr 22, 2021
ae484e4
Enable unnecessary_null_checks lint (#82084)
Abhishek01039 May 14, 2021
8920924
Add space before curly parentheses. (#85306)
asashour Jul 1, 2021
55352a4
Ban sync*/async* from user facing code (#95050)
dnfield Dec 12, 2021
0867a08
Enable no_leading_underscores_for_local_identifiers (#96422)
goderbauer Jan 21, 2022
cf527c8
Allow remove listener on disposed change notifier (#97988)
chunhtai Feb 9, 2022
00c6aee
Add explanation to ChangeNotifier (#98295)
chunhtai Feb 16, 2022
ad97e24
feat: Added docstring examples to AnimatedBuilder and ChangeNotifier …
albertodev01 Feb 28, 2022
f41901a
Fix `deprecated_new_in_comment_reference` for `material` library (#10…
guidezpl Mar 21, 2022
752591f
super parameters for framework (#100905)
goderbauer Apr 14, 2022
c95bf13
Add ShortcutsRegistry (#103456)
gspencergoog May 19, 2022
c0d40af
Use `curly_braces_in_flow_control_structures` for `foundation`, `gest…
guidezpl May 25, 2022
7317aae
Switch debugAssertNotDisposed to be a static (#104772)
gspencergoog May 31, 2022
badb5ec
Export public API types from foundation/*.dart library. (#105648)
a14n Jun 9, 2022
1351c01
Export public API types from foundation/scheduler/gestures/semantics …
a14n Jun 24, 2022
1e6f91e
Update docs on ChangeNotifier.dispose and KeepAliveHandle.release (#1…
dnfield Jul 26, 2022
11835bb
Can call ChangeNotifier.hasListeners after disposed (#108931)
chunhtai Aug 4, 2022
e114036
Create class MemoryAllocations. (#110230)
polina-c Sep 10, 2022
856914a
Fix references to symbols to use brackets instead of backticks (#111331)
gspencergoog Sep 12, 2022
2de98b9
Fix performance regression. (#111615)
polina-c Sep 15, 2022
1179330
Instrument State, Layer, RenderObject and Element. (#111328)
polina-c Sep 20, 2022
ddf33c6
Disallow dispose during listener callback (#114530)
chunhtai Nov 18, 2022
a55eb7c
Add ListenableBuilder with examples (#116543)
gspencergoog Dec 7, 2022
52c3962
Bump lower Dart SDK constraints to 3.0 & add class modifiers (#122546)
goderbauer Mar 21, 2023
32cf983
Documentation improvements (#122787)
Hixie Mar 22, 2023
550efcb
Define testWidgetsWithLeakTracking. (#125063)
polina-c May 4, 2023
0977b2a
Add spaces after flow control statements (#126320)
tgucio May 15, 2023
f61d571
Unpin leak_tracker and handle breaking changes in API. (#132352)
polina-c Aug 14, 2023
795dc97
Enable ChangeNotifier clients to dispatch event of object creation in…
polina-c Aug 23, 2023
6b04285
Users of ChangeNotifier should dispatch event of object creation in c…
polina-c Aug 24, 2023
a0b459b
Resolve breaking change of adding a method to ChangeNotifier. (#134953)
polina-c Sep 18, 2023
bc766be
Revert "Resolve breaking change of adding a method to ChangeNotifier.…
zanderso Sep 18, 2023
f0a1d75
Reland Resolve breaking change of adding a method to ChangeNotifier. …
polina-c Sep 19, 2023
98b3ef0
Remove usage of testWidgetsWithLeakTracking. (#140239)
polina-c Dec 15, 2023
c9a5ebe
Rename MemoryAllocations to FlutterMemoryAllocations. (#140623)
polina-c Jan 2, 2024
419db80
Allow `Listenable.merge()` to use any iterable (#143675)
nate-thegrate Feb 26, 2024
99f64b9
Docimports for foundation (#151119)
goderbauer Jul 2, 2024
95ac2da
Initial empty repository
chadj-at-google Apr 19, 2013
bae7241
Trigger Build (#160476)
jtmcdole Dec 17, 2024
7b46eeb
Auto-format Framework (#160545)
goderbauer Dec 19, 2024
927822b
Clean up leak tracker instrumentation tech debt. (#164070)
polina-c Feb 25, 2025
55ed68c
Flutter test cleanup (#170891)
kevmoo Jun 24, 2025
0a91f20
Bump Dart to 3.8 and reformat (#171703)
Piinks Jul 7, 2025
8386a09
Modernize framework lints (#179089)
Piinks Nov 26, 2025
65e165d
Improve documentation about ValueNotifier's behavior (#179870)
AbdeMohlbi Jan 6, 2026
6cd45de
Update doc in foundation to match the style guide (#181972)
chunhtai Feb 6, 2026
a2354b4
Adds listenable package
chunhtai Jun 11, 2026
da26a37
addressing comments
chunhtai Jul 1, 2026
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
6 changes: 6 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,14 @@
- any-glob-to-any-file:
- packages/vector_math/**/*

'p: listen':
- changed-files:
- any-glob-to-any-file:
- packages/listen/**/*

'triage-framework':
- changed-files:
- any-glob-to-any-file:
- packages/vector_math/**/*
- packages/flutter_hook_config/**/*
- packages/listen/**/*
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ These are the packages hosted in this repository:
|---------|-----|--------|-------|--------|---------------|
| [flutter\_hook\_config](./packages/flutter_hook_config/) | [![pub package](https://img.shields.io/pub/v/flutter_hook_config.svg)](https://pub.dev/packages/flutter_hook_config) | [![pub points](https://img.shields.io/pub/points/flutter_hook_config)](https://pub.dev/packages/flutter_hook_config/score) | [![downloads](https://img.shields.io/pub/dm/flutter_hook_config)](https://pub.dev/packages/flutter_hook_config/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20flutter_hook_config?label=)](https://github.com/flutter/flutter/labels/p%3A%20flutter_hook_config) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/core-packages/p%3A%20flutter_hook_config?label=)](https://github.com/flutter/core-packages/labels/p%3A%20flutter_hook_config) |
| [flutter\_template\_images](./packages/flutter_template_images/) | [![pub package](https://img.shields.io/pub/v/flutter_template_images.svg)](https://pub.dev/packages/flutter_template_images) | [![pub points](https://img.shields.io/pub/points/flutter_template_images)](https://pub.dev/packages/flutter_template_images/score) | [![downloads](https://img.shields.io/pub/dm/flutter_template_images)](https://pub.dev/packages/flutter_template_images/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20flutter_template_images?label=)](https://github.com/flutter/flutter/labels/p%3A%20flutter_template_images) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/core-packages/p%3A%20flutter_template_images?label=)](https://github.com/flutter/core-packages/labels/p%3A%20flutter_template_images) |
| [listen](./packages/listen/) | [![pub package](https://img.shields.io/pub/v/listen.svg)](https://pub.dev/packages/listen) | [![pub points](https://img.shields.io/pub/points/listen)](https://pub.dev/packages/listen/score) | [![downloads](https://img.shields.io/pub/dm/listen)](https://pub.dev/packages/listen/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20listen?label=)](https://github.com/flutter/flutter/labels/p%3A%20listen) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/core-packages/p%3A%20listen?label=)](https://github.com/flutter/core-packages/labels/p%3A%20listen) |
| [multicast\_dns](./packages/multicast_dns/) | [![pub package](https://img.shields.io/pub/v/multicast_dns.svg)](https://pub.dev/packages/multicast_dns) | [![pub points](https://img.shields.io/pub/points/multicast_dns)](https://pub.dev/packages/multicast_dns/score) | [![downloads](https://img.shields.io/pub/dm/multicast_dns)](https://pub.dev/packages/multicast_dns/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20multicast_dns?label=)](https://github.com/flutter/flutter/labels/p%3A%20multicast_dns) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/core-packages/p%3A%20multicast_dns?label=)](https://github.com/flutter/core-packages/labels/p%3A%20multicast_dns) |
| [mustache\_template](./third_party/packages/mustache_template/) | [![pub package](https://img.shields.io/pub/v/mustache_template.svg)](https://pub.dev/packages/mustache_template) | [![pub points](https://img.shields.io/pub/points/mustache_template)](https://pub.dev/packages/mustache_template/score) | [![downloads](https://img.shields.io/pub/dm/mustache_template)](https://pub.dev/packages/mustache_template/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20mustache_template?label=)](https://github.com/flutter/flutter/labels/p%3A%20mustache_template) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/core-packages/p%3A%20mustache_template?label=)](https://github.com/flutter/core-packages/labels/p%3A%20mustache_template) |
| [standard\_message\_codec](./packages/standard_message_codec/) | [![pub package](https://img.shields.io/pub/v/standard_message_codec.svg)](https://pub.dev/packages/standard_message_codec) | [![pub points](https://img.shields.io/pub/points/standard_message_codec)](https://pub.dev/packages/standard_message_codec/score) | [![downloads](https://img.shields.io/pub/dm/standard_message_codec)](https://pub.dev/packages/standard_message_codec/score) | [![GitHub issues by-label](https://img.shields.io/github/issues/flutter/flutter/p%3A%20standard_message_codec?label=)](https://github.com/flutter/flutter/labels/p%3A%20standard_message_codec) | [![GitHub pull requests by-label](https://img.shields.io/github/issues-pr/flutter/core-packages/p%3A%20standard_message_codec?label=)](https://github.com/flutter/core-packages/labels/p%3A%20standard_message_codec) |
Expand Down
9 changes: 9 additions & 0 deletions packages/listen/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.children
.project
.DS_Store
packages
pubspec.lock
.pub
.packages
.dart_tool
.idea
6 changes: 6 additions & 0 deletions packages/listen/AUTHORS
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Below is a list of people and organizations that have contributed
# to the project. Names should be added to the list like so:
#
# Name/Organization <email address>

Google Inc.
3 changes: 3 additions & 0 deletions packages/listen/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 1.0.0-beta.1

- Moves source code from `flutter/flutter` to `flutter/core-packages`.
25 changes: 25 additions & 0 deletions packages/listen/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Copyright 2013 The Flutter Authors

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
103 changes: 103 additions & 0 deletions packages/listen/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?code-excerpt path-base="example/lib"?>

# listen

A package to notify state changes to interested listeners in pure Dart.

## Usage

### Using ValueNotifier

`ValueNotifier` wraps a single value and notifies listeners whenever the value changes:

<?code-excerpt "readme_excerpts.dart (ValueNotifier)"?>
```dart
void valueNotifierExample() {
final counter = ValueNotifier<int>(0);

counter.addListener(() {
print('Value changed: ${counter.value}');
});

counter.value = 5; // Prints: Value changed: 5
counter.value = 10; // Prints: Value changed: 10
counter.value = 10; // Does not print because the value is == 10

counter.dispose();
}

```

### Using ChangeNotifier

Extend or mix in `ChangeNotifier` to manage state and notify listeners manually:

<?code-excerpt "readme_excerpts.dart (ChangeNotifierClass)"?>
```dart
/// A [ChangeNotifier] subclass that encapsulates a list of items and notifies
/// listeners whenever items are added or removed.
class ItemListNotifier extends ChangeNotifier {
final List<String> _items = <String>[];

/// The unmodifiable list of current items.
List<String> get items => List<String>.unmodifiable(_items);

/// Adds an [item] to the list and notifies listeners.
void addItem(String item) {
_items.add(item);
notifyListeners();
}

/// Removes an [item] from the list and notifies listeners if it was present.
void removeItem(String item) {
if (_items.remove(item)) {
notifyListeners();
}
}
}

```

Then, listen to changes and update state:

<?code-excerpt "readme_excerpts.dart (ChangeNotifierUsage)"?>
```dart
void changeNotifierExample() {
final listNotifier = ItemListNotifier();

listNotifier.addListener(() {
print('Current items: ${listNotifier.items}');
});

listNotifier.addItem('Apple'); // Prints: Current items: [Apple]
listNotifier.addItem('Banana'); // Prints: Current items: [Apple, Banana]
listNotifier.removeItem('Apple'); // Prints: Current items: [Banana]

listNotifier.dispose();
}

```

### Merging listenables

Use `Listenable.merge` to listen to multiple objects simultaneously:

<?code-excerpt "readme_excerpts.dart (Merge)"?>
```dart
void mergeExample() {
final first = ValueNotifier<String>('Hello');
final second = ValueNotifier<String>('World');

final merged = Listenable.merge(<Listenable>[first, second]);

merged.addListener(() {
print('Merged listenable triggered: ${first.value} ${second.value}');
});

first.value = 'Hi'; // Prints: Merged listenable triggered: Hi World
second.value = 'Dart'; // Prints: Merged listenable triggered: Hi Dart

first.dispose();
second.dispose();
}
```
35 changes: 35 additions & 0 deletions packages/listen/example/lib/counter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: avoid_print

import 'package:listen/listen.dart';

/// A simple counter that extends [ChangeNotifier] to notify listeners
/// whenever its value changes.
class Counter extends ChangeNotifier {
int _count = 0;

/// The current count value.
int get count => _count;

/// Increments the count by one and notifies listeners.
void increment() {
_count++;
notifyListeners();
}
}

void main() {
final counter = Counter();

counter.addListener(() {
print('Counter value changed to: ${counter.count}');
});

counter.increment(); // Prints: Counter value changed to: 1
counter.increment(); // Prints: Counter value changed to: 2

counter.dispose();
}
43 changes: 43 additions & 0 deletions packages/listen/example/lib/list_notifier.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: avoid_print

import 'package:listen/listen.dart';

/// A [ChangeNotifier] subclass that encapsulates a list of items and notifies
/// listeners whenever items are added or removed.
class ItemListNotifier extends ChangeNotifier {
final List<String> _items = <String>[];

/// The unmodifiable list of current items.
List<String> get items => List<String>.unmodifiable(_items);

/// Adds an [item] to the list and notifies listeners.
void addItem(String item) {
_items.add(item);
notifyListeners();
}

/// Removes an [item] from the list and notifies listeners if it was present.
void removeItem(String item) {
if (_items.remove(item)) {
notifyListeners();
}
}
}

void main() {
final listNotifier = ItemListNotifier();

listNotifier.addListener(() {
print('Current items: ${listNotifier.items}');
});

listNotifier.addItem('Apple'); // Prints: Current items: [Apple]
listNotifier.addItem('Banana'); // Prints: Current items: [Apple, Banana]
listNotifier.removeItem('Apple'); // Prints: Current items: [Banana]

listNotifier.dispose();
}
24 changes: 24 additions & 0 deletions packages/listen/example/lib/listenable_merge.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: avoid_print

import 'package:listen/listen.dart';

void main() {
final first = ValueNotifier<String>('Hello');
final second = ValueNotifier<String>('World');

final merged = Listenable.merge(<Listenable>[first, second]);

merged.addListener(() {
print('Merged listenable triggered: ${first.value} ${second.value}');
});

first.value = 'Hi'; // Prints: Merged listenable triggered: Hi World
second.value = 'Dart'; // Prints: Merged listenable triggered: Hi Dart

first.dispose();
second.dispose();
}
20 changes: 20 additions & 0 deletions packages/listen/example/lib/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// ignore_for_file: avoid_print

import 'package:listen/listen.dart';

void main() {
final counter = ValueNotifier<int>(0);

counter.addListener(() {
print('Counter changed to: ${counter.value}');
});

counter.value = 1; // Prints: Counter changed to: 1
counter.value = 2; // Prints: Counter changed to: 2

counter.dispose();
}
91 changes: 91 additions & 0 deletions packages/listen/example/lib/readme_excerpts.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright 2013 The Flutter Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This file exists solely to host compiled excerpts for README.md, and is not
// intended for use as an actual example application.

// ignore_for_file: avoid_print

import 'package:listen/listen.dart';

/// Demonstrates [ValueNotifier] usage for README.
// #docregion ValueNotifier
void valueNotifierExample() {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason this is duplicated almost exactly here from main.dart, instead of the README snippet just pulling from main.dart?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That will require adding the #docregion identifier on the main.dart, which I think may be confusing for people looking at the example. so I intentionally group all excerpt related code in one file even if I can probably grab the code from some other example. Let me know reducing duplication here is more preferred.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Traditionally we haven't worried about having it in main.dart, and only use readme_excerpts.dart when there were things we wanted to show in the README that weren't in the example.

It's not a rule though, so if you are concerned about the comments in the example this is fine.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will keep this as-is

final counter = ValueNotifier<int>(0);

counter.addListener(() {
print('Value changed: ${counter.value}');
});

counter.value = 5; // Prints: Value changed: 5
counter.value = 10; // Prints: Value changed: 10
counter.value = 10; // Does not print because the value is == 10

counter.dispose();
}

// #enddocregion ValueNotifier

// #docregion ChangeNotifierClass
/// A [ChangeNotifier] subclass that encapsulates a list of items and notifies
/// listeners whenever items are added or removed.
class ItemListNotifier extends ChangeNotifier {
final List<String> _items = <String>[];

/// The unmodifiable list of current items.
List<String> get items => List<String>.unmodifiable(_items);

/// Adds an [item] to the list and notifies listeners.
void addItem(String item) {
_items.add(item);
notifyListeners();
}

/// Removes an [item] from the list and notifies listeners if it was present.
void removeItem(String item) {
if (_items.remove(item)) {
notifyListeners();
}
}
}

// #enddocregion ChangeNotifierClass

/// Demonstrates [ChangeNotifier] usage for README.
// #docregion ChangeNotifierUsage
void changeNotifierExample() {
final listNotifier = ItemListNotifier();

listNotifier.addListener(() {
print('Current items: ${listNotifier.items}');
});

listNotifier.addItem('Apple'); // Prints: Current items: [Apple]
listNotifier.addItem('Banana'); // Prints: Current items: [Apple, Banana]
listNotifier.removeItem('Apple'); // Prints: Current items: [Banana]

listNotifier.dispose();
}

// #enddocregion ChangeNotifierUsage

/// Demonstrates [Listenable.merge] usage for README.
// #docregion Merge
void mergeExample() {
final first = ValueNotifier<String>('Hello');
final second = ValueNotifier<String>('World');

final merged = Listenable.merge(<Listenable>[first, second]);

merged.addListener(() {
print('Merged listenable triggered: ${first.value} ${second.value}');
});

first.value = 'Hi'; // Prints: Merged listenable triggered: Hi World
second.value = 'Dart'; // Prints: Merged listenable triggered: Hi Dart

first.dispose();
second.dispose();
}
// #enddocregion Merge
Loading
Loading