Skip to content

Commit 1dbc23e

Browse files
yerzhantfelangel
authored andcommitted
refactor(flutter_login): use RepositoryProvider + dispose (#4365)
1 parent 6f21d97 commit 1dbc23e

File tree

7 files changed

+78
-36
lines changed

7 files changed

+78
-36
lines changed

examples/flutter_login/lib/app.dart

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,24 @@ import 'package:flutter_login/login/login.dart';
77
import 'package:flutter_login/splash/splash.dart';
88
import 'package:user_repository/user_repository.dart';
99

10-
class App extends StatefulWidget {
10+
class App extends StatelessWidget {
1111
const App({super.key});
1212

13-
@override
14-
State<App> createState() => _AppState();
15-
}
16-
17-
class _AppState extends State<App> {
18-
late final AuthenticationRepository _authenticationRepository;
19-
late final UserRepository _userRepository;
20-
21-
@override
22-
void initState() {
23-
super.initState();
24-
_authenticationRepository = AuthenticationRepository();
25-
_userRepository = UserRepository();
26-
}
27-
28-
@override
29-
void dispose() {
30-
_authenticationRepository.dispose();
31-
super.dispose();
32-
}
33-
3413
@override
3514
Widget build(BuildContext context) {
36-
return RepositoryProvider.value(
37-
value: _authenticationRepository,
15+
return MultiRepositoryProvider(
16+
providers: [
17+
RepositoryProvider(
18+
create: (_) => AuthenticationRepository(),
19+
dispose: (repository) => repository.dispose(),
20+
),
21+
RepositoryProvider(create: (_) => UserRepository()),
22+
],
3823
child: BlocProvider(
3924
lazy: false,
40-
create: (_) => AuthenticationBloc(
41-
authenticationRepository: _authenticationRepository,
42-
userRepository: _userRepository,
25+
create: (context) => AuthenticationBloc(
26+
authenticationRepository: context.read<AuthenticationRepository>(),
27+
userRepository: context.read<UserRepository>(),
4328
)..add(AuthenticationSubscriptionRequested()),
4429
child: const AppView(),
4530
),

packages/flutter_bloc/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 9.1.0
2+
3+
- feat: expose `dispose` callback on `RepositoryProvider` ([#4356](https://github.com/felangel/bloc/pull/4356))
4+
15
# 9.0.0
26

37
- fix: ensure widget is mounted before invoking listener ([#4237](https://github.com/felangel/bloc/pull/4237))

packages/flutter_bloc/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,16 @@ context.read<RepositoryA>();
426426
RepositoryProvider.of<RepositoryA>(context)
427427
```
428428

429+
Repositories that manage resources which must be disposed can do so via the `dispose` callback:
430+
431+
```dart
432+
RepositoryProvider(
433+
create: (context) => RepositoryA(),
434+
dispose: (context, repository) => repository.close(),
435+
child: ChildA(),
436+
);
437+
```
438+
429439
### MultiRepositoryProvider
430440

431441
**MultiRepositoryProvider** is a Flutter widget that merges multiple `RepositoryProvider` widgets into one.

packages/flutter_bloc/lib/src/bloc_provider.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import 'package:provider/provider.dart';
55
import 'package:provider/single_child_widget.dart';
66

77
/// {@template bloc_provider}
8-
/// Takes a [Create] function that is responsible for
8+
/// Takes a `create` function that is responsible for
99
/// creating the [Bloc] or [Cubit] and a [child] which will have access
1010
/// to the instance via `BlocProvider.of(context)`.
1111
/// It is used as a dependency injection (DI) widget so that a single instance
@@ -19,7 +19,7 @@ import 'package:provider/single_child_widget.dart';
1919
/// ```
2020
///
2121
/// It automatically handles closing the instance when used with [Create].
22-
/// By default, [Create] is called only when the instance is accessed.
22+
/// By default, `create` is called only when the instance is accessed.
2323
/// To override this behavior, set [lazy] to `false`.
2424
///
2525
/// ```dart
@@ -35,7 +35,7 @@ class BlocProvider<T extends StateStreamableSource<Object?>>
3535
extends SingleChildStatelessWidget {
3636
/// {@macro bloc_provider}
3737
const BlocProvider({
38-
required Create<T> create,
38+
required T Function(BuildContext context) create,
3939
Key? key,
4040
this.child,
4141
this.lazy = true,
@@ -52,7 +52,7 @@ class BlocProvider<T extends StateStreamableSource<Object?>>
5252
///
5353
/// A new [Bloc] or [Cubit] should not be created in `BlocProvider.value`.
5454
/// New instances should always be created using the
55-
/// default constructor within the [Create] function.
55+
/// default constructor within the `create` function.
5656
///
5757
/// ```dart
5858
/// BlocProvider.value(
@@ -76,7 +76,7 @@ class BlocProvider<T extends StateStreamableSource<Object?>>
7676
/// Defaults to `true`.
7777
final bool lazy;
7878

79-
final Create<T>? _create;
79+
final T Function(BuildContext context)? _create;
8080

8181
final T? _value;
8282

packages/flutter_bloc/lib/src/repository_provider.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import 'package:flutter/widgets.dart';
22
import 'package:provider/provider.dart';
33

44
/// {@template repository_provider}
5-
/// Takes a [Create] function that is responsible for creating the repository
5+
/// Takes a `create` function that is responsible for creating the repository
66
/// and a `child` which will have access to the repository via
77
/// `RepositoryProvider.of(context)`.
88
/// It is used as a dependency injection (DI) widget so that a single instance
@@ -28,14 +28,15 @@ import 'package:provider/provider.dart';
2828
class RepositoryProvider<T> extends Provider<T> {
2929
/// {@macro repository_provider}
3030
RepositoryProvider({
31-
required Create<T> create,
31+
required T Function(BuildContext context) create,
32+
void Function(T value)? dispose,
3233
Key? key,
3334
Widget? child,
3435
bool? lazy,
3536
}) : super(
3637
key: key,
3738
create: create,
38-
dispose: (_, __) {},
39+
dispose: (_, value) => dispose?.call(value),
3940
child: child,
4041
lazy: lazy,
4142
);

packages/flutter_bloc/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: flutter_bloc
22
description: Flutter Widgets that make it easy to implement the BLoC (Business Logic Component) design pattern. Built to be used with the bloc state management package.
3-
version: 9.0.0
3+
version: 9.1.0
44
repository: https://github.com/felangel/bloc/tree/master/packages/flutter_bloc
55
issue_tracker: https://github.com/felangel/bloc/issues
66
homepage: https://bloclibrary.dev

packages/flutter_bloc/test/repository_provider_test.dart

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,5 +356,47 @@ void main() {
356356
final counterText = counterFinder.evaluate().first.widget as Text;
357357
expect(counterText.data, '0');
358358
});
359+
360+
testWidgets('calls dispose callback when disposed', (tester) async {
361+
var disposeCalled = false;
362+
await tester.pumpWidget(
363+
MaterialApp(
364+
home: Scaffold(
365+
body: RepositoryProvider<Repository>(
366+
create: (_) => const Repository(0),
367+
dispose: (repository) {
368+
disposeCalled = true;
369+
expect(repository.data, equals(0));
370+
},
371+
child: Builder(
372+
builder: (context) => Text(
373+
'${context.read<Repository>().data}',
374+
key: const Key('value_data'),
375+
),
376+
),
377+
),
378+
floatingActionButton: Builder(
379+
builder: (context) => FloatingActionButton(
380+
onPressed: () => Navigator.of(context).pop(),
381+
child: const Icon(Icons.remove),
382+
),
383+
),
384+
),
385+
),
386+
);
387+
final repositoryFinder = find.byKey(const Key('value_data'));
388+
expect(repositoryFinder, findsOneWidget);
389+
390+
final repositoryText = repositoryFinder.evaluate().first.widget as Text;
391+
expect(repositoryText.data, '0');
392+
393+
final fabFinder = find.byType(FloatingActionButton);
394+
expect(fabFinder, findsOneWidget);
395+
396+
expect(disposeCalled, isFalse);
397+
await tester.tap(fabFinder);
398+
await tester.pumpAndSettle();
399+
expect(disposeCalled, isTrue);
400+
});
359401
});
360402
}

0 commit comments

Comments
 (0)