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

Configs for quicklinks #911

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
57 changes: 55 additions & 2 deletions lib/core/managers/quick_link_repository.dart
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
// Dart imports:
import 'dart:convert';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:notredame/ui/utils/app_theme.dart';
import 'package:font_awesome_flutter/name_icon_mapping.dart';

// Package imports:
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

// Project imports:
import 'package:notredame/core/constants/quick_links.dart';
import 'package:notredame/core/managers/cache_manager.dart';
import 'package:notredame/core/models/quick_link.dart';
import 'package:notredame/core/models/quick_link_data.dart';
import 'package:notredame/core/services/firebase_storage_service.dart';
import 'package:notredame/locator.dart';
import 'package:notredame/core/services/remote_config_service.dart';

class QuickLinkRepository {
final CacheManager _cacheManager = locator<CacheManager>();
final RemoteConfigService _remoteConfigService =
locator<RemoteConfigService>();
final FirebaseStorageService _storageService =
locator<FirebaseStorageService>();

static const String quickLinksCacheKey = "quickLinksCache";

Expand All @@ -36,7 +47,49 @@ class QuickLinkRepository {
quickLinksCacheKey, jsonEncode(quickLinkDataList));
}

List<QuickLink> getDefaultQuickLinks(AppIntl intl) {
return quickLinks(intl);
Future<List<QuickLink>> getDefaultQuickLinks(AppIntl intl) async {
final values = await _remoteConfigService.quicklinksValues;

if (values == null || values as List == null || (values as List).isEmpty) {
return quickLinks(intl);
}
final listValues = values as List<dynamic>;
final List<QuickLink> listQuicklink = [];

for (var i = 0; i < listValues.length; i++) {
Widget imageWidget;
final map = listValues[i] as Map<String, dynamic>;
if (map['icon'] != null) {
final String iconName = map['icon'] as String;
imageWidget = FaIcon(
faIconNameMapping['solid $iconName'],
color: AppTheme.etsLightRed,
size: 64,
);
} else if (map['remotePath'] != null) {
// from cache
final String remotePathKey = map['remotePath'] as String;
String imageUrl;
try {
imageUrl = await _cacheManager.get(remotePathKey);
} on Exception catch (_) {
imageUrl = await _storageService.getImageUrl(remotePathKey);
_cacheManager.update(remotePathKey, imageUrl);
}

imageWidget = CachedNetworkImage(
imageUrl: imageUrl,
color: AppTheme.etsLightRed,
);
}
final QuickLink quickLink =
QuickLink.fromJson(listValues[i] as Map<String, dynamic>);
quickLink.name =
intl.localeName == "fr" ? quickLink.nameFr : quickLink.nameEn;
quickLink.image = imageWidget;
listQuicklink.add(quickLink);
}

return listQuicklink;
}
}
22 changes: 18 additions & 4 deletions lib/core/models/quick_link.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,27 @@ import 'package:flutter/material.dart';

class QuickLink {
final int id;
final Widget image;
final String name;
Widget image;
final String link;
final String nameFr;
final String nameEn;
String name;

// If name is provided it will be used instead of nameFr and nameEn
QuickLink(
{required this.id,
required this.image,
required this.name,
this.image,
this.name,
this.nameFr,
this.nameEn,
required this.link});

factory QuickLink.fromJson(Map<String, dynamic> json) {
return QuickLink(
id: int.parse(json['id'] as String),
nameFr: json['nameFr'] as String,
nameEn: json['nameEn'] as String,
link: json['link'] as String,
);
}
}
57 changes: 57 additions & 0 deletions lib/core/services/course_grade_cache_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Package imports:
import 'package:firebase_analytics/firebase_analytics.dart';

/// Manage the analytics of the application
class CourseGradeCacheService {
final FirebaseAnalytics _analytics = FirebaseAnalytics.instance;

CourseGradeCacheService();

void setCourseGradeCache(String semester, String courseCode,
String courseName, double courseGrade) {
_analytics.logEvent(name: "setCourseGradeCache");
}
}

class SemesterCache {
final String semester;
final List<GradeCache> gradeCacheList;

SemesterCache({this.semester, this.gradeCacheList});

factory SemesterCache.fromJson(Map<String, dynamic> json) {
return SemesterCache(
semester: json['semester'] as String,
gradeCacheList: (json['gradeCacheList'] as List<dynamic>)
.map((e) => GradeCache.fromJson(e as Map<String, dynamic>))
.toList(),
);
}

Map<String, dynamic> toJson() => {
'semester': semester,
'gradeCacheList': gradeCacheList.map((e) => e.toJson()),
};
}

class GradeCache {
final String courseCode;
final String courseName;
final double courseGrade;

GradeCache({this.courseCode, this.courseName, this.courseGrade});

factory GradeCache.fromJson(Map<String, dynamic> json) {
return GradeCache(
courseCode: json['courseCode'] as String,
courseName: json['courseName'] as String,
courseGrade: json['courseGrade'] as double,
);
}

Map<String, dynamic> toJson() => {
'courseCode': courseCode,
'courseName': courseName,
'courseGrade': courseGrade,
};
}
43 changes: 43 additions & 0 deletions lib/core/services/firebase_storage_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Package imports:
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/cupertino.dart';

// Project imports:
import 'package:notredame/core/services/analytics_service.dart';
import 'package:notredame/locator.dart';

/// Manage the analytics of the application
class FirebaseStorageService {
static const String tag = "FirebaseStorageService";
static const String _defaultPath = "app-images";

FirebaseStorage firebaseStorage;

final AnalyticsService _analyticsService = locator<AnalyticsService>();

/// Reference to the app images folder in default cloud storage
Reference _appImageReferences;

@visibleForTesting
Reference get appImageReferences => _appImageReferences;

FirebaseStorageService({this.firebaseStorage}) {
firebaseStorage ??= FirebaseStorage.instance;
_appImageReferences = firebaseStorage.ref(_defaultPath);
}

/// Get the url of the image from the firebase storage
/// [fileName] is the fileName of the image in the firebase storage
Future<String> getImageUrl(String fileName) async {
try {
_appImageReferences ??= firebaseStorage.ref(_defaultPath);

final child = _appImageReferences.child(fileName);
final url = await child.getDownloadURL();
return url;
} on Exception catch (e) {
_analyticsService.logError(tag, "Error while getting the image url", e);
rethrow;
}
}
}
12 changes: 8 additions & 4 deletions lib/core/services/remote_config_service.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
//SERVICE

// Package imports:
import 'dart:convert';

import 'package:firebase_remote_config/firebase_remote_config.dart';

// Project imports:
import 'package:notredame/core/services/analytics_service.dart';
import 'package:notredame/locator.dart';

//OTHERS

/// Manage the analytics of the application
class RemoteConfigService {
static const String tag = "RemoteConfigService";
Expand All @@ -26,6 +24,7 @@ class RemoteConfigService {
static const _dashboardMsgColor = "dashboard_message_color";
static const _dashboardMsgUrl = "dashboard_message_url";
static const _dashboardMsgType = "dashboard_message_type";
static const _quicklinksValues = "quicklinks_values";

static const _scheduleListViewDefault = "schedule_list_view_default";
final FirebaseRemoteConfig _remoteConfig = FirebaseRemoteConfig.instance;
Expand Down Expand Up @@ -108,6 +107,11 @@ class RemoteConfigService {
return _remoteConfig.getString(_dashboardMsgType);
}

Future<dynamic> get quicklinksValues async {
await fetch();
return jsonDecode(_remoteConfig.getString(_quicklinksValues));
}

Future<void> fetch() async {
final AnalyticsService analyticsService = locator<AnalyticsService>();
try {
Expand Down
6 changes: 3 additions & 3 deletions lib/core/viewmodels/quick_links_viewmodel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class QuickLinksViewModel extends FutureViewModel<List<QuickLink>> {

// otherwise, return quickLinks according to the cache
final defaultQuickLinks =
_quickLinkRepository.getDefaultQuickLinks(_appIntl);
await _quickLinkRepository.getDefaultQuickLinks(_appIntl);
quickLinkDataList.sort((a, b) => a.index.compareTo(b.index));
return quickLinkDataList
.map((data) => defaultQuickLinks
Expand All @@ -47,8 +47,8 @@ class QuickLinksViewModel extends FutureViewModel<List<QuickLink>> {
final currentQuickLinkIds = quickLinkList.map((e) => e.id).toList();

// Return those not in current quick links but in default list
return _quickLinkRepository
.getDefaultQuickLinks(_appIntl)
final defaults = await _quickLinkRepository.getDefaultQuickLinks(_appIntl);
return defaults
.where((element) => !currentQuickLinkIds.contains(element.id))
.toList();
}
Expand Down
2 changes: 2 additions & 0 deletions lib/locator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:notredame/core/managers/settings_manager.dart';
import 'package:notredame/core/managers/user_repository.dart';
import 'package:notredame/core/services/analytics_service.dart';
import 'package:notredame/core/services/app_widget_service.dart';
import 'package:notredame/core/services/firebase_storage_service.dart';
import 'package:notredame/core/services/github_api.dart';
import 'package:notredame/core/services/in_app_review_service.dart';
import 'package:notredame/core/services/internal_info_service.dart';
Expand All @@ -35,6 +36,7 @@ void setupLocator() {
locator.registerLazySingleton(() => const FlutterSecureStorage());
locator.registerLazySingleton(() => PreferencesService());
locator.registerLazySingleton(() => NetworkingService());
locator.registerLazySingleton(() => FirebaseStorageService());
locator.registerLazySingleton(() => SirenFlutterService());
locator.registerLazySingleton(() => AppWidgetService());
locator.registerLazySingleton(() => InAppReviewService());
Expand Down
56 changes: 56 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,27 @@ packages:
url: "https://pub.dev"
source: hosted
version: "8.9.2"
cached_network_image:
dependency: "direct main"
description:
name: cached_network_image
url: "https://pub.dartlang.org"
source: hosted
version: "3.2.3"
cached_network_image_platform_interface:
dependency: transitive
description:
name: cached_network_image_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
cached_network_image_web:
dependency: transitive
description:
name: cached_network_image_web
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
calendar_view:
dependency: "direct main"
description:
Expand Down Expand Up @@ -426,6 +447,27 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.25"
firebase_storage:
dependency: "direct main"
description:
name: firebase_storage
url: "https://pub.dartlang.org"
source: hosted
version: "11.2.8"
firebase_storage_platform_interface:
dependency: transitive
description:
name: firebase_storage_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "4.4.7"
firebase_storage_web:
dependency: transitive
description:
name: firebase_storage_web
url: "https://pub.dartlang.org"
source: hosted
version: "3.6.8"
fixnum:
dependency: transitive
description:
Expand All @@ -439,6 +481,13 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_blurhash:
dependency: transitive
description:
name: flutter_blurhash
url: "https://pub.dartlang.org"
source: hosted
version: "0.7.0"
flutter_cache_manager:
dependency: "direct main"
description:
Expand Down Expand Up @@ -934,6 +983,13 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.5.0"
octo_image:
dependency: transitive
description:
name: octo_image
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
package_config:
dependency: transitive
description:
Expand Down
Loading
Loading