Skip to content

Commit

Permalink
Bugfix/offline dashboard grades (#155)
Browse files Browse the repository at this point in the history
* Fixed no internet message for dashboard and grade details

* Added tests to verify networking service logic on course repository

* Updated pubspec version

* Replaced no connection toast by snackbar

* Centralized snackbar to BottomBar class

* Fixed test from pages using the networking service

* Fixed formatting issue in quick links tests

* Fixed tests

* Cleaned up test using networking service

* added icon and allow to dismiss after context change with maybeof

# Deprecation Notice https://pub.dev/packages/connectivity -> https://pub.dev/packages/connectivity_plus

* Listen to change in status of connection

* Merge branch 'master' into bugfix/offline-dashboard-grades

* Changed to text under navbar

* [CI UPDATE GOLDENS]

* Update golden files

* Fixed pubspec

* [CI UPDATE GOLDENS]

* Update golden files

* Updated version

* Fix goldens

* Changed background color of text under navbar

* Removed unused import

* [CI UPDATE GOLDENS]

* Check connectivity on initial loading

* Updated version

* [CI UPDATE GOLDENS]

* Remove unnecessary check

Co-authored-by: alexandremarkus <[email protected]>
Co-authored-by: JonathanDuvalV <[email protected]>
Co-authored-by: Samuel Montambault <[email protected]>
  • Loading branch information
4 people authored Jul 28, 2021
1 parent 4770eea commit 889ab79
Show file tree
Hide file tree
Showing 39 changed files with 201 additions and 130 deletions.
11 changes: 11 additions & 0 deletions lib/core/managers/course_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,11 @@ class CourseRepository {
}
}

// Don't try to update cache when offline
if (!(await _networkingService.hasConnectivity())) {
return _sessions;
}

try {
// getPassword will try to authenticate the user if not authenticated.
final String password = await _userRepository.getPassword();
Expand Down Expand Up @@ -309,6 +314,12 @@ class CourseRepository {
/// version of the course. Return the course with the summary set.
Future<Course> getCourseSummary(Course course) async {
CourseSummary summary;

// Don't try to update the summary when user has no connection
if (!(await _networkingService.hasConnectivity())) {
return course;
}

try {
final String password = await _userRepository.getPassword();
summary = await _signetsApi.getCourseSummary(
Expand Down
4 changes: 2 additions & 2 deletions lib/core/services/networking_service.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// FLUTTER / DART / THIRD-PARTIES
import 'dart:async';

import 'package:connectivity/connectivity.dart';
import 'package:connectivity_plus/connectivity_plus.dart';

class NetworkingService {
final Connectivity _connectivity = Connectivity();
Expand Down
10 changes: 0 additions & 10 deletions lib/core/utils/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ import 'package:fluttertoast/fluttertoast.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

// SERVICES
import 'package:notredame/core/services/networking_service.dart';

class Utils {
/// Used to open a url
static Future<void> launchURL(String url, AppIntl intl) async {
Expand All @@ -26,13 +23,6 @@ class Utils {
return ((grade / maxGrade) * 100).roundToDouble();
}

static Future showNoConnectionToast(
NetworkingService networkingService, AppIntl intl) async {
if (!await networkingService.hasConnectivity()) {
Fluttertoast.showToast(msg: intl.no_connectivity);
}
}

static Color getColorByBrightness(
BuildContext context, Color lightColor, Color darkColor) {
return Theme.of(context).brightness == Brightness.light
Expand Down
10 changes: 0 additions & 10 deletions lib/core/viewmodels/grades_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,6 @@ import 'package:notredame/core/managers/course_repository.dart';
// MODEL
import 'package:notredame/core/models/course.dart';

// SERVICE
import 'package:notredame/core/services/networking_service.dart';

// UTILS
import 'package:notredame/core/utils/utils.dart';

// OTHER
import 'package:notredame/locator.dart';

Expand All @@ -26,9 +20,6 @@ class GradesViewModel extends FutureViewModel<Map<String, List<Course>>> {
/// Localization class of the application.
final AppIntl _appIntl;

/// Verify if user has an active internet connection
final NetworkingService _networkingService = locator<NetworkingService>();

/// Contains all the courses of the student sorted by session
final Map<String, List<Course>> coursesBySession = {};

Expand All @@ -51,7 +42,6 @@ class GradesViewModel extends FutureViewModel<Map<String, List<Course>>> {
}
}).whenComplete(() {
setBusy(false);
Utils.showNoConnectionToast(_networkingService, _appIntl);
});

return coursesBySession;
Expand Down
10 changes: 0 additions & 10 deletions lib/core/viewmodels/profile_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,6 @@ import 'package:notredame/core/managers/user_repository.dart';
import 'package:notredame/core/models/profile_student.dart';
import 'package:notredame/core/models/program.dart';

// SERVICE
import 'package:notredame/core/services/networking_service.dart';

// UTILS
import 'package:notredame/core/utils/utils.dart';

// OTHERS
import '../../locator.dart';

Expand All @@ -27,9 +21,6 @@ class ProfileViewModel extends FutureViewModel<List<Program>> {
/// Localization class of the application.
final AppIntl _appIntl;

/// Verify if user has an active internet connection
final NetworkingService _networkingService = locator<NetworkingService>();

/// List of the programs
List<Program> _programList = List.empty();

Expand Down Expand Up @@ -81,7 +72,6 @@ class ProfileViewModel extends FutureViewModel<List<Program>> {
.then((value) => _userRepository.getPrograms().catchError(onError))
.whenComplete(() {
setBusyForObject(isLoadingEvents, false);
Utils.showNoConnectionToast(_networkingService, _appIntl);
});
return value;
});
Expand Down
10 changes: 0 additions & 10 deletions lib/core/viewmodels/schedule_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ import 'package:notredame/core/managers/settings_manager.dart';
// MODELS
import 'package:notredame/core/models/course_activity.dart';

// SERVICE
import 'package:notredame/core/services/networking_service.dart';

// UTILS
import 'package:notredame/core/utils/utils.dart';

// OTHER
import 'package:notredame/locator.dart';
import 'package:notredame/core/constants/preferences_flags.dart';
Expand Down Expand Up @@ -52,9 +46,6 @@ class ScheduleViewModel extends FutureViewModel<List<CourseActivity>> {
/// Get current locale
Locale get locale => _settingsManager.locale;

/// Verify if user has an active internet connection
final NetworkingService _networkingService = locator<NetworkingService>();

ScheduleViewModel({@required AppIntl intl, DateTime initialSelectedDate})
: _appIntl = intl,
selectedDate = initialSelectedDate ?? DateTime.now(),
Expand Down Expand Up @@ -83,7 +74,6 @@ class ScheduleViewModel extends FutureViewModel<List<CourseActivity>> {
}
}).whenComplete(() {
setBusyForObject(isLoadingEvents, false);
Utils.showNoConnectionToast(_networkingService, _appIntl);
});
return value;
});
Expand Down
92 changes: 75 additions & 17 deletions lib/ui/widgets/base_scaffold.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
// FLUTTER / DART / THIRD-PARTIES
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

// UTILS
import 'package:notredame/core/utils/utils.dart';
import 'package:notredame/ui/utils/loading.dart';
import 'package:notredame/ui/utils/app_theme.dart';

// WIDGETS
import 'package:notredame/ui/widgets/bottom_bar.dart';

/// Basic Scaffold to avoid boilerplate code in the application.
/// Contains a loader controlled by [_isLoading]
class BaseScaffold extends StatelessWidget {
class BaseScaffold extends StatefulWidget {
final AppBar appBar;

final Widget body;
Expand Down Expand Up @@ -35,25 +41,77 @@ class BaseScaffold extends StatelessWidget {
_isLoading = isLoading,
_isInteractionLimitedWhileLoading = isInteractionLimitedWhileLoading;

@override
_BaseScaffoldState createState() => _BaseScaffoldState();
}

class _BaseScaffoldState extends State<BaseScaffold> {
// Displays text under the app bar when offline.
static bool _isOffline = false;

@override
void initState() {
super.initState();
_setOfflineValue();
_listenToChangeInConnectivity();
}

Future _setOfflineValue() async {
final isOffline =
await Connectivity().checkConnectivity() == ConnectivityResult.none;
setState(() {
_isOffline = isOffline;
});
}

void _listenToChangeInConnectivity() {
Connectivity().onConnectivityChanged.listen((event) {
setState(() {
_isOffline = event == ConnectivityResult.none;
});
});
}

@override
Widget build(BuildContext context) => Scaffold(
appBar: appBar,
body: SafeArea(
top: false,
child: Stack(
children: [
body,
if (_isLoading)
buildLoading(
isInteractionLimitedWhileLoading:
_isInteractionLimitedWhileLoading)
else
const SizedBox()
],
body: Scaffold(
appBar: widget.appBar,
body: SafeArea(
top: false,
child: Stack(
children: [
widget.body,
if (widget._isLoading)
buildLoading(
isInteractionLimitedWhileLoading:
widget._isInteractionLimitedWhileLoading)
else
const SizedBox()
],
),
),
bottomNavigationBar: widget._showBottomBar ? BottomBar() : null,
floatingActionButton: widget.fab,
floatingActionButtonLocation: widget.fabPosition,
),
bottomNavigationBar: _showBottomBar ? BottomBar() : null,
floatingActionButton: fab,
floatingActionButtonLocation: fabPosition,
bottomNavigationBar: _isOffline ? buildOfflineBar(context) : null,
);

Widget buildOfflineBar(BuildContext context) {
return Stack(
alignment: Alignment.center,
children: [
Container(
color: Utils.getColorByBrightness(context,
AppTheme.lightThemeBackground, AppTheme.darkThemeBackground),
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height / 30,
),
Text(
AppIntl.of(context).no_connectivity,
textAlign: TextAlign.center,
),
],
);
}
}
1 change: 1 addition & 0 deletions lib/ui/widgets/bottom_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class BottomBar extends StatelessWidget {
Widget build(BuildContext context) {
return BottomNavigationBar(
type: BottomNavigationBarType.fixed,
elevation: 0,
onTap: (value) => _onTap(value),
items: _buildItems(context),
currentIndex: _defineIndex(ModalRoute.of(context).settings.name),
Expand Down
45 changes: 33 additions & 12 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -106,34 +106,48 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.15.0"
connectivity:
connectivity_plus:
dependency: "direct main"
description:
name: connectivity
name: connectivity_plus
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.6"
connectivity_for_web:
version: "1.0.4"
connectivity_plus_linux:
dependency: transitive
description:
name: connectivity_for_web
name: connectivity_plus_linux
url: "https://pub.dartlang.org"
source: hosted
version: "0.4.0"
connectivity_macos:
version: "1.0.3"
connectivity_plus_macos:
dependency: transitive
description:
name: connectivity_macos
name: connectivity_plus_macos
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.0"
connectivity_platform_interface:
version: "1.0.2"
connectivity_plus_platform_interface:
dependency: transitive
description:
name: connectivity_platform_interface
name: connectivity_plus_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.1"
version: "1.0.2"
connectivity_plus_web:
dependency: transitive
description:
name: connectivity_plus_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
connectivity_plus_windows:
dependency: transitive
description:
name: connectivity_plus_windows
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
convert:
dependency: transitive
description:
Expand All @@ -155,6 +169,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
dbus:
dependency: transitive
description:
name: dbus
url: "https://pub.dartlang.org"
source: hosted
version: "0.5.4"
enum_to_string:
dependency: "direct main"
description:
Expand Down
4 changes: 2 additions & 2 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 4.1.3+1
version: 4.1.4+1

environment:
sdk: ">=2.10.0 <3.0.0"
Expand Down Expand Up @@ -62,7 +62,7 @@ dependencies:
feature_discovery: ^0.14.0
path_provider: ^2.0.1
rive: ^0.7.3
connectivity: ^3.0.4
connectivity_plus: ^1.0.4
flutter_svg: ^0.22.0
font_awesome_flutter: ^9.1.0

Expand Down
Loading

0 comments on commit 889ab79

Please sign in to comment.