Skip to content

Commit aad4eef

Browse files
authored
Release 0.11.0 (#26)
1 parent 0c78b06 commit aad4eef

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1093
-342
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,6 @@ build/
7171
!**/ios/**/default.pbxuser
7272
!**/ios/**/default.perspectivev3
7373
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
74+
75+
# Test Coverage
76+
coverage

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## [0.11.0]
4+
5+
* Migrating to `bloc` 8.1.x and `flutter_bloc` 8.1.x,
6+
* `ConnectionBloc` - a BLoC that exposes the Internet connection state to the UI.
7+
38
## [0.10.0]
49

510
* Migrating to `bloc` 8.0.x and `flutter_bloc` 8.0.x,

README.md

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ A `Repository` to handles data operations. It knows where to get the data from a
3232
* `onEmpty` - informs the presentation layer that the loading is completed, but `null` or empty data was retrieved,
3333
* `onError` - informs the presentation layer that the loading or refreshing has ended with an error. It also provides an error that has occurred.
3434

35-
3635
## Features
3736

3837
### ListBloc
@@ -117,6 +116,7 @@ Where:
117116
[Paged List BLoC Sample App](example/lib/src/list_paged_filter_app.dart)
118117

119118
### DetailsBloc
119+
120120
A BLoC that allows to fetch a single item with given identifier.
121121

122122
#### DetailsRepository
@@ -132,6 +132,62 @@ Where:
132132

133133
[List/Details BLoC Sample App](example/lib/src/list_details_app.dart)
134134

135+
### ConnectionBloc
136+
137+
A BLoC that exposes the Internet connection state to the UI.
138+
139+
#### Connection
140+
141+
The Internet connection state. It can be either `online` or `offline`.
142+
143+
#### ConnectionRepository
144+
145+
`ConnectionRepository` notifies about connection state changes, such as going online or offline.
146+
147+
Please notice, that this is only a contract and a developer needs to provide an implementation. This can be done using one of many popular packages, like:
148+
149+
* [connectivity_plus](https://pub.dev/packages/connectivity_plus)
150+
* [internet_connection_checker](https://pub.dev/packages/internet_connection_checker)
151+
152+
Or whatever works for you. A sample implementation using `connectivity_plus` may look as follows:
153+
154+
```dart
155+
class ConnectivityPlusRepository implements ConnectionRepository {
156+
@override
157+
Stream<Connection> observe() {
158+
return connectivity.onConnectivityChanged.map(
159+
(ConnectivityResult result) => result != ConnectivityResult.none
160+
? Connection.online
161+
: Connection.offline,
162+
);
163+
}
164+
}
165+
```
166+
167+
#### ConnectionBuilder
168+
169+
`ConnectionBuilder` is responsible for building the UI based `Connection` state.
170+
171+
It's a wrapper over the `BlocBuilder` widget so it accepts a `bloc` object and provides `WidgetBuilder` functions for possible states:
172+
173+
* `onOnline` - a builder for the the `Connection.online` state,
174+
* `onOffline` - a builder for the the `Connection.offline` state,
175+
176+
#### ConnectionListener
177+
178+
`ConnectionListener` is responsible for performing a one-time action based on the `Connection` state change.
179+
180+
It should be used for functionality that needs to occur only once in response to the `Connection` state change such as navigation, `SnackBar`, showing a `Dialog`, etc.
181+
182+
`ConnectionListener` is a wrapper over the `BlocListener` widget so it accepts a `bloc` object as well as a `child` widget. It also takes `ConnectionCallback` functions for possible states:
183+
184+
* `onOnline` - a callback for the the `Connection.online` state,
185+
* `onOffline` - a callback for the `Connection.offline` state.
186+
187+
#### Usage:
188+
189+
[Connection Sample App](example/lib/src/connection_app.dart)
190+
135191
## Dart version
136192

137193
- Dart 2: >= 2.12.0

analysis_options.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,7 @@
11
include: package:lint/analysis_options.yaml
2+
lintner:
3+
rules:
4+
always_specify_types: true
5+
avoid_classes_with_only_static_members: true
6+
lines_longer_than_80_chars: true
7+
prefer_single_quotes: true

example/lib/src/album/ui/photos_list_empty.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'package:flutter/material.dart';
22

33
class PhotosListEmpty extends StatelessWidget {
4-
const PhotosListEmpty({Key? key}) : super(key: key);
4+
const PhotosListEmpty({super.key});
55

66
@override
77
Widget build(BuildContext context) {

example/lib/src/album/ui/photos_list_paged.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ class PhotosListPaged extends StatelessWidget {
1010

1111
const PhotosListPaged(
1212
this.page, {
13-
Key? key,
13+
super.key,
1414
required this.onLoadNextPage,
15-
}) : super(key: key);
15+
});
1616

1717
@override
1818
Widget build(BuildContext context) {
1919
return InfiniteListView.separated(
20-
itemBuilder: (context, index) => _PhotoGridItem(page.items[index]),
20+
itemBuilder: (context, index) => PhotoGridItem(page.items[index]),
2121
separatorBuilder: (context, index) => const Divider(),
2222
itemCount: page.items.length,
2323
hasNext: page.hasMoreItems,
@@ -27,13 +27,13 @@ class PhotosListPaged extends StatelessWidget {
2727
}
2828
}
2929

30-
class _PhotoGridItem extends StatelessWidget {
30+
class PhotoGridItem extends StatelessWidget {
3131
final Photo photo;
3232

33-
const _PhotoGridItem(
33+
const PhotoGridItem(
3434
this.photo, {
35-
Key? key,
36-
}) : super(key: key);
35+
super.key,
36+
});
3737

3838
@override
3939
Widget build(BuildContext context) {

example/lib/src/common/error_message.dart

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ import 'package:flutter/widgets.dart';
33
class ErrorMessage extends StatelessWidget {
44
final Object error;
55

6-
const ErrorMessage({
7-
required this.error,
8-
Key? key,
9-
}) : super(key: key);
6+
const ErrorMessage({required this.error, super.key});
107

118
@override
129
Widget build(BuildContext context) {

example/lib/src/common/loading_indicator.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'package:flutter/material.dart';
22

33
class LoadingIndicator extends StatelessWidget {
4-
const LoadingIndicator({Key? key}) : super(key: key);
4+
const LoadingIndicator({super.key});
55

66
@override
77
Widget build(BuildContext context) {

example/lib/src/common/loading_page_indicator.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'package:flutter/material.dart';
22

33
class LoadingPageIndicator extends StatelessWidget {
4-
const LoadingPageIndicator({Key? key}) : super(key: key);
4+
const LoadingPageIndicator({super.key});
55

66
@override
77
Widget build(BuildContext context) {
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import 'package:connectivity_plus/connectivity_plus.dart';
2+
import 'package:example/src/list_app.dart';
3+
import 'package:example/src/post/model/post.dart';
4+
import 'package:example/src/post/model/post_repository.dart';
5+
import 'package:example/src/tools/connection/connectivity_plus_repository.dart';
6+
import 'package:flutter/material.dart';
7+
import 'package:flutter_bloc/flutter_bloc.dart';
8+
import 'package:flutter_bloc_patterns/base_list.dart';
9+
import 'package:flutter_bloc_patterns/connection.dart';
10+
11+
void main() => runApp(ConnectionApp());
12+
13+
typedef PostsBloc = ListBloc<Post>;
14+
15+
class ConnectionApp extends StatelessWidget {
16+
@override
17+
Widget build(BuildContext context) {
18+
return MaterialApp(
19+
title: 'Connection App',
20+
theme: ThemeData(primarySwatch: Colors.green),
21+
home: MultiBlocProvider(
22+
providers: [
23+
BlocProvider(
24+
create: (_) => ListBloc<Post>(PostListRepository()),
25+
),
26+
BlocProvider(
27+
create: (_) => ConnectionBloc(
28+
ConnectivityPlusRepository(Connectivity()),
29+
),
30+
),
31+
],
32+
child: const ConnectionPage(),
33+
),
34+
);
35+
}
36+
}
37+
38+
class ConnectionPage extends StatefulWidget {
39+
const ConnectionPage({super.key});
40+
41+
@override
42+
State<ConnectionPage> createState() => _ConnectionPageState();
43+
}
44+
45+
class _ConnectionPageState extends State<ConnectionPage> {
46+
@override
47+
void initState() {
48+
super.initState();
49+
context.read<PostsBloc>().loadItems();
50+
}
51+
52+
@override
53+
Widget build(BuildContext context) {
54+
return Scaffold(
55+
appBar: AppBar(title: const Text('Posts')),
56+
body: ConnectionListener(
57+
onOnline: _showOnlineSnackbar,
58+
onOffline: _showOfflineSnackbar,
59+
child: ConnectionBuilder(
60+
onOnline: (context) => const PostsViewStateBuilder(),
61+
onOffline: (context) => const OfflineView(),
62+
),
63+
),
64+
);
65+
}
66+
67+
void _showOnlineSnackbar(BuildContext context) {
68+
ScaffoldMessenger.of(context).showSnackBar(
69+
SnackBar(
70+
content: const Text('You are back online.'),
71+
backgroundColor: Colors.green[300],
72+
),
73+
);
74+
}
75+
76+
void _showOfflineSnackbar(BuildContext context) {
77+
ScaffoldMessenger.of(context).showSnackBar(
78+
SnackBar(
79+
content: const Text('You are offline.'),
80+
backgroundColor: Colors.red[300],
81+
),
82+
);
83+
}
84+
}
85+
86+
class OfflineView extends StatelessWidget {
87+
const OfflineView({super.key});
88+
89+
@override
90+
Widget build(BuildContext context) {
91+
return Center(
92+
child: Column(
93+
mainAxisAlignment: MainAxisAlignment.center,
94+
children: [
95+
const Icon(Icons.signal_wifi_0_bar_rounded, size: 64),
96+
const SizedBox(height: 16),
97+
Text(
98+
'You are offline. Check your Internet connection.',
99+
style: Theme.of(context).textTheme.bodyText2,
100+
)
101+
],
102+
),
103+
);
104+
}
105+
}

0 commit comments

Comments
 (0)