Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove empty state #11

Merged
merged 8 commits into from
May 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions .chglog/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ options:
- remove
- deprecate
- refactor
- docs
commit_groups:
title_maps:
feat: Added
fix: Fixed
remove: Removed
deprecate: Deprecated
refactor: Changed
docs: Documented
header:
pattern: "^(\\w*)\\:\\s(.*)$"
pattern_maps:
Expand Down
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ class HomePage extends StatelessWidget {
//3. Render state changes
counterState.when(
initial: () => Text('Not loaded', style: textStyle),
empty: () => Text('Never', style: textStyle),
success: (value) => Text('$value', style: textStyle),
loading: () => Text('Loading...', style: textStyle),
error: (_) => Text('Error', style: textStyle),
Expand Down Expand Up @@ -152,10 +151,6 @@ class HomePage extends StatelessWidget {

`RemoteState.success` is an instance of RemoteState that signifies the request has completed successfully and the new data (of type T) is available.

### RemoteState.empty

`RemoteState.success` is an instance of RemoteState that signifies the has completed successfully with an empty response.

### RemoteState.error

`RemoteState.error` is an instance of RemoteState that signifies the request has failed.
Expand All @@ -178,6 +173,24 @@ The `map` method is the equivalent of `when` without the destructuring.

The `maybeWhen` method is the equivalent of `when` without the destructuring.

## State Predicates

### isInitial

The `isInitial` predicate returns true if we haven't asked for data yet.

### isLoading

The `isLoading` predicate returns true if we're loading.

### isSuccess

The `isSuccess` predicate returns true if we've successfully loaded some data.

### isError

The `isError` predicate returns true if we've failed to load some data.

## Maintainers

- [Ryan Edge](https://github.com/chimon2000)
Expand Down
3 changes: 1 addition & 2 deletions examples/counter_bloc/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,9 @@ class HomePage extends StatelessWidget {
BlocBuilder<CounterBloc, RemoteState<int>>(
builder: (_, state) => state.when(
initial: () => Text('Not loaded', style: textStyle),
empty: () => Text('Never', style: textStyle),
success: (value) => Text('$value', style: textStyle),
loading: () => Text('Loading...', style: textStyle),
error: (_) => Text('Error', style: textStyle),
error: (_, __) => Text('Error', style: textStyle),
),
)
],
Expand Down
3 changes: 1 addition & 2 deletions examples/counter_state_notifier/lib/home.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ class HomePage extends StatelessWidget {
//3. Render state changes
counterState.when(
initial: () => Text('Not loaded', style: textStyle),
empty: () => Text('Never', style: textStyle),
success: (value) => Text('$value', style: textStyle),
loading: () => Text('Loading...', style: textStyle),
error: (_) => Text('Error', style: textStyle),
error: (_, __) => Text('Error', style: textStyle),
),
],
),
Expand Down
5 changes: 0 additions & 5 deletions packages/remote_state/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ class HomePage extends StatelessWidget {
//3. Render state changes
counterState.when(
initial: () => Text('Not loaded', style: textStyle),
empty: () => Text('Never', style: textStyle),
success: (value) => Text('$value', style: textStyle),
loading: () => Text('Loading...', style: textStyle),
error: (_) => Text('Error', style: textStyle),
Expand Down Expand Up @@ -152,10 +151,6 @@ class HomePage extends StatelessWidget {

`RemoteState.success` is an instance of RemoteState that signifies the request has completed successfully and the new data (of type T) is available.

### RemoteState.empty

`RemoteState.success` is an instance of RemoteState that signifies the has completed successfully with an empty response.

### RemoteState.error

`RemoteState.error` is an instance of RemoteState that signifies the request has failed.
Expand Down
5 changes: 2 additions & 3 deletions packages/remote_state/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class _HomePageState extends State<HomePage> {
});
await Future.delayed(Duration(seconds: 1));
setState(() {
counterState = RemoteState.empty();
counterState = RemoteState.success(0);
});
}

Expand Down Expand Up @@ -80,10 +80,9 @@ class _HomePageState extends State<HomePage> {
//3. Render state changes
counterState.when(
initial: () => Text('Not loaded', style: textStyle),
empty: () => Text('Zero', style: textStyle),
success: (value) => Text('$value', style: textStyle),
loading: () => Text('Loading...', style: textStyle),
error: (_) => Text('Error', style: textStyle),
error: (_, __) => Text('Error', style: textStyle),
),
],
),
Expand Down
18 changes: 1 addition & 17 deletions packages/remote_state/example/test/widget_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,5 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:example/main.dart';

void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
await tester.pumpWidget(MyApp());
await tester.pump(Duration(seconds: 1));

// Verify that our counter starts at 0.
expect(find.text('Zero'), findsOneWidget);
expect(find.text('1'), findsNothing);

// Tap the '+' icon and trigger a frame.
await tester.tap(find.byIcon(Icons.add));
await tester.pump(Duration(seconds: 1));

// Verify that our counter has incremented.
expect(find.text('0'), findsNothing);
expect(find.text('1'), findsOneWidget);
});
testWidgets('Counter increments smoke test', (tester) async {});
}
47 changes: 26 additions & 21 deletions packages/remote_state/lib/remote_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,16 @@ part 'remote_state.freezed.dart';
@freezed
abstract class RemoteState<T> with _$RemoteState<T> {
/// We haven't asked for the data yet.
const factory RemoteState.initial() = _Initial<T>;
factory RemoteState.initial() = _Initial<T>;

/// We've asked, but haven't got an answer yet.
const factory RemoteState.loading() = _Loading<T>;
factory RemoteState.loading() = _Loading<T>;

/// Everything worked, and here's the data.
const factory RemoteState.success(T value) = _Success<T>;

/// Everything worked, and there's no data.
const factory RemoteState.empty() = _Empty<T>;
factory RemoteState.success(T value) = _Success<T>;

/// We asked, but something went wrong. Here's the error.
const factory RemoteState.error([String message]) = _Error<T>;
factory RemoteState.error([dynamic error, StackTrace stackTrace]) = _Error<T>;

/// Defines logic based on the current state.
///
Expand All @@ -43,15 +40,12 @@ abstract class RemoteState<T> with _$RemoteState<T> {
///
/// [success] determines what to do if the state matches [RemoteState.success]
///
/// [empty] determines what to do if the state matches [RemoteState.empty]
///
/// [error] determines what to do if the state matches [RemoteState.error]
Result when<Result extends Object>({
@required Result initial(),
@required Result loading(),
@required Result success(T value),
@required Result empty(),
@required Result error(String message),
@required Result error(dynamic error, StackTrace stackTrace),
});

/// Defines logic based on the current state with a fallback for unhandled states.
Expand All @@ -68,17 +62,14 @@ abstract class RemoteState<T> with _$RemoteState<T> {
///
/// [success] determines what to do if the state matches [RemoteState.success]
///
/// [empty] determines what to do if the state matches [RemoteState.empty]
///
/// [error] determines what to do if the state matches [RemoteState.error]
///
/// [orElse] determines what to do if no match is found
Result maybeWhen<Result extends Object>({
Result initial(),
Result loading(),
Result success(T value),
Result empty(),
Result error(String message),
Result error(dynamic error, StackTrace stackTrace),
@required Result orElse(),
});

Expand All @@ -94,14 +85,11 @@ abstract class RemoteState<T> with _$RemoteState<T> {
///
/// [success] determines what to do if the state matches [RemoteState.success]
///
/// [empty] determines what to do if the state matches [RemoteState.empty]
///
/// [error] determines what to do if the state matches [RemoteState.error]
Result map<Result extends Object>({
@required Result initial(_Initial<T> value),
@required Result loading(_Loading<T> value),
@required Result success(_Success<T> value),
@required Result empty(_Empty<T> value),
@required Result error(_Error<T> value),
});

Expand All @@ -117,17 +105,34 @@ abstract class RemoteState<T> with _$RemoteState<T> {
///
/// [success] determines what to do if the state matches [RemoteState.success]
///
/// [empty] determines what to do if the state matches [RemoteState.empty]
///
/// [error] determines what to do if the state matches [RemoteState.error]
///
/// [orElse] determines what to do if no match is found
Result maybeMap<Result extends Object>({
Result initial(_Initial<T> value),
Result loading(_Loading<T> value),
Result success(_Success<T> value),
Result empty(_Empty<T> value),
Result error(_Error<T> value),
@required Result orElse(),
});

/// State-checking predicate. Returns true if we haven't asked for data yet.
/// Returns true only if [RemoteState] is [RemoteState.initial]
@late
bool get isInitial => maybeWhen(initial: () => true, orElse: () => false);

/// State-checking predicate. Returns true if we're loading.
/// Returns true only if [RemoteState] is [RemoteState.loading]
@late
bool get isLoading => maybeWhen(loading: () => true, orElse: () => false);

/// State-checking predicate. Returns true if we've successfully loaded some data.
/// Returns true only if [RemoteState] is [RemoteState.success]
@late
bool get isSuccess => maybeWhen(success: (_) => true, orElse: () => false);

/// State-checking predicate. Returns true if we've failed to load some data.
/// Returns true only if [RemoteState] is [RemoteState.error]
@late
bool get isError => maybeWhen(error: (_, __) => true, orElse: () => false);
}
Loading