From 32004f121886abc843b0953c17f87a4801dacd87 Mon Sep 17 00:00:00 2001 From: Simone Sestito Date: Mon, 22 Oct 2018 12:56:33 +0200 Subject: [PATCH] Add offline error handling --- lib/main.dart | 5 ++--- lib/route/collection.dart | 11 +++++----- lib/route/home.dart | 11 +++++----- lib/route/launches_result.dart | 14 +++++++++++- lib/service/RocketService.dart | 40 ++++++++++++++++++++++++---------- lib/utils.dart | 7 ++++++ lib/view/OfflineView.dart | 20 +++++++++++++++++ pubspec.yaml | 1 + 8 files changed, 83 insertions(+), 26 deletions(-) create mode 100644 lib/utils.dart create mode 100644 lib/view/OfflineView.dart diff --git a/lib/main.dart b/lib/main.dart index f5eadc9..31aae80 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -93,14 +93,13 @@ class SplashState extends State with SingleTickerProviderStateMixin { final Animation curve = CurvedAnimation(parent: controller, curve: Curves.elasticIn); rocketAnimation = IntTween(begin: 0, end: 360).animate(curve); - controller.forward(); - controller.addStatusListener((status) async { + controller..addStatusListener((status) async { if (status == AnimationStatus.completed) { // Wait after the animation await Future.delayed(Duration(milliseconds: 600)); widget.callback(); } - }); + })..forward(); } @override diff --git a/lib/route/collection.dart b/lib/route/collection.dart index b7ff206..cbbeb57 100644 --- a/lib/route/collection.dart +++ b/lib/route/collection.dart @@ -19,6 +19,7 @@ import 'package:escape_earth/route/launches_result.dart'; import 'package:escape_earth/service/RocketService.dart'; +import 'package:escape_earth/view/OfflineView.dart'; import 'package:escape_earth/view/RocketView.dart'; import 'package:escape_earth/view/RoundSearch.dart'; import 'package:flutter/material.dart'; @@ -32,17 +33,17 @@ class CollectionRocketRoute extends StatelessWidget { future: RocketService.getLaunches(), initialData: null, builder: (context, snap) { + if (snap.error != null) { + debugPrint(snap.error.toString()); + return OfflineView(); + } + if (snap.data == null || snap.data.length == 0) { return Center( child: CircularProgressIndicator(), ); } - if (snap.error != null) { - print(snap.error); - return Center(child: Icon(Icons.portable_wifi_off)); - } - return ListView.builder( padding: EdgeInsets.only(top: 90.0, right: 16.0, left: 16.0), itemCount: snap.data.length, diff --git a/lib/route/home.dart b/lib/route/home.dart index 4c5ae3c..a886aaa 100644 --- a/lib/route/home.dart +++ b/lib/route/home.dart @@ -22,6 +22,7 @@ import 'package:escape_earth/route/collection.dart'; import 'package:escape_earth/route/qa.dart'; import 'package:escape_earth/service/RocketService.dart'; import 'package:escape_earth/view/NewsView.dart'; +import 'package:escape_earth/view/OfflineView.dart'; import 'package:escape_earth/view/RocketHero.dart'; import 'package:escape_earth/view/RocketView.dart'; import 'package:flutter/material.dart'; @@ -99,17 +100,17 @@ class HomeBody extends StatelessWidget { return FutureBuilder( future: RocketService.getNextLaunch(), builder: (context, snap) { + if (snap.error != null) { + debugPrint(snap.error.toString()); + return OfflineView(); + } + if (snap.data == null) { return Center( child: CircularProgressIndicator(), ); } - if (snap.error != null) { - print(snap.error); - return Center(child: Icon(Icons.portable_wifi_off)); - } - return Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ diff --git a/lib/route/launches_result.dart b/lib/route/launches_result.dart index 230df85..84135e7 100644 --- a/lib/route/launches_result.dart +++ b/lib/route/launches_result.dart @@ -18,6 +18,7 @@ */ import 'package:escape_earth/service/RocketService.dart'; +import 'package:escape_earth/view/OfflineView.dart'; import 'package:escape_earth/view/RocketView.dart'; import 'package:flutter/material.dart'; @@ -39,12 +40,23 @@ class LaunchesResultRoute extends StatelessWidget { future: RocketService.getLaunches(query: query), initialData: null, builder: (context, snap) { - if (snap.data == null || snap.data.length == 0) { + if (snap.error != null) { + debugPrint(snap.error.toString()); + return OfflineView(); + } + + if (snap.data == null) { return Center( child: CircularProgressIndicator(), ); } + if (snap.data.length == 0) { + return Center( + child: Text("No results :("), + ); + } + return ListView.builder( padding: EdgeInsets.only(top: 48.0), itemCount: snap.data.length, diff --git a/lib/service/RocketService.dart b/lib/service/RocketService.dart index 4af2c3a..d3ba1dd 100644 --- a/lib/service/RocketService.dart +++ b/lib/service/RocketService.dart @@ -21,39 +21,51 @@ import 'dart:async'; import 'dart:convert'; import 'package:escape_earth/model/Agency.dart'; import 'package:escape_earth/model/RocketLaunch.dart'; +import 'package:escape_earth/utils.dart'; import 'package:http/http.dart' as http; class RocketService { static Future getNextLaunch() async { - final response = await http.get("https://launchlibrary.net/1.4/launch?next=1"); + if (!(await isConnected())) { + throw StateError("Device offline."); + } + + final response = + await http.get("https://launchlibrary.net/1.4/launch?next=1"); final content = json.decode(response.body)["launches"][0]; final agency = await getAgencyById(content["lsp"]); return RocketLaunch( - country: agency.countryCode, - launchCompany: agency, - name: content["name"], - date: content["windowstart"], - videoUrl: (content["vidURLs"] ?? [null])[0], - ); + country: agency.countryCode, + launchCompany: agency, + name: content["name"], + date: content["windowstart"], + videoUrl: (content["vidURLs"] ?? [null])[0], + ); } - static Future> getLaunches({ String query }) async { + static Future> getLaunches({String query}) async { + if (!(await isConnected())) { + throw StateError("Device offline."); + } + http.Response rawLaunchesResponse; if (query == null || query == "") { - rawLaunchesResponse = await http.get("https://launchlibrary.net/1.4/launch?next=25"); + rawLaunchesResponse = + await http.get("https://launchlibrary.net/1.4/launch?next=25"); } else { - rawLaunchesResponse = await http.get("https://launchlibrary.net/1.4/launch?next=25&name=$query"); + rawLaunchesResponse = await http + .get("https://launchlibrary.net/1.4/launch?next=25&name=$query"); } final List launchesContent = json.decode(rawLaunchesResponse.body)["launches"]; - + final agRequests = []; for (Map item in launchesContent) { agRequests.add(getAgencyById(item["lsp"])); } final allAgencies = await Future.wait(agRequests); - + final result = []; for (int i = 0; i < launchesContent.length; i++) { result.add(RocketLaunch( @@ -68,6 +80,10 @@ class RocketService { } static Future getAgencyById(String id) async { + if (!(await isConnected())) { + throw StateError("Device offline."); + } + final raw = await http.get("https://launchlibrary.net/1.4/agency/$id"); final agency = json.decode(raw.body)["agencies"][0]; return Agency( diff --git a/lib/utils.dart b/lib/utils.dart new file mode 100644 index 0000000..a8c2bd5 --- /dev/null +++ b/lib/utils.dart @@ -0,0 +1,7 @@ +import 'package:connectivity/connectivity.dart'; + +Future isConnected() async { + final connectivityResult = await (Connectivity().checkConnectivity()); + return connectivityResult == ConnectivityResult.mobile || + connectivityResult == ConnectivityResult.wifi; +} diff --git a/lib/view/OfflineView.dart b/lib/view/OfflineView.dart new file mode 100644 index 0000000..41939e2 --- /dev/null +++ b/lib/view/OfflineView.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; + +class OfflineView extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Icon(Icons.signal_wifi_off, size: 50.0), + Padding(padding: EdgeInsets.all(20.0)), + Text( + "You're offline.", + style: TextStyle(fontSize: 21.0), + textAlign: TextAlign.center, + ), + ], + ); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 7436d29..6311fdb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,6 +15,7 @@ environment: dependencies: http: ^0.12.0 url_launcher: ^4.0.1 + connectivity: ^0.3.2 flutter: sdk: flutter