[roll] Update third-party dart packages
Roller-URL: https://ci.chromium.org/b/8858079893751699984
Cq-Cl-Tag: roller-builder:flutter-with-deps-roller
Cq-Cl-Tag: roller-bid:8858079893751699984
CQ-Do-Not-Cancel-Tryjobs: true
Change-Id: I29185123c5bdee1366a6d287ce030be905738693
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/dart-pkg/+/471479
Reviewed-by: GI Roller <global-integration-roller@fuchsia-infra.iam.gserviceaccount.com>
Commit-Queue: GI Roller <global-integration-roller@fuchsia-infra.iam.gserviceaccount.com>
diff --git a/code_builder/.github/workflows/test-package.yml b/code_builder/.github/workflows/test-package.yml
new file mode 100644
index 0000000..28a5086
--- /dev/null
+++ b/code_builder/.github/workflows/test-package.yml
@@ -0,0 +1,72 @@
+name: Dart CI
+
+on:
+ # Run on PRs and pushes to the default branch.
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+ schedule:
+ - cron: "0 0 * * 0"
+
+env:
+ PUB_ENVIRONMENT: bot.github
+
+jobs:
+ # Check code formatting and static analysis on a single OS (linux)
+ # against Dart dev and 2.7.0.
+ analyze:
+ runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ sdk: [dev]
+ version: [latest]
+ include:
+ - sdk: stable
+ version: 2.7.0
+ steps:
+ - uses: actions/checkout@v2
+ - uses: cedx/setup-dart@v2 # TODO(dart-lang/setup-dart#3): use the official setup-dart action
+ with:
+ release-channel: ${{ matrix.sdk }}
+ version: ${{ matrix.version }}
+ - id: install
+ name: Install dependencies
+ run: pub get
+ - name: Check formatting
+ run: dartfmt --dry-run --set-exit-if-changed .
+ if: always() && steps.install.outcome == 'success'
+ - name: Analyze code
+ run: dartanalyzer --fatal-infos --fatal-warnings .
+ if: always() && steps.install.outcome == 'success'
+
+ # Run tests on a matrix consisting of two dimensions:
+ # 1. OS: ubuntu-latest, (macos-latest, windows-latest)
+ # 2. release channel: dev, 2.7.0
+ test:
+ needs: analyze
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ # Add macos-latest and/or windows-latest if relevant for this package.
+ os: [ubuntu-latest]
+ sdk: [dev]
+ version: [latest]
+ include:
+ - os: ubuntu-latest
+ sdk: stable
+ version: 2.7.0
+ steps:
+ - uses: actions/checkout@v2
+ - uses: cedx/setup-dart@v2 # TODO(dart-lang/setup-dart#3): use the official setup-dart action
+ with:
+ release-channel: ${{ matrix.sdk }}
+ version: ${{ matrix.version }}
+ - id: install
+ name: Install dependencies
+ run: pub get
+ - name: Run VM tests
+ run: pub run test --platform vm
+ if: always() && steps.install.outcome == 'success'
diff --git a/code_builder/.travis.yml b/code_builder/.travis.yml
deleted file mode 100644
index dda7d52..0000000
--- a/code_builder/.travis.yml
+++ /dev/null
@@ -1,17 +0,0 @@
-language: dart
-
-dart:
- - dev
- - 2.7.0
-
-dart_task:
-- test
-- dartanalyzer: --fatal-infos --fatal-warnings .
-- dartfmt: sdk
-
-branches:
- only: [master]
-
-cache:
- directories:
- - $HOME/.pub-cache
diff --git a/code_builder/BUILD.gn b/code_builder/BUILD.gn
index 8636ee9..96417d0 100644
--- a/code_builder/BUILD.gn
+++ b/code_builder/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for code_builder-3.5.0
+# This file is generated by importer.py for code_builder-3.6.0
import("//build/dart/dart_library.gni")
@@ -42,6 +42,8 @@
"src/specs/expression/code.dart",
"src/specs/expression/invoke.dart",
"src/specs/expression/literal.dart",
+ "src/specs/extension.dart",
+ "src/specs/extension.g.dart",
"src/specs/field.dart",
"src/specs/field.g.dart",
"src/specs/library.dart",
diff --git a/code_builder/CHANGELOG.md b/code_builder/CHANGELOG.md
index c1dbf3f..b80e4d9 100644
--- a/code_builder/CHANGELOG.md
+++ b/code_builder/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 3.6.0
+
+* Add support for creating `extension` methods.
+* Expand constraint on `built_value` to allow null safe migrated version.
+
## 3.5.0
* Add support for defining enums.
diff --git a/code_builder/README.md b/code_builder/README.md
index a438d7d..89d973f 100644
--- a/code_builder/README.md
+++ b/code_builder/README.md
@@ -1,5 +1,5 @@
[![Pub package](https://img.shields.io/pub/v/code_builder.svg)](https://pub.dev/packages/code_builder)
-[![Build status](https://travis-ci.org/dart-lang/code_builder.svg)](https://travis-ci.org/dart-lang/code_builder)
+[![Build Status](https://github.com/dart-lang/code_builder/workflows/Dart%20CI/badge.svg?branch=master)](https://github.com/dart-lang/code_builder/actions?query=workflow%3A%22Dart+CI%22+branch%3Amaster)
[![Gitter chat](https://badges.gitter.im/dart-lang/build.svg)](https://gitter.im/dart-lang/build)
A fluent, builder-based library for generating valid Dart code.
@@ -29,15 +29,16 @@
```
Outputs:
+
```dart
class Animal extends Organism {
void eat() => print('Yum!');
}
```
-Have a complicated set of dependencies for your generated code?
-`code_builder` supports automatic scoping of your ASTs to automatically
-use prefixes to avoid symbol conflicts:
+Have a complicated set of dependencies for your generated code? `code_builder`
+supports automatic scoping of your ASTs to automatically use prefixes to avoid
+symbol conflicts:
```dart
import 'package:code_builder/code_builder.dart';
@@ -60,6 +61,7 @@
```
Outputs:
+
```dart
import 'package:a/a.dart' as _i1;
import 'package:b/b.dart' as _i2;
@@ -70,8 +72,8 @@
## Contributing
-* Read and help us document common patterns over [at the wiki][wiki].
-* Is there a *bug* in the code? [File an issue][issue].
+- Read and help us document common patterns over [at the wiki][wiki].
+- Is there a _bug_ in the code? [File an issue][issue].
If a feature is missing (the Dart language is always evolving) or you'd like an
easier or better way to do something, consider [opening a pull request][pull].
@@ -91,9 +93,9 @@
### Updating generated (`.g.dart`) files
-> **NOTE**: There is currently a limitation in `build_runner` that requires
-> a workaround for developing this package. We expect this to be unnecessary
-> in the future.
+> **NOTE**: There is currently a limitation in `build_runner` that requires a
+> workaround for developing this package. We expect this to be unnecessary in
+> the future.
Use [`build_runner`][build_runner]:
diff --git a/code_builder/lib/code_builder.dart b/code_builder/lib/code_builder.dart
index 564299a..60adee8 100644
--- a/code_builder/lib/code_builder.dart
+++ b/code_builder/lib/code_builder.dart
@@ -39,6 +39,7 @@
literalString,
literalTrue,
literalFalse;
+export 'src/specs/extension.dart' show Extension, ExtensionBuilder;
export 'src/specs/field.dart' show Field, FieldBuilder, FieldModifier;
export 'src/specs/library.dart' show Library, LibraryBuilder;
export 'src/specs/method.dart'
diff --git a/code_builder/lib/src/emitter.dart b/code_builder/lib/src/emitter.dart
index bd5b32d..b680235 100644
--- a/code_builder/lib/src/emitter.dart
+++ b/code_builder/lib/src/emitter.dart
@@ -10,6 +10,7 @@
import 'specs/directive.dart';
import 'specs/enum.dart';
import 'specs/expression.dart';
+import 'specs/extension.dart';
import 'specs/field.dart';
import 'specs/library.dart';
import 'specs/method.dart';
@@ -234,6 +235,37 @@
}
@override
+ StringSink visitExtension(Extension spec, [StringSink output]) {
+ output ??= StringBuffer();
+ spec.docs.forEach(output.writeln);
+ spec.annotations.forEach((a) => visitAnnotation(a, output));
+
+ output.write('extension');
+ if (spec.name != null) {
+ output.write(' ${spec.name}');
+ }
+ visitTypeParameters(spec.types.map((r) => r.type), output);
+ if (spec.on != null) {
+ output.write(' on ');
+ spec.on.type.accept(this, output);
+ }
+ output.write(' {');
+ spec.fields.forEach((f) {
+ visitField(f, output);
+ output.writeln();
+ });
+ spec.methods.forEach((m) {
+ visitMethod(m, output);
+ if (_isLambdaMethod(m)) {
+ output.write(';');
+ }
+ output.writeln();
+ });
+ output.writeln(' }');
+ return output;
+ }
+
+ @override
StringSink visitDirective(Directive spec, [StringSink output]) {
output ??= StringBuffer();
switch (spec.type) {
diff --git a/code_builder/lib/src/specs/extension.dart b/code_builder/lib/src/specs/extension.dart
new file mode 100644
index 0000000..9260471
--- /dev/null
+++ b/code_builder/lib/src/specs/extension.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:built_value/built_value.dart';
+import 'package:built_collection/built_collection.dart';
+import 'package:meta/meta.dart';
+
+import '../../code_builder.dart';
+import '../base.dart';
+import '../mixins/annotations.dart';
+import '../mixins/dartdoc.dart';
+import '../mixins/generics.dart';
+import '../visitors.dart';
+import 'expression.dart';
+import 'field.dart';
+import 'method.dart';
+import 'reference.dart';
+
+part 'extension.g.dart';
+
+@immutable
+abstract class Extension extends Object
+ with HasAnnotations, HasDartDocs, HasGenerics
+ implements Built<Extension, ExtensionBuilder>, Spec {
+ factory Extension([void Function(ExtensionBuilder b) updates]) = _$Extension;
+
+ Extension._();
+
+ @override
+ BuiltList<Expression> get annotations;
+
+ @override
+ BuiltList<String> get docs;
+
+ @nullable
+ Reference get on;
+
+ @override
+ BuiltList<Reference> get types;
+
+ BuiltList<Method> get methods;
+ BuiltList<Field> get fields;
+
+ /// Name of the extension - optional.
+ @nullable
+ String get name;
+
+ @override
+ R accept<R>(
+ SpecVisitor<R> visitor, [
+ R context,
+ ]) =>
+ visitor.visitExtension(this, context);
+}
+
+abstract class ExtensionBuilder extends Object
+ with HasAnnotationsBuilder, HasDartDocsBuilder, HasGenericsBuilder
+ implements Builder<Extension, ExtensionBuilder> {
+ factory ExtensionBuilder() = _$ExtensionBuilder;
+
+ ExtensionBuilder._();
+
+ @override
+ ListBuilder<Expression> annotations = ListBuilder<Expression>();
+
+ @override
+ ListBuilder<String> docs = ListBuilder<String>();
+
+ Reference on;
+
+ @override
+ ListBuilder<Reference> types = ListBuilder<Reference>();
+
+ ListBuilder<Method> methods = ListBuilder<Method>();
+ ListBuilder<Field> fields = ListBuilder<Field>();
+
+ /// Name of the extension - optional.
+ String name;
+}
diff --git a/code_builder/lib/src/specs/extension.g.dart b/code_builder/lib/src/specs/extension.g.dart
new file mode 100644
index 0000000..befd295
--- /dev/null
+++ b/code_builder/lib/src/specs/extension.g.dart
@@ -0,0 +1,256 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'extension.dart';
+
+// **************************************************************************
+// BuiltValueGenerator
+// **************************************************************************
+
+class _$Extension extends Extension {
+ @override
+ final BuiltList<Expression> annotations;
+ @override
+ final BuiltList<String> docs;
+ @override
+ final Reference on;
+ @override
+ final BuiltList<Reference> types;
+ @override
+ final BuiltList<Method> methods;
+ @override
+ final BuiltList<Field> fields;
+ @override
+ final String name;
+
+ factory _$Extension([void Function(ExtensionBuilder) updates]) =>
+ (new ExtensionBuilder()..update(updates)).build() as _$Extension;
+
+ _$Extension._(
+ {this.annotations,
+ this.docs,
+ this.on,
+ this.types,
+ this.methods,
+ this.fields,
+ this.name})
+ : super._() {
+ if (annotations == null) {
+ throw new BuiltValueNullFieldError('Extension', 'annotations');
+ }
+ if (docs == null) {
+ throw new BuiltValueNullFieldError('Extension', 'docs');
+ }
+ if (types == null) {
+ throw new BuiltValueNullFieldError('Extension', 'types');
+ }
+ if (methods == null) {
+ throw new BuiltValueNullFieldError('Extension', 'methods');
+ }
+ if (fields == null) {
+ throw new BuiltValueNullFieldError('Extension', 'fields');
+ }
+ }
+
+ @override
+ Extension rebuild(void Function(ExtensionBuilder) updates) =>
+ (toBuilder()..update(updates)).build();
+
+ @override
+ _$ExtensionBuilder toBuilder() => new _$ExtensionBuilder()..replace(this);
+
+ @override
+ bool operator ==(Object other) {
+ if (identical(other, this)) return true;
+ return other is Extension &&
+ annotations == other.annotations &&
+ docs == other.docs &&
+ on == other.on &&
+ types == other.types &&
+ methods == other.methods &&
+ fields == other.fields &&
+ name == other.name;
+ }
+
+ @override
+ int get hashCode {
+ return $jf($jc(
+ $jc(
+ $jc(
+ $jc(
+ $jc($jc($jc(0, annotations.hashCode), docs.hashCode),
+ on.hashCode),
+ types.hashCode),
+ methods.hashCode),
+ fields.hashCode),
+ name.hashCode));
+ }
+
+ @override
+ String toString() {
+ return (newBuiltValueToStringHelper('Extension')
+ ..add('annotations', annotations)
+ ..add('docs', docs)
+ ..add('on', on)
+ ..add('types', types)
+ ..add('methods', methods)
+ ..add('fields', fields)
+ ..add('name', name))
+ .toString();
+ }
+}
+
+class _$ExtensionBuilder extends ExtensionBuilder {
+ _$Extension _$v;
+
+ @override
+ ListBuilder<Expression> get annotations {
+ _$this;
+ return super.annotations ??= new ListBuilder<Expression>();
+ }
+
+ @override
+ set annotations(ListBuilder<Expression> annotations) {
+ _$this;
+ super.annotations = annotations;
+ }
+
+ @override
+ ListBuilder<String> get docs {
+ _$this;
+ return super.docs ??= new ListBuilder<String>();
+ }
+
+ @override
+ set docs(ListBuilder<String> docs) {
+ _$this;
+ super.docs = docs;
+ }
+
+ @override
+ Reference get on {
+ _$this;
+ return super.on;
+ }
+
+ @override
+ set on(Reference on) {
+ _$this;
+ super.on = on;
+ }
+
+ @override
+ ListBuilder<Reference> get types {
+ _$this;
+ return super.types ??= new ListBuilder<Reference>();
+ }
+
+ @override
+ set types(ListBuilder<Reference> types) {
+ _$this;
+ super.types = types;
+ }
+
+ @override
+ ListBuilder<Method> get methods {
+ _$this;
+ return super.methods ??= new ListBuilder<Method>();
+ }
+
+ @override
+ set methods(ListBuilder<Method> methods) {
+ _$this;
+ super.methods = methods;
+ }
+
+ @override
+ ListBuilder<Field> get fields {
+ _$this;
+ return super.fields ??= new ListBuilder<Field>();
+ }
+
+ @override
+ set fields(ListBuilder<Field> fields) {
+ _$this;
+ super.fields = fields;
+ }
+
+ @override
+ String get name {
+ _$this;
+ return super.name;
+ }
+
+ @override
+ set name(String name) {
+ _$this;
+ super.name = name;
+ }
+
+ _$ExtensionBuilder() : super._();
+
+ ExtensionBuilder get _$this {
+ if (_$v != null) {
+ super.annotations = _$v.annotations?.toBuilder();
+ super.docs = _$v.docs?.toBuilder();
+ super.on = _$v.on;
+ super.types = _$v.types?.toBuilder();
+ super.methods = _$v.methods?.toBuilder();
+ super.fields = _$v.fields?.toBuilder();
+ super.name = _$v.name;
+ _$v = null;
+ }
+ return this;
+ }
+
+ @override
+ void replace(Extension other) {
+ if (other == null) {
+ throw new ArgumentError.notNull('other');
+ }
+ _$v = other as _$Extension;
+ }
+
+ @override
+ void update(void Function(ExtensionBuilder) updates) {
+ if (updates != null) updates(this);
+ }
+
+ @override
+ _$Extension build() {
+ _$Extension _$result;
+ try {
+ _$result = _$v ??
+ new _$Extension._(
+ annotations: annotations.build(),
+ docs: docs.build(),
+ on: on,
+ types: types.build(),
+ methods: methods.build(),
+ fields: fields.build(),
+ name: name);
+ } catch (_) {
+ String _$failedField;
+ try {
+ _$failedField = 'annotations';
+ annotations.build();
+ _$failedField = 'docs';
+ docs.build();
+
+ _$failedField = 'types';
+ types.build();
+ _$failedField = 'methods';
+ methods.build();
+ _$failedField = 'fields';
+ fields.build();
+ } catch (e) {
+ throw new BuiltValueNestedFieldError(
+ 'Extension', _$failedField, e.toString());
+ }
+ rethrow;
+ }
+ replace(_$result);
+ return _$result;
+ }
+}
+
+// ignore_for_file: always_put_control_body_on_new_line,always_specify_types,annotate_overrides,avoid_annotating_with_dynamic,avoid_as,avoid_catches_without_on_clauses,avoid_returning_this,lines_longer_than_80_chars,omit_local_variable_types,prefer_expression_function_bodies,sort_constructors_first,test_types_in_equals,unnecessary_const,unnecessary_new
diff --git a/code_builder/lib/src/visitors.dart b/code_builder/lib/src/visitors.dart
index 1447b83..ed2ab4d 100644
--- a/code_builder/lib/src/visitors.dart
+++ b/code_builder/lib/src/visitors.dart
@@ -10,6 +10,7 @@
import 'specs/directive.dart';
import 'specs/enum.dart';
import 'specs/expression.dart';
+import 'specs/extension.dart';
import 'specs/field.dart';
import 'specs/library.dart';
import 'specs/method.dart';
@@ -25,6 +26,8 @@
T visitClass(Class spec, [T context]);
+ T visitExtension(Extension spec, [T context]);
+
T visitEnum(Enum spec, [T context]);
T visitConstructor(Constructor spec, String clazz, [T context]);
diff --git a/code_builder/pubspec.yaml b/code_builder/pubspec.yaml
index abc1d67..8c8982d 100644
--- a/code_builder/pubspec.yaml
+++ b/code_builder/pubspec.yaml
@@ -1,5 +1,5 @@
name: code_builder
-version: 3.5.0
+version: 3.6.0
description: >-
A fluent, builder-based library for generating valid Dart code
@@ -9,8 +9,8 @@
sdk: '>=2.7.0 <3.0.0'
dependencies:
- built_collection: '>=3.0.0 <5.0.0'
- built_value: ^7.0.0
+ built_collection: '>=3.0.0 <6.0.0'
+ built_value: '>=7.0.0 <9.0.0'
collection: ^1.14.0
matcher: ^0.12.0
meta: ^1.0.5
diff --git a/provider/.gitignore b/provider/.gitignore
index 7dfcccc..03aab06 100644
--- a/provider/.gitignore
+++ b/provider/.gitignore
@@ -3,6 +3,7 @@
android/
ios/
.packages
+
# Remove the following pattern if you wish to check in your lock file
pubspec.lock
diff --git a/provider/BUILD.gn b/provider/BUILD.gn
index e06057e..67121e9 100644
--- a/provider/BUILD.gn
+++ b/provider/BUILD.gn
@@ -1,4 +1,4 @@
-# This file is generated by importer.py for provider-4.3.2+3
+# This file is generated by importer.py for provider-4.3.2+4
import("//build/dart/dart_library.gni")
diff --git a/provider/CHANGELOG.md b/provider/CHANGELOG.md
index ce4aea3..11c0a27 100644
--- a/provider/CHANGELOG.md
+++ b/provider/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 4.3.2+4
+
+`ValueListenableProvider` is no-longer deprecated. Only its default constructor is deprecated (the `.value` constructor is kept)
+
# 4.3.2+3
Marked `ValueListenableProvider` as deprecated
diff --git a/provider/README.md b/provider/README.md
index e4d8a3f..171f0f8 100644
--- a/provider/README.md
+++ b/provider/README.md
@@ -1,4 +1,4 @@
-[English](https://github.com/rrousselGit/provider/blob/master/README.md) | [Português](https://github.com/rrousselGit/provider/blob/master/resources/translations/pt_br/README.md) | [简体中文](./resources/translations/zh-CN/README.md)
+[English](https://github.com/rrousselGit/provider/blob/master/README.md) | [Português](https://github.com/rrousselGit/provider/blob/master/resources/translations/pt_br/README.md) | [简体中文](https://github.com/rrousselGit/provider/blob/master/resources/translations/zh-CN/README.md) | [Español](https://github.com/rrousselGit/provider/blob/master/resources/translations/es_MX/README.md)
<a href="https://github.com/rrousselGit/provider/actions"><img src="https://github.com/rrousselGit/provider/workflows/Build/badge.svg" alt="Build Status"></a>
[![codecov](https://codecov.io/gh/rrousselGit/provider/branch/master/graph/badge.svg)](https://codecov.io/gh/rrousselGit/provider) [![Gitter](https://badges.gitter.im/flutter_provider/community.svg)](https://gitter.im/flutter_provider/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
diff --git a/provider/example/lib/main.dart b/provider/example/lib/main.dart
index 1257582..4dc2a40 100644
--- a/provider/example/lib/main.dart
+++ b/provider/example/lib/main.dart
@@ -75,6 +75,8 @@
),
),
floatingActionButton: FloatingActionButton(
+ key: const Key('increment_floatingActionButton'),
+
/// Calls `context.read` instead of `context.watch` so that it does not rebuild
/// when [Counter] changes.
onPressed: () => context.read<Counter>().increment(),
@@ -94,6 +96,7 @@
/// Calls `context.watch` to make [Count] rebuild when [Counter] changes.
'${context.watch<Counter>().count}',
+ key: const Key('counterState'),
style: Theme.of(context).textTheme.headline4);
}
}
diff --git a/provider/example/pubspec.yaml b/provider/example/pubspec.yaml
index ee9e3d2..14395d3 100644
--- a/provider/example/pubspec.yaml
+++ b/provider/example/pubspec.yaml
@@ -13,8 +13,11 @@
provider:
dev_dependencies:
+ flutter_driver:
+ sdk: flutter
flutter_test:
sdk: flutter
+ test: ^1.15.7
dependency_overrides:
provider:
diff --git a/provider/example/test_driver/app.dart b/provider/example/test_driver/app.dart
new file mode 100644
index 0000000..9a2786b
--- /dev/null
+++ b/provider/example/test_driver/app.dart
@@ -0,0 +1,11 @@
+import 'package:flutter_driver/driver_extension.dart';
+import 'package:example/main.dart' as app;
+
+void main() {
+ // This line enables the extension.
+ enableFlutterDriverExtension();
+
+ // Call the `main()` function of the app, or call `runApp` with
+ // any widget you are interested in testing.
+ app.main();
+}
diff --git a/provider/example/test_driver/app_test.dart b/provider/example/test_driver/app_test.dart
new file mode 100644
index 0000000..1d55676
--- /dev/null
+++ b/provider/example/test_driver/app_test.dart
@@ -0,0 +1,42 @@
+// Imports the Flutter Driver API.
+import 'package:flutter_driver/flutter_driver.dart';
+import 'package:test/test.dart';
+
+void main() {
+ group('counter app', () {
+ FlutterDriver _driver;
+
+ final incrementFloatingButton =
+ find.byValueKey('increment_floatingActionButton');
+ final appBarText = find.text('Example');
+ final counterState = find.byValueKey('counterState');
+
+ /// connect to [FlutterDriver]
+ setUpAll(() async {
+ _driver = await FlutterDriver.connect();
+ });
+
+ /// close the driver
+ tearDownAll(() async {
+ await _driver?.close();
+ });
+
+ test('AppBar is Flutter Demo Home Page', () async {
+ expect(await _driver.getText(appBarText), 'Example');
+ });
+
+ test('counterText is started with 0', () async {
+ expect(await _driver.getText(counterState), '0');
+ });
+
+ test('pressed increment floating action button twice', () async {
+ // tap floating action button
+ await _driver.tap(incrementFloatingButton);
+ expect(await _driver.getText(counterState), '1');
+
+ // tap floating action button
+ await _driver.tap(incrementFloatingButton);
+ expect(await _driver.getText(counterState), '2');
+ });
+ });
+}
diff --git a/provider/lib/src/provider.dart b/provider/lib/src/provider.dart
index 6fe061f..8c7db2c 100644
--- a/provider/lib/src/provider.dart
+++ b/provider/lib/src/provider.dart
@@ -503,7 +503,7 @@
/// Widget build(BuildContext context) {
/// return RaisedButton(
/// onPressed: () {
- /// // as performant as the previous previous solution, but resilient to refactoring
+ /// // as performant as the previous solution, but resilient to refactoring
/// context.read<Counter>().increment(),
/// },
/// );
diff --git a/provider/lib/src/value_listenable_provider.dart b/provider/lib/src/value_listenable_provider.dart
index 21795ee..4f0abea 100644
--- a/provider/lib/src/value_listenable_provider.dart
+++ b/provider/lib/src/value_listenable_provider.dart
@@ -5,7 +5,6 @@
import 'provider.dart';
/// Listens to a [ValueListenable] and expose its current value.
-@Deprecated('Will be removed in 5.0.0')
class ValueListenableProvider<T>
extends DeferredInheritedProvider<ValueListenable<T>, T> {
/// Creates a [ValueNotifier] using [create] and automatically dispose it
@@ -20,6 +19,11 @@
/// * [ValueListenable]
/// * [ListenableProvider], similar to [ValueListenableProvider] but for any
/// kind of [Listenable].
+ @Deprecated(
+ 'Will be removed in 5.0.0. '
+ 'Instead use a StatefulWidget and manually create/dispose the ValueNotifier, '
+ 'then use ValueListenableProvider.value()',
+ )
ValueListenableProvider({
Key key,
@required Create<ValueNotifier<T>> create,
diff --git a/provider/pubspec.yaml b/provider/pubspec.yaml
index 9f57612..f75fa4b 100644
--- a/provider/pubspec.yaml
+++ b/provider/pubspec.yaml
@@ -1,17 +1,17 @@
name: provider
description: A wrapper around InheritedWidget to make them easier to use and more reusable.
-version: 4.3.2+3
+version: 4.3.2+4
homepage: https://github.com/rrousselGit/provider
environment:
sdk: ">=2.7.0 <3.0.0"
- flutter: ">= 1.16.0"
+ flutter: ">=1.16.0 <2.0.0"
dependencies:
collection: ^1.14.13
flutter:
sdk: flutter
- nested: ">= 0.0.4 < 2.0.0"
+ nested: ">=0.0.4 <2.0.0"
dev_dependencies:
flutter_test:
diff --git a/provider/resources/translations/es_MX/README.md b/provider/resources/translations/es_MX/README.md
new file mode 100644
index 0000000..35cb20d
--- /dev/null
+++ b/provider/resources/translations/es_MX/README.md
@@ -0,0 +1,682 @@
+[English](https://github.com/rrousselGit/provider/blob/master/README.md) | [Português](https://github.com/rrousselGit/provider/blob/master/resources/translations/pt_br/README.md) | [简体中文](https://github.com/rrousselGit/provider/blob/master/resources/translations/zh-CN/README.md) | [Español](./resources/translations/es_MX/README.md)
+
+<a href="https://github.com/rrousselGit/provider/actions"><img src="https://github.com/rrousselGit/provider/workflows/Build/badge.svg" alt="Build Status"></a>
+[![codecov](https://codecov.io/gh/rrousselGit/provider/branch/master/graph/badge.svg)](https://codecov.io/gh/rrousselGit/provider) [![Gitter](https://badges.gitter.im/flutter_provider/community.svg)](https://gitter.im/flutter_provider/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+
+[<img src="https://raw.githubusercontent.com/rrousselGit/provider/master/resources/flutter_favorite.png" width="200" />](https://flutter.dev/docs/development/packages-and-plugins/favorites)
+
+
+Un wrapper alrededor de [InheritedWidget]
+para hacerlo más fácil de usar y más utilizable.
+
+Al utilizar `provider` en lugar de escribir manualmente los [InheritedWidget], obtendrás:
+
+- asignación/eliminación simplificada de los recursos
+- lazy-loading
+- un boilerplate muy reducido en lugar de hacer una nueva clase cada vez.
+- compatibilidad con devtools
+- una manera común de consumir esto [InheritedWidget]s (ver [Provider.of]/[Consumer]/[Selector])
+- incrementa la escalabilidad de tus clases con un mecanismo de escucha (listener) que crece exponencialmente
+ en complejidad (tales como [ChangeNotifier], el cual es O(N²) al enviar notificaciones)
+
+Para leer más acerca de `provider`, leé su [documentación](https://pub.dev/documentation/provider/latest/provider/provider-library.html).
+
+Ver también:
+
+- [La documentación oficial de Flutter en gestión de estado](https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple), la cual muestra como usar `provider` + [ChangeNotifier]
+- [Ejemplos de arquitectura en Flutter](https://github.com/brianegan/flutter_architecture_samples/tree/master/change_notifier_provider), la cual contiene una implementación de una app usando `provider` + [ChangeNotifier]
+- [flutter_bloc](https://github.com/felangel/bloc) y [Mobx](https://github.com/mobxjs/mobx.dart), los cuales usan `provider` en su arquitectura.
+
+## Migrar de v3.x.0 a v4.0.0
+
+- Los parámetros `builder` e `initialBuilder` de providers son eliminados.
+ - `initialBuilder` deberá ser reemplazado por `create`.
+ - `builder` de "proxy" providers deberá ser reemplazado por `update`
+ - `builder` de providers clásicos deberá ser reemplazado por `create`.
+
+- las nuevas callbacks `create`/`update` son lazy-loaded, lo cual significa que serán llamadas
+ la primera vez que su valor sea leído, en lugar de la primera vez que el usuario sea creado.
+
+ Si esto no se quiere, puedes deshabilitar el lazy-loading pasando el valor `lazy: false` a
+ el provider de tu elección.
+
+ ```dart
+ FutureProvider(
+ create: (_) async => doSomeHttpRequest(),
+ lazy: false,
+ child: ...
+ )
+ ```
+
+- `ProviderNotFoundError` es renombrado a `ProviderNotFoundException`.
+
+- La interface `SingleChildCloneableWidget` es eliminada y reemplazada por un nuevo tipo
+ de widget `SingleChildWidget`.
+
+ Ve [este issue](https://github.com/rrousselGit/provider/issues/237) para detalles
+ acerca de como migrar.
+
+- [Selector] ahora comparará más profundamente el valor anterior y nuevo si estas son colecciones.
+
+ Si este no quiere, puedes revertir el comportamiento pasando el parámetro `shouldRebuild` al
+ [Selector]
+
+ ```dart
+ Selector<Selected, Consumed>(
+ shouldRebuild: (previous, next) => previous == next,
+ builder: ...,
+ )
+ ```
+
+- `DelegateWidget` y su familia han sido eliminados. En su lugar, para providers personalizados tendrán
+ subclasses directas [InheritedProvider] o un provider existente.
+
+## Uso
+
+### Exponiendo un valor
+
+#### Exponiendo una nueva instancia del objeto
+
+Los providers permiten no solo exponer un valor, sino también crear/escuchar/eliminar.
+
+Para exponer un objeto recién creado, utilice el constructor por defecto de un provider.
+_No uses_ el constructor `.value` si quieres **crear** un objeto, o
+podrías tener efectos secundarios no deseados.
+
+Ve [esta respuesta de stackoverflow](https://stackoverflow.com/questions/52249578/how-to-deal-with-unwanted-widget-build)
+la cual explica en mayor detalle, por qué usar el constructor `.value` para crear nuevos valores no es óptimo.
+
+- **DO** crea un nuevo objeto dentro de `create`.
+
+```dart
+Provider(
+ create: (_) => MyModel(),
+ child: ...
+)
+```
+
+- **DON'T** usar `Provider.value` para crear tu objeto.
+
+```dart
+ChangeNotifierProvider.value(
+ value: MyModel(),
+ child: ...
+)
+```
+
+- **DON'T** crear tu objeto de variables que pueden cambiar en el tiempo.
+
+ En esta situación, tu objeto nunca será actualizado cuando el
+ valor cambie.
+
+```dart
+int count;
+
+Provider(
+ create: (_) => MyModel(count),
+ child: ...
+)
+```
+
+Si quieres pasar variables que puede cambiar en el tiempo de tu objeto,
+considera utilizar `ProxyProvider`:
+
+```dart
+int count;
+
+ProxyProvider0(
+ update: (_, __) => MyModel(count),
+ child: ...
+)
+```
+
+**NOTA**:
+
+Cuando se utiliza la llamada de `create`/`update` de un provider, vale la pena señalar que en esta llamada
+se llama `lazy` por defecto.
+
+Lo que esto significa es que, hasta que el valor sea solicitado al menos una vez, el `create`/`update`
+no se llamarán las callback.
+
+Este comportamiento puede ser desactivado si quieres precalcular algo de lógica, usando el parámetro `lazy`:
+
+```dart
+MyProvider(
+ create: (_) => Something(),
+ lazy: false,
+)
+```
+
+#### Reutilizando una instancia de un objeto existente:
+
+Si ya tienes una instancia de un objeto y quieres exponerlo,
+deberías usar el constructor `.value` de un proveedor.
+
+Si no lo hace, puede llamar al método `dispose` de tu objeto cuando todavía está en uso.
+
+- **DO** usa `ChangeNotifierProvider.value` para un provider tipo
+ [ChangeNotifier] existente.
+
+```dart
+MyChangeNotifier variable;
+
+ChangeNotifierProvider.value(
+ value: variable,
+ child: ...
+)
+```
+
+- **DON'T** reutiliza un [ChangeNotifier] existente usando su constructor por defecto.
+
+```dart
+MyChangeNotifier variable;
+
+ChangeNotifierProvider(
+ create: (_) => variable,
+ child: ...
+)
+```
+
+### Leyendo un valor
+
+La manera mas fácil de leer un valor es usando los métodos de su extensión en [BuildContext]:
+
+- `context.watch<T>()`, el cual hace que el widget escuche los cambios en `T`.
+- `context.read<T>()`, este regresa `T` sin escucharlo.
+- `context.select<T, R>(R cb(T value))`, permite al widget escuchar solo una pequeña parte de `T`.
+
+O utiliza el método estático `Provider.of<T>(context)`, el cual se comporta similar a `watch` y cuando le pasa el valor `false`
+al parámetro `listen` como `Provider.of<T>(context, liste: false)` se comportará similar a `read`
+
+Vale la pena decir que `context.read<T>()` no hará que tu widget haga un rebuild cuando el valor cambia y no puede ser
+llamado dentro de `StatelessWidget.build`/`State.build`. Por otro lado, puede ser llamado libremente fuera de estos métodos.
+
+Estos métodos buscarán en el árbol de los widgets a partir del widget asociado
+con el `BuildContext` pasado, y devolverá la variable de tipo más cercano
+`T` encontrada (o lanzara una `exception` si no encuentra nada).
+
+Vale la pena señalar que esta operación es O(1). No implica realmente recorrer
+en el árbol de los widgets.
+
+Combinado con el primer ejemplo de [exponer un valor](#exposing-a-value), este
+el widget leerá el `String` expuesto y mostrará "Hola Mundo".
+
+```dart
+class Home extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return Text(
+ // Don't forget to pass the type of the object you want to obtain to `watch`!
+ context.watch<String>(),
+ );
+ }
+}
+```
+
+Otra opción, en lugar de utilizar estos métodos, podemos usar [Consumer] y [Selector].
+
+Estos pueden ayudar a optimizar el desempeño o cuando es difícil de obtener
+el `BuildContext` descendiente del provider
+
+Ve las [FAQ](https://github.com/rrousselGit/provider#my-widget-rebuilds-too-often-what-can-i-do) o la documentación de [Consumer](https://pub.dev/documentation/provider/latest/provider/Consumer-class.html)
+y [Selector](https://pub.dev/documentation/provider/latest/provider/Selector-class.html) para más información.
+
+### MultiProvider
+
+Cuando inyectamos muchos valores en una aplicación grande, `Provider` puede convertirse
+muy anidado rápidamente.
+
+```dart
+Provider<Something>(
+ create: (_) => Something(),
+ child: Provider<SomethingElse>(
+ create: (_) => SomethingElse(),
+ child: Provider<AnotherThing>(
+ create: (_) => AnotherThing(),
+ child: someWidget,
+ ),
+ ),
+),
+```
+
+A:
+
+```dart
+MultiProvider(
+ providers: [
+ Provider<Something>(create: (_) => Something()),
+ Provider<SomethingElse>(create: (_) => SomethingElse()),
+ Provider<AnotherThing>(create: (_) => AnotherThing()),
+ ],
+ child: someWidget,
+)
+```
+
+El comportamiento de ambos ejemplos es el mismo. `Multiprovider` solo cambia la
+apariencia del código.
+
+### ProxyProvider
+
+Desde la versión 3.0.0, existe un nuevo tipo de provider: `ProxyProvider`.
+
+`ProxyProvider` es un provider que combina múltiples valores de otros provider
+dentro de un nuevo objeto, y envía el resultado a `Provider`.
+
+Este nuevo objeto será actualizado cuando uno de los providers de los que depende
+sea actualizado.
+
+El siguiente ejemplo usa `ProxyProvider` para construir una traducción de acuerdo a un contador
+que viene de otro provider.
+
+```dart
+Widget build(BuildContext context) {
+ return MultiProvider(
+ providers: [
+ ChangeNotifierProvider(create: (_) => Counter()),
+ ProxyProvider<Counter, Translations>(
+ update: (_, counter, __) => Translations(counter.value),
+ ),
+ ],
+ child: Foo(),
+ );
+}
+
+class Translations {
+ const Translations(this._value);
+
+ final int _value;
+
+ String get title => 'You clicked $_value times';
+}
+```
+
+Viene con múltiples variaciones, tales como:
+
+- `ProxyProvider` vs `ProxyProvider2` vs `ProxyProvider3`, ...
+
+ El dígito después del nombre de la clase es el número de providers que
+ `ProxyProvider` depende.
+
+- `ProxyProvider` vs `ChangeNotifierProxyProvider` vs `ListenableProxyProvider`, ...
+
+ Todos trabajan de manera similar, pero en lugar de enviar el resultado del `Provider`,
+ el `ChangeNotifierProxyProvider` enviará su valor a un `ChangeNotifierProvider`.
+
+### FAQ
+
+#### Puedo ver el contenido de mis objetos?
+
+Flutter viene con [devtools](https://github.com/flutter/devtools), el cual muestra
+cómo el árbol de widgets, está en un momento determinado.
+
+Ya que los providers son widgets, también son visibles en las devtools:
+
+<img src="https://raw.githubusercontent.com/rrousselGit/provider/master/resources/devtools_providers.jpg" width="200" />
+
+De ahí, si tu presionas un provider, serás capaz de ver los valores que contiene:
+
+<img src="https://raw.githubusercontent.com/rrousselGit/provider/master/resources/expanded_devtools.jpg" width="200" />
+
+(screenshot de las devtools usando la carpeta de `example`)
+
+#### Devtool solo muestran "Instance of MyClass". Que puedo hacer?
+
+Por defecto, devtool necesita `toString`, el cual por defecto es "Instance of MyClass".
+
+Para algo más útil, tienes dos opciones:
+
+- Usa el API [Diagnosticable](https://api.flutter.dev/flutter/foundation/Diagnosticable-class.html) de Flutter.
+
+ Para la mayoría de los casos, esto se logrará utilizando [DiagnosticableTreeMixin]
+ en tus objetos, siguiendo la implementación personalizada de [debugFillProperties](https://api.flutter.dev/flutter/foundation/DiagnosticableTreeMixin/debugFillProperties.html).
+
+ ```dart
+ class MyClass with DiagnosticableTreeMixin {
+ MyClass({this.a, this.b});
+
+ final int a;
+ final String b;
+
+ @override
+ void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+ super.debugFillProperties(properties);
+ // list all the properties of your class here.
+ // See the documentation of debugFillProperties for more information.
+ properties.add(IntProperty('a', a));
+ properties.add(StringProperty('b', b));
+ }
+ }
+ ```
+
+- override `toString`.
+
+ Si no puedes usar [DiagnosticableTreeMixin] (como si tu clase estuviera en un paquete
+ que no depende de Flutter), entonces puedes simplemente usar el método override `toString`.
+
+ Esto es más fácil que usar [DiagnosticableTreeMixin] pero es menos poderoso:
+ No podrás expandir/contraer los detalles de tu objeto.
+
+ ```dart
+ class MyClass with DiagnosticableTreeMixin {
+ MyClass({this.a, this.b});
+
+ final int a;
+ final String b;
+
+ @override
+ String toString() {
+ return '$runtimeType(a: $a, b: $b)';
+ }
+ }
+ ```
+
+#### Me aparece una exception cuando obtengo Providers dentro de `initState`. Que puedo hacer?
+
+Esta excepción ocurre porque estás tratando de escuchar a un provider de un
+life-cycle que nunca jamás será llamado de nuevo.
+
+Significa que debes usar otro ciclo de vida (`build`), o explícitamente
+específica que no te importan las actualizaciones.
+
+Entonces, en lugar de:
+
+```dart
+initState() {
+ super.initState();
+ print(context.watch<Foo>().value);
+}
+```
+
+puedes hacer esto:
+
+```dart
+Value value;
+
+Widget build(BuildContext context) {
+ final value = context.watch<Foo>.value;
+ if (value != this.value) {
+ this.value = value;
+ print(value);
+ }
+}
+```
+
+El cual imprime `value` cuando sea que cambie (y solo cuando cambie)
+
+También puedes hacer esto:
+
+```dart
+initState() {
+ super.initState();
+ print(context.read<Foo>().value);
+}
+```
+
+El cual imprimirá `value` una vez _e ignorará las actualizaciones._
+
+#### Como manejar hot-reload en mis objetos?
+
+Puedes hacer que el objeto de tu provider implemente `ReassembleHandler`:
+
+```dart
+class Example extends ChangeNotifier implements ReassembleHandler {
+ @override
+ void reassemble() {
+ print('Did hot-reload');
+ }
+}
+```
+
+Después úsalo de forma normal con `provider`:
+
+```dart
+ChangeNotifierProvider(create: (_) => Example()),
+```
+
+#### Utilizo [ChangeNotifier] y tengo una exception cuando se actualiza, que sucede?
+
+Es probable que esto ocurra porque se está modificando el [ChangeNotifier] de uno de
+sus descendientes, _mientras que el árbol de los widgets se está construyendo_.
+
+Una situación típica en la que esto ocurre es cuando se inicia una petición http, donde
+el futuro está almacenado dentro del notifier:
+
+
+```dart
+initState() {
+ super.initState();
+ context.read<MyNotifier>().fetchSomething();
+}
+```
+
+Esto no está permitido, porque la actualización es inmediata.
+
+Lo que significa que algunos widgets pueden construir _antes_ de la mutación, mientras que otros
+widgets construirán _después_ de la mutación.
+Esto podría causar inconsistencias en su UI y por lo tanto no está permitido.
+
+En su lugar, deberías realizar esa mutación en un lugar que afectará a todo
+el árbol por igual:
+
+- directamente dentro del `create` de tu provider/constructor de tu modelo:
+
+ ```dart
+ class MyNotifier with ChangeNotifier {
+ MyNotifier() {
+ _fetchSomething();
+ }
+
+ Future<void> _fetchSomething() async {}
+ }
+ ```
+
+ Esto es útil cuando no existe un "parámetro externo".
+
+- asincronamente al final del frame
+ ```dart
+ initState() {
+ super.initState();
+ Future.microtask(() =>
+ context.read<MyNotifier>(context).fetchSomething(someValue);
+ );
+ }
+ ```
+ Esto es ligeramente menos ideal, pero permite pasar parámetros a la mutación.
+
+#### Tengo que usar [ChangeNotifier] para estados complejos?
+
+No.
+
+Puedes utilizar un objeto para representar tu estado. Por ejemplo, otra opción
+es usar la arquitectura de `Provider.value()` combinada con `StatefulWidget`.
+
+Aquí está un ejemplo del counter usando tal arquitectura:
+
+```dart
+class Example extends StatefulWidget {
+ const Example({Key key, this.child}) : super(key: key);
+
+ final Widget child;
+
+ @override
+ ExampleState createState() => ExampleState();
+}
+
+class ExampleState extends State<Example> {
+ int _count;
+
+ void increment() {
+ setState(() {
+ _count++;
+ });
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return Provider.value(
+ value: _count,
+ child: Provider.value(
+ value: this,
+ child: widget.child,
+ ),
+ );
+ }
+}
+```
+
+donde podemos leer el estado haciendo esto:
+
+```dart
+return Text(context.watch<int>().toString());
+```
+
+y modificar el estado con:
+
+```dart
+return FloatingActionButton(
+ onPressed: () => context.read<ExampleState>().increment(),
+ child: Icon(Icons.plus_one),
+);
+```
+
+También, puedes crear tu propio provider.
+
+#### Puedo hacer mi propio Provider?
+
+Si. `provider` muestra todos los pequeños componentes para hacer el tuyo.
+
+Esto incluye:
+
+- `SingleChildStatelessWidget`, para hacer que el widget funcione con `MultiProvider`.
+ Esta interfaz es expuesta como parte de `package:provider/single_child_widget`
+
+- [InheritedProvider], el `InheritedWidget` genérico obtenido cuando hacemos `context.watch`.
+
+Aquí está un ejemplo de un provider personalizado para usar `ValueNotifier` como estado:
+https://gist.github.com/rrousselGit/4910f3125e41600df3c2577e26967c91
+
+#### Mi widget hace muchos rebuilds, que puedo hacer?
+
+En lugar de usar `context.watch`, puedes usar `context.select` para escuchar solo a un conjunto
+específico de propiedades en el objeto obtenido
+
+Por ejemplo, podrías escribir esto:
+
+```dart
+Widget build(BuildContext context) {
+ final person = context.watch<Person>();
+ return Text(person.name);
+}
+```
+
+Podría provocar que el widget haga rebuild, si otro aparte de `name` cambia.
+
+En su lugar, puedes usar `context.select` para escuchar solo los cambios en la propiedad `name`:
+
+```dart
+Widget build(BuildContext context) {
+ final name = context.select((Person p) => p.name);
+ return Text(name);
+}
+```
+
+De esta manera, el widget no realizará rebuilds innecesarios si algo aparte de `name` cambia.
+
+Similarmente, puedes utilizar [Consumer]/[Selector].
+Su propiedad `child` opcional permite solo hacer rebuild en una parte especifica del
+árbol de widgets.
+
+```dart
+Foo(
+ child: Consumer<A>(
+ builder: (_, a, child) {
+ return Bar(a: a, child: child);
+ },
+ child: Baz(),
+ ),
+)
+```
+
+En este ejemplo, solo `Bar` hará un rebuild cuando `A` actualice. `Foo` y `Baz` no harán builds
+innecesarios.
+
+#### Puedo obtener dos providers diferentes usando el mismo tipo?
+
+No. Aunque puedes tener varios providers compartiendo el mismo tipo, un widget
+será capaz de obtener sólo uno de ellos: el ancestro más cercano.
+
+En cambio, debe dar explícitamente a ambos proveedores un tipo diferente
+
+En lugar de:
+
+```dart
+Provider<String>(
+ create: (_) => 'England',
+ child: Provider<String>(
+ create: (_) => 'London',
+ child: ...,
+ ),
+),
+```
+
+Utiliza:
+
+```dart
+Provider<Country>(
+ create: (_) => Country('England'),
+ child: Provider<City>(
+ create: (_) => City('London'),
+ child: ...,
+ ),
+),
+```
+
+#### Puedo consumir una interfaz y proveer una implementación?
+
+Sí, se debe dar una pista del tipo al compilador para indicar que la interfaz se consumirá, con la implementación prevista en create.
+
+```dart
+abstract class ProviderInterface with ChangeNotifier {
+ ...
+}
+
+class ProviderImplementation with ChangeNotifier implements ProviderInterface {
+ ...
+}
+
+class Foo extends StatelessWidget {
+ @override
+ build(context) {
+ final provider = Provider.of<ProviderInterface>(context);
+ return ...
+ }
+}
+
+ChangeNotifierProvider<ProviderInterface>(
+ create: (_) => ProviderImplementation(),
+ child: Foo(),
+),
+```
+
+### Providers existentes
+
+`provider` nos muestra algunos tipos diferentes de "provider" para diferentes tipos de objetos.
+
+La lista completa de todos los objetos disponibles esta [aquí](https://pub.dev/documentation/provider/latest/provider/provider-library.html)
+
+| Nombre | Descripción |
+| ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| [Provider](https://pub.dartlang.org/documentation/provider/latest/provider/Provider-class.html) | La forma más básica de provider. Toma un valor y lo expone, sea cual sea el valor. |
+| [ListenableProvider](https://pub.dartlang.org/documentation/provider/latest/provider/ListenableProvider-class.html) | Un proveedor específico para el objeto Listenable. ListenableProvider escuchará el objeto y pedirá a los widgets que dependen de él que lo reconstruyan siempre que se llame al listener. |
+| [ChangeNotifierProvider](https://pub.dartlang.org/documentation/provider/latest/provider/ChangeNotifierProvider-class.html) | Se especifica el tipo de ListenableProvider para ChangeNotifier. Este llamará automáticamente `ChangeNotifier.dispose` cuando lo necesite. |
+| [ValueListenableProvider](https://pub.dartlang.org/documentation/provider/latest/provider/ValueListenableProvider-class.html) | Escucha al ValueListenable y solo muestra `ValueListenable.value`. |
+| [StreamProvider](https://pub.dartlang.org/documentation/provider/latest/provider/StreamProvider-class.html) | Escucha a un Stream y muestra el último valor emitido. |
+| [FutureProvider](https://pub.dartlang.org/documentation/provider/latest/provider/FutureProvider-class.html) | Toma un `Future` y actualiza a sus dependientes cuando el futuro es completado. |
+
+[provider.of]: https://pub.dev/documentation/provider/latest/provider/Provider/of.html
+[selector]: https://pub.dev/documentation/provider/latest/provider/Selector-class.html
+[consumer]: https://pub.dev/documentation/provider/latest/provider/Consumer-class.html
+[changenotifier]: https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html
+[inheritedwidget]: https://api.flutter.dev/flutter/widgets/InheritedWidget-class.html
+[inheritedprovider]: https://pub.dev/documentation/provider/latest/provider/InheritedProvider-class.html
+[diagnosticabletreemixin]: https://api.flutter.dev/flutter/foundation/DiagnosticableTreeMixin-mixin.html