Skip to content

Commit c0a28af

Browse files
committed
First prototype of pkg:listen
1 parent b59ecf4 commit c0a28af

File tree

9 files changed

+248
-0
lines changed

9 files changed

+248
-0
lines changed

pkgs/listen/.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Don’t commit the following directories created by pub.
2+
.buildlog
3+
.pub/
4+
.dart_tool/
5+
build/
6+
packages
7+
.packages
8+
9+
# Or the files created by dart2js.
10+
*.dart.js
11+
*.js_
12+
*.js.deps
13+
*.js.map
14+
15+
# Include when developing application packages.
16+
pubspec.lock

pkgs/listen/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## 1.0.0-beta.0
2+
3+
- First release.

pkgs/listen/LICENSE

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Copyright 2014 The Flutter Authors. All rights reserved.
2+
3+
Redistribution and use in source and binary forms, with or without modification,
4+
are permitted provided that the following conditions are met:
5+
6+
* Redistributions of source code must retain the above copyright
7+
notice, this list of conditions and the following disclaimer.
8+
* Redistributions in binary form must reproduce the above
9+
copyright notice, this list of conditions and the following
10+
disclaimer in the documentation and/or other materials provided
11+
with the distribution.
12+
* Neither the name of Google Inc. nor the names of its
13+
contributors may be used to endorse or promote products derived
14+
from this software without specific prior written permission.
15+
16+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
23+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

pkgs/listen/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Very prototype package

pkgs/listen/analysis_options.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# https://dart.dev/guides/language/analysis-options
2+
3+
include: package:dart_flutter_team_lints/analysis_options.yaml
4+
5+
analyzer:
6+
language:
7+
strict-raw-types: true
8+
9+
linter:
10+
rules:
11+
- avoid_unused_constructor_parameters
12+
- cancel_subscriptions
13+
- literal_only_boolean_expressions
14+
- missing_whitespace_between_adjacent_strings
15+
- no_adjacent_strings_in_list
16+
- no_runtimeType_toString
17+
- unnecessary_await_in_return

pkgs/listen/lib/listen.dart

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
/// An object that maintains a list of listeners.
6+
///
7+
/// The listeners are typically used to notify clients that the object has been
8+
/// updated.
9+
///
10+
/// There are two variants of this interface:
11+
///
12+
/// * [ValueListenable], an interface that augments the [Listenable] interface
13+
/// with the concept of a _current value_.
14+
///
15+
/// * [Animation], an interface that augments the [ValueListenable] interface
16+
/// to add the concept of direction (forward or reverse).
17+
///
18+
/// Many classes in the Flutter API use or implement these interfaces. The
19+
/// following subclasses are especially relevant:
20+
///
21+
/// * [ChangeNotifier], which can be subclassed or mixed in to create objects
22+
/// that implement the [Listenable] interface.
23+
///
24+
/// * [ValueNotifier], which implements the [ValueListenable] interface with
25+
/// a mutable value that triggers the notifications when modified.
26+
///
27+
/// The terms "notify clients", "send notifications", "trigger notifications",
28+
/// and "fire notifications" are used interchangeably.
29+
///
30+
/// See also:
31+
///
32+
/// * [AnimatedBuilder], a widget that uses a builder callback to rebuild
33+
/// whenever a given [Listenable] triggers its notifications. This widget is
34+
/// commonly used with [Animation] subclasses, hence its name, but is by no
35+
/// means limited to animations, as it can be used with any [Listenable]. It
36+
/// is a subclass of [AnimatedWidget], which can be used to create widgets
37+
/// that are driven from a [Listenable].
38+
/// * [ValueListenableBuilder], a widget that uses a builder callback to
39+
/// rebuild whenever a [ValueListenable] object triggers its notifications,
40+
/// providing the builder with the value of the object.
41+
/// * [InheritedNotifier], an abstract superclass for widgets that use a
42+
/// [Listenable]'s notifications to trigger rebuilds in descendant widgets
43+
/// that declare a dependency on them, using the [InheritedWidget] mechanism.
44+
/// * [Listenable.merge], which creates a [Listenable] that triggers
45+
/// notifications whenever any of a list of other [Listenable]s trigger their
46+
/// notifications.
47+
abstract class Listenable {
48+
/// Abstract const constructor. This constructor enables subclasses to provide
49+
/// const constructors so that they can be used in const expressions.
50+
const Listenable();
51+
52+
/// Return a [Listenable] that triggers when any of the given [Listenable]s
53+
/// themselves trigger.
54+
///
55+
/// Once the factory is called, items must not be added or removed from the
56+
/// iterable.
57+
/// Doing so will lead to memory leaks or exceptions.
58+
///
59+
/// The iterable may contain nulls; they are ignored.
60+
factory Listenable.merge(Iterable<Listenable?> listenables) =
61+
_MergingListenable;
62+
63+
/// Register a closure to be called when the object notifies its listeners.
64+
void addListener(void Function() listener);
65+
66+
/// Remove a previously registered closure from the list of closures that the
67+
/// object notifies.
68+
void removeListener(void Function() listener);
69+
}
70+
71+
/// An interface for subclasses of [Listenable] that expose a [value].
72+
///
73+
/// This interface is implemented by [ValueNotifier<T>] and [Animation<T>], and
74+
/// allows other APIs to accept either of those implementations interchangeably.
75+
///
76+
/// See also:
77+
///
78+
/// * [ValueListenableBuilder], a widget that uses a builder callback to
79+
/// rebuild whenever a [ValueListenable] object triggers its notifications,
80+
/// providing the builder with the value of the object.
81+
abstract class ValueListenable<T> extends Listenable {
82+
/// Abstract const constructor. This constructor enables subclasses to provide
83+
/// const constructors so that they can be used in const expressions.
84+
const ValueListenable();
85+
86+
/// The current value of the object. When the value changes, the callbacks
87+
/// registered with [addListener] will be invoked.
88+
T get value;
89+
}
90+
91+
class _MergingListenable extends Listenable {
92+
_MergingListenable(this._children);
93+
94+
final Iterable<Listenable?> _children;
95+
96+
@override
97+
void addListener(void Function() listener) {
98+
for (final child in _children) {
99+
child?.addListener(listener);
100+
}
101+
}
102+
103+
@override
104+
void removeListener(void Function() listener) {
105+
for (final child in _children) {
106+
child?.removeListener(listener);
107+
}
108+
}
109+
110+
@override
111+
String toString() {
112+
return 'Listenable.merge([${_children.join(", ")}])';
113+
}
114+
}

pkgs/listen/pubspec.yaml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
name: listen
2+
version: 1.0.0-beta.0
3+
description: Includes core Flutter types Listenable and ValueListenable
4+
5+
environment:
6+
sdk: ^3.7.0
7+
8+
dev_dependencies:
9+
dart_flutter_team_lints: ^3.5.0
10+
test: any

pkgs/listen/test/listen_test.dart

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright 2014 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'package:listen/listen.dart';
6+
import 'package:test/test.dart';
7+
8+
import 'test_listenable.dart';
9+
10+
void main() {
11+
test('Listenable.merge', () {
12+
final listenableA = TestListenable();
13+
final listenableB = TestListenable();
14+
15+
final merged = Listenable.merge([listenableA, listenableB]);
16+
17+
var callCount = 0;
18+
19+
void testListener() {
20+
callCount++;
21+
}
22+
23+
merged.addListener(testListener);
24+
25+
expect(callCount, 0);
26+
27+
listenableA.notify();
28+
expect(callCount, 1);
29+
30+
listenableB.notify();
31+
expect(callCount, 2);
32+
33+
merged.removeListener(testListener);
34+
35+
listenableA.notify();
36+
expect(callCount, 2);
37+
38+
listenableB.notify();
39+
expect(callCount, 2);
40+
});
41+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import 'package:listen/listen.dart';
2+
3+
class TestListenable extends Listenable {
4+
final _listeners = <void Function()>{};
5+
6+
void notify() {
7+
for (final listener in _listeners) {
8+
listener();
9+
}
10+
}
11+
12+
@override
13+
void addListener(void Function() listener) {
14+
_listeners.add(listener);
15+
}
16+
17+
@override
18+
void removeListener(void Function() listener) {
19+
_listeners.remove(listener);
20+
}
21+
}

0 commit comments

Comments
 (0)