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

Improved view loading and error cases #87

Merged
merged 9 commits into from
Oct 24, 2023
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
8 changes: 7 additions & 1 deletion packages/flutter_rocket/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,10 @@
- Added end2end test on example
- Renamed `multi` `RocketModel` field to `all`
- Added `targetData` parameter on `request` method of `RocketRequest`
- Added `forEach` method to `Rocket`
- Added `forEach` method to `Rocket`

/// New Updates

## 0.0.4

* Update RocketView
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ void main() {
// Verify the 100 posts button exist.
expect(find.text('100 Posts'), findsOneWidget);

final Finder postButton = find.byKey(const Key('post'));
final Finder postButton = find.byKey(const Key('posts'));

// open posts screen
await tester.tap(postButton);
Expand All @@ -45,7 +45,7 @@ void main() {
await tester.pumpAndSettle();
expect(find.text('10 Users'), findsOneWidget);

final Finder userButton = find.byKey(const Key('user'));
final Finder userButton = find.byKey(const Key('users'));

// open users screen
await tester.tap(userButton);
Expand All @@ -69,7 +69,7 @@ void main() {
app.main();
await tester.pumpAndSettle();
expect(find.text('5000 Photos'), findsOneWidget);
final Finder photoButton = find.byKey(const Key('photo'));
final Finder photoButton = find.byKey(const Key('photos'));

// open photos screen
await tester.tap(photoButton);
Expand All @@ -80,7 +80,7 @@ void main() {
app.main();
await tester.pumpAndSettle();
expect(find.text('200 Todos'), findsOneWidget);
final Finder todosButton = find.byKey(const Key('todo'));
final Finder todosButton = find.byKey(const Key('todos'));

// open photos screen
await tester.tap(todosButton);
Expand Down
6 changes: 2 additions & 4 deletions packages/flutter_rocket/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: router.routeInformationParser,
routeInformationProvider: router.routeInformationProvider,
routerDelegate: router.routerDelegate,
routerConfig: router,
title: '🚀 Rocket Package 🚀',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
Expand Down Expand Up @@ -91,7 +89,7 @@ class Example extends StatelessWidget {
fontSize: 24.0,
color: Colors.brown),
),
onPressed: () => context.go("/$to")),
onPressed: () => context.go("/$to", extra: title)),
);
}
}
Expand Down
12 changes: 6 additions & 6 deletions packages/flutter_rocket/example/lib/router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ final router = GoRouter(
pageBuilder: (context, state) => NoTransitionPage<void>(
key: state.pageKey,
child: MiniView(
title: "MiniView",
title: state.extra.toString(),
),
),
),
Expand All @@ -32,7 +32,7 @@ final router = GoRouter(
pageBuilder: (context, state) => NoTransitionPage<void>(
key: state.pageKey,
child: CounterExample(
title: "Counter",
title: state.extra.toString(),
),
),
),
Expand All @@ -41,7 +41,7 @@ final router = GoRouter(
pageBuilder: (context, state) => NoTransitionPage<void>(
key: state.pageKey,
child: PostExample(
title: "Posts",
title: state.extra.toString(),
),
),
),
Expand All @@ -59,7 +59,7 @@ final router = GoRouter(
pageBuilder: (context, state) => NoTransitionPage<void>(
key: state.pageKey,
child: UserExample(
title: "Users",
title: state.extra.toString(),
),
),
),
Expand All @@ -68,7 +68,7 @@ final router = GoRouter(
pageBuilder: (context, state) => NoTransitionPage<void>(
key: state.pageKey,
child: PhotoExample(
title: "Photos",
title: state.extra.toString(),
),
),
),
Expand All @@ -84,7 +84,7 @@ final router = GoRouter(
pageBuilder: (context, state) => NoTransitionPage<void>(
key: state.pageKey,
child: TodosExample(
title: "Todos",
title: state.extra.toString(),
),
),
),
Expand Down
6 changes: 5 additions & 1 deletion packages/flutter_rocket/example/lib/views/photo_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ class PhotoExample extends StatelessWidget {
width: MediaQuery.of(context).size.width,
child: RocketView(
model: photo,
loader: const CircularProgressIndicator(),
onLoading: () {
return const Center(
child: CircularProgressIndicator(),
);
},
// get 5000 items
call: () => GetPhotos.getPhotos(photo),
builder: (context, modelState) {
Expand Down
6 changes: 5 additions & 1 deletion packages/flutter_rocket/example/lib/views/post_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ class PostExample extends StatelessWidget {
// callType: CallType.callAsStream,
// secondsOfStream: 1,
// customized your loading (default widget is CircularProgressIndicator)
loader: const CircularProgressIndicator(),
onLoading: () {
return const Center(
child: CircularProgressIndicator(),
);
},

// handle errors
onError: (RocketException exception, Function() reload) {
Expand Down
6 changes: 5 additions & 1 deletion packages/flutter_rocket/example/lib/views/todos_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ class TodosExample extends StatelessWidget {
body: RocketView(
model: todoModel,
call: () => GetTodos.getTodos(todoModel),
loader: const CircularProgressIndicator(),
onLoading: () {
return const Center(
child: CircularProgressIndicator(),
);
},
callType: CallType.callIfModelEmpty,
builder: (context, state) {
return ListView.builder(
Expand Down
6 changes: 5 additions & 1 deletion packages/flutter_rocket/example/lib/views/user_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ class UserExample extends StatelessWidget {
// your model
model: users,
// your widget for show data from model
loader: const CircularProgressIndicator(),
onLoading: () {
return const Center(
child: CircularProgressIndicator(),
);
},
builder: (context, modelState) {
return ListView.builder(
itemCount: users.all!.length,
Expand Down
3 changes: 2 additions & 1 deletion packages/flutter_rocket/example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.0

flutter_rocket: ^0.0.2
flutter_rocket:
path: ../
go_router: ^10.0.0


Expand Down
4 changes: 2 additions & 2 deletions packages/flutter_rocket/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: flutter_rocket
description: Powerful package for state management & request.
version: 0.0.3
version: 0.0.4
repository: https://github.com/JahezAcademy/flutter_rocket/flutter_rocket
issue_tracker: https://github.com/JahezAcademy/flutter_rocket/labels/flutter_rocket
homepage: https://github.com/JahezAcademy/flutter_rocket
Expand All @@ -14,7 +14,7 @@ dependencies:
sdk: flutter
rocket_model: ^0.0.2
rocket_listenable: ^0.0.1
rocket_view: ^0.0.1
rocket_view: ^0.0.2
rocket_mini_view: ^0.0.1
rocket_client: ^0.0.2
rocket_singleton: ^0.0.1
Expand Down
7 changes: 6 additions & 1 deletion packages/rocket_view/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 0.0.1

* [CHANGELOG](https://github.com/JahezAcademy/flutter_rocket/blob/dev/packages/flutter_rocket/CHANGELOG.md)
* [Old changelogs](https://pub.dev/packages/flutter_rocket/changelog)

# 0.0.2

* Changed `loader` widget arg to `onLoading` buidlder
* Improved states onLoading & onError
9 changes: 8 additions & 1 deletion packages/rocket_view/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@ class TodoList extends StatelessWidget {
return RocketView(
model: todoModel,
call: () => GetTodos.getTodos(todoModel),
loader: const CircularProgressIndicator(),
onLoading: () {
return const Center(
child: CircularProgressIndicator(
color: Colors.red,
),
);
},
onError: (error, reload) => Text('Error: ${error.exception}'),
callType: CallType.callIfModelEmpty,
builder: (context, state) {
return ListView.builder(
Expand Down
12 changes: 7 additions & 5 deletions packages/rocket_view/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,13 @@ class RocketViewExample extends StatelessWidget {
// Define how to handle errors
onError: (error, reload) => Text('Error: ${error.exception}'),
// Add a loading indicator while the Todo list is being fetched
loader: const Center(
child: CircularProgressIndicator(
color: Colors.red,
),
),
onLoading: () {
return const Center(
child: CircularProgressIndicator(
color: Colors.red,
),
);
},
),
);
}
Expand Down
67 changes: 28 additions & 39 deletions packages/rocket_view/lib/src/rocket_view_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:rocket_model/rocket_model.dart';

import 'enums.dart';

typedef OnError = Widget Function(RocketException error, Function() reload);
typedef OnError = Widget Function(RocketException error, Function() reload)?;

class RocketView<T> extends StatefulWidget {
/// A widget that helps to manage the state of a `RocketModel` and handle the different states of the data.
Expand Down Expand Up @@ -61,27 +61,27 @@ class RocketView<T> extends StatefulWidget {
Key? key,
required this.model,
required this.builder,
this.call = _myDefaultFunc,
this.call,
this.callType = CallType.callAsFuture,
this.secondsOfStream = 1,
this.loader,
this.onError = _defaultOnError,
this.onLoading,
this.onError,
}) : super(key: key) {
/// Call the `call` function based on the `callType` parameter.
switch (callType) {
case CallType.callAsFuture:
call();
call?.call();
break;
case CallType.callIfModelEmpty:
if (!model.existData) {
call();
call?.call();
}
break;
case CallType.callAsStream:
call();
call?.call();
Timer.periodic(Duration(seconds: secondsOfStream), (timer) {
model.loadingChecking = true;
call();
call?.call();
if (!model.hasListeners || model.state != RocketState.done) {
timer.cancel();
}
Expand All @@ -90,47 +90,25 @@ class RocketView<T> extends StatefulWidget {
}
}

/// Default function that does nothing.
static _myDefaultFunc() {}

/// Default error widget that displays the error message, status code, response, and a retry button.
static Widget _defaultOnError(
RocketException error, dynamic Function() reload) {
return SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(error.exception.toString()),
Text("StatusCode : ${error.statusCode.toString()}"),
Text(
error.response.toString(),
style: const TextStyle(overflow: TextOverflow.fade),
),
TextButton(onPressed: reload, child: const Text("Retry"))
],
),
);
}

/// The function that builds the widget tree based on the state.
final Widget Function(BuildContext, RocketState) builder;

/// The function that fetches data.
final dynamic Function() call;
final dynamic Function()? call;

/// When to call the `call` function.
final CallType callType;

/// Number of seconds between calls if `callType` is `CallType.callAsStream`.
final int secondsOfStream;

/// The widget to display while data is loading.
final Widget? loader;
/// The widget to display while data is loading, if not defined you need to handle it on `builder` by `state`
final Widget Function()? onLoading;

/// The `RocketModel` object that holds the data and state.
final RocketModel<T> model;

/// The function to call if an error occurs.
/// The function to call if an error occurs, if not defined you need to handle it on `builder` by `state`
final OnError onError;

@override
Expand All @@ -153,7 +131,7 @@ class ViewRocketState extends State<RocketView> {
/// Register this listener to the `RocketModel`.
reload = () {
widget.model.state = RocketState.loading;
widget.call.call();
widget.call?.call();
};
widget.model.registerListener(rocketRebuild, _handleChange);
super.initState();
Expand Down Expand Up @@ -212,19 +190,30 @@ class ViewRocketState extends State<RocketView> {
_handleStates() {
switch (widget.model.state) {
case RocketState.loading:
return Center(child: widget.loader);
return widget.onLoading!();
case RocketState.done:
return widget.builder(context, widget.model.state);
case RocketState.failed:
return widget.onError(widget.model.exception, reload);
return widget.onError!(widget.model.exception, reload);
}
}

@override
Widget build(BuildContext context) {
/// Call the builder function if the loader is `null`.
if (widget.loader == null) {
return widget.builder(context, widget.model.state);
final bool invalidonLoading =
widget.model.state == RocketState.loading && widget.onLoading == null;
final bool invalidOnError =
widget.model.state == RocketState.failed && widget.onError == null;
final bool invalidCase = invalidonLoading || invalidOnError;
if (invalidCase) {
try {
return widget.builder(context, widget.model.state);
} catch (e) {
assert(!invalidCase,
"Should define ${invalidOnError ? "onError" : "onLoading"} or handle state in builder\n$e");
return const SizedBox.shrink();
}
}

/// Return the appropriate widget tree based on the `RocketState`.
Expand Down
2 changes: 1 addition & 1 deletion packages/rocket_view/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: rocket_view
description: Package View widget based on RocketModel.
version: 0.0.1
version: 0.0.2
repository: https://github.com/JahezAcademy/flutter_rocket/tree/dev/packages/rocket_view
issue_tracker: https://github.com/JahezAcademy/flutter_rocket/labels/rocket_view
homepage: https://github.com/JahezAcademy/flutter_rocket
Expand Down
Loading