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

Started v2.0 migration #1986

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 2 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: 1 addition & 1 deletion .github/workflows/client.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ jobs:
- run: echo PHASE 2 - Ensure auto-gened protocol buffers
- run: sudo apt install -y protobuf-compiler
- run: protoc --version
- run: flutter pub global activate protoc_plugin ^19.0.1
- run: flutter pub global activate protoc_plugin ^20.0.0
working-directory: ./client
- run: echo "$HOME/.pub-cache/bin" >> $GITHUB_PATH
- run: ./tools/gen-client-protos.sh
Expand Down
2 changes: 1 addition & 1 deletion client/lib/api/alerts.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'package:flutter/material.dart';

class Alert {
final String title;
final String? title;
final String body;
final Color color;
final bool dismissable;
Expand Down
10 changes: 5 additions & 5 deletions client/lib/api/content/caching.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class WhoCacheManager extends BaseCacheManager {
// Change this key when the cache database becomes incompatible with the prior cache.
static const key = 'whoCache2';

static WhoCacheManager _instance;
static WhoCacheManager? _instance;

// If you don't have a network connection for >10 years, you don't update
// the app, or we have more than 10000 content bundles, you might get old content.
Expand All @@ -22,13 +22,13 @@ class WhoCacheManager extends BaseCacheManager {

factory WhoCacheManager() {
_instance ??= WhoCacheManager._init();
return _instance;
return _instance!;
}

// This changes the behavior of the base method to wait for an update of the
// expired file before returning, rather than favoring the cached version.
@override
Future<File> getSingleFile(String url, {Map<String, String> headers}) async {
Future<File?> getSingleFile(String url, {Map<String, String>? headers}) async {
final cacheFile = await getFileFromCache(url);
if (cacheFile != null) {
if (cacheFile.validTill.isBefore(DateTime.now())) {
Expand All @@ -41,7 +41,7 @@ class WhoCacheManager extends BaseCacheManager {
throw Exception(
'No internet connectivity - will not attempt download');
}
return (await webHelper.downloadFile(url, authHeaders: headers)).file;
return (await webHelper.downloadFile(url, authHeaders: headers!)).file;
} catch (err) {
print(
'Error refreshing expired file, returning cached version: $url');
Expand All @@ -57,7 +57,7 @@ class WhoCacheManager extends BaseCacheManager {
throw Exception('No internet connectivity - will not attempt download');
}
print('Downloading file: $url');
final download = await webHelper.downloadFile(url, authHeaders: headers);
final download = await webHelper.downloadFile(url, authHeaders: headers!);
return download.file;
} catch (e) {
print('Error downloading file: $url, $e');
Expand Down
27 changes: 13 additions & 14 deletions client/lib/api/content/content_bundle.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:flutter/foundation.dart';
import 'package:yaml/yaml.dart';

/// A localized YAML file loaded preferentially from the network, falling back
Expand All @@ -16,7 +15,7 @@ class ContentBundle {
/// Construct a bundle from utf-8 bytes containing YAML
ContentBundle.fromBytes(Uint8List bytes,
{bool unsupportedSchemaVersionAvailable = false}) {
var yamlString = Encoding.getByName('utf-8').decode(bytes);
var yamlString = Encoding.getByName('utf-8')!.decode(bytes);
_init(yamlString,
unsupportedSchemaVersionAvailable: unsupportedSchemaVersionAvailable);
}
Expand All @@ -32,20 +31,20 @@ class ContentBundle {
{bool unsupportedSchemaVersionAvailable = false}) {
yaml = loadYaml(yamlString);
unsupportedSchemaVersionAvailable = unsupportedSchemaVersionAvailable;
if (schemaVersion > maxSupportedSchemaVersion) {
if (schemaVersion! > maxSupportedSchemaVersion) {
throw ContentBundleSchemaVersionException();
}
}

int get schemaVersion {
int? get schemaVersion {
return getInt('schema_version');
}

int get contentVersion {
int? get contentVersion {
return getInt('content_version');
}

String get contentType {
String? get contentType {
try {
return yaml['contents']['type'];
} catch (err) {
Expand All @@ -54,55 +53,55 @@ class ContentBundle {
}

/// For content types containing a primary list of items, return the items.
YamlList get contentItems {
YamlList? get contentItems {
try {
return yaml['contents']['items'];
} catch (err) {
return YamlList();
}
}

YamlList get contentResults {
YamlList? get contentResults {
try {
return yaml['contents']['results'];
} catch (err) {
return YamlList();
}
}

YamlList get contentCards {
YamlList? get contentCards {
try {
return yaml['contents']['results_cards'];
} catch (err) {
return YamlList();
}
}

YamlList get contentPromos {
YamlList? get contentPromos {
try {
return yaml['contents']['promos'];
} catch (err) {
return YamlList();
}
}

YamlList get contentPoster {
YamlList? get contentPoster {
try {
return yaml['contents']['poster'];
} catch (err) {
return YamlList();
}
}

String getString(String key) {
String? getString(String key) {
try {
return (yaml['contents'][key]).trim();
} catch (err) {
return null;
}
}

int getInt(String key, {int orDefault = -1}) {
int? getInt(String key, {int orDefault = -1}) {
try {
return yaml[key];
} catch (err) {
Expand All @@ -116,7 +115,7 @@ class ContentBundle {
class ContentBase {
ContentBundle bundle;

ContentBase(this.bundle, {@required String schemaName}) {
ContentBase(this.bundle, {required String schemaName}) {
if (bundle.contentType != schemaName) {
throw Exception('Unsupported content type: ${bundle.contentType}');
}
Expand Down
10 changes: 5 additions & 5 deletions client/lib/api/content/content_loading.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,19 @@ class ContentService {
static final Duration networkTimeout = Duration(seconds: 30);
static final String baseAssetPath = 'assets/content_bundles'; // no trailing

ContentService({@required Endpoint endpoint})
ContentService({required Endpoint endpoint})
: baseContentURL = '${endpoint.staticContentUrl}/content/bundles';

/// Load a localized content bundle loaded preferentially from the network, falling back
/// to a local asset. If no bundle can be found with the specified name an exception is thrown.
Future<ContentBundle> load(
Locale locale, String countryIsoCode, String name) async {
Future<ContentBundle?> load(
Locale locale, String? countryIsoCode, String name) async {
final languageCode = locale.languageCode;
final countryCode = countryIsoCode ?? locale.countryCode;
final languageAndCountry = '${languageCode}_${countryCode}';
var unsupportedSchemaVersionAvailable = false;

ContentBundle networkBundle;
ContentBundle? networkBundle;

// Attempt to load the full language and country path from the network.
// The content server contains linked / duplicated paths as needed such that
Expand Down Expand Up @@ -62,7 +62,7 @@ class ContentService {
}
}

Future<ContentBundle> _loadFromAssetsWithFallback(
Future<ContentBundle?> _loadFromAssetsWithFallback(
String name,
String languageAndCountry,
bool unsupportedSchemaVersionAvailable,
Expand Down
71 changes: 35 additions & 36 deletions client/lib/api/content/content_store.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:mobx/mobx.dart';
import 'package:who_app/api/content/content_bundle.dart';
Expand All @@ -18,23 +17,23 @@ part 'content_store.g.dart';

class ContentStore extends _ContentStore with _$ContentStore {
ContentStore(
{@required ContentService service,
@required Locale locale,
@required String countryIsoCode})
{required ContentService service,
required Locale locale,
required String? countryIsoCode})
: super(service: service, locale: locale, countryIsoCode: countryIsoCode);
}

abstract class _ContentStore with Store implements Updateable {
final Locale locale;
final ContentService service;
final String countryIsoCode;
final String? countryIsoCode;

_ContentStore(
{@required this.service,
@required this.locale,
@required this.countryIsoCode});
{required this.service,
required this.locale,
required this.countryIsoCode});

bool _unsupportedSchemaVersionAvailable(ContentBase cb) =>
bool _unsupportedSchemaVersionAvailable(ContentBase? cb) =>
cb?.bundle?.unsupportedSchemaVersionAvailable ?? false;

@computed
Expand All @@ -50,34 +49,34 @@ abstract class _ContentStore with Store implements Updateable {
].map(_unsupportedSchemaVersionAvailable).reduce((a, b) => a || b);

@observable
LogicContext logicContext;
LogicContext? logicContext;

@observable
AdviceContent travelAdvice;
AdviceContent? travelAdvice;

@observable
FactContent getTheFacts;
FactContent? getTheFacts;

@observable
FactContent protectYourself;
FactContent? protectYourself;

@observable
IndexContent homeIndex;
IndexContent? homeIndex;

@observable
IndexContent learnIndex;
IndexContent? learnIndex;

@observable
IndexContent newsIndex;
IndexContent? newsIndex;

@observable
QuestionContent questionsAnswered;
QuestionContent? questionsAnswered;

@observable
SymptomCheckerContent symptomChecker;
SymptomCheckerContent? symptomChecker;

Future<void> updateBundle<T extends ContentBase>(String name, T old,
T Function(ContentBundle) constructor, void Function(T) setter) async {
Future<void> updateBundle<T extends ContentBase?>(String name, T old,
T Function(ContentBundle?) constructor, void Function(T) setter) async {
final newValue =
constructor(await service.load(locale, countryIsoCode, name));
if ((newValue?.bundle?.contentVersion ?? 0) >
Expand All @@ -102,36 +101,36 @@ abstract class _ContentStore with Store implements Updateable {
// the *cache* must be enforced elsewhere.
try {
await Future.wait([
updateBundle<IndexContent>(
'home_index', homeIndex, (cb) => IndexContent(cb), (v) {
updateBundle<IndexContent?>(
'home_index', homeIndex, (cb) => IndexContent(cb!), (v) {
homeIndex = v;
}),
updateBundle<AdviceContent>(
'travel_advice', travelAdvice, (cb) => AdviceContent(cb), (v) {
updateBundle<AdviceContent?>(
'travel_advice', travelAdvice, (cb) => AdviceContent(cb!), (v) {
travelAdvice = v;
}),
updateBundle<FactContent>(
'get_the_facts', getTheFacts, (cb) => FactContent(cb), (v) {
updateBundle<FactContent?>(
'get_the_facts', getTheFacts, (cb) => FactContent(cb!), (v) {
getTheFacts = v;
}),
updateBundle<FactContent>(
'protect_yourself', protectYourself, (cb) => FactContent(cb), (v) {
updateBundle<FactContent?>(
'protect_yourself', protectYourself, (cb) => FactContent(cb!), (v) {
protectYourself = v;
}),
updateBundle<IndexContent>(
'learn_index', learnIndex, (cb) => IndexContent(cb), (v) {
updateBundle<IndexContent?>(
'learn_index', learnIndex, (cb) => IndexContent(cb!), (v) {
learnIndex = v;
}),
updateBundle<IndexContent>(
'news_index', newsIndex, (cb) => IndexContent(cb), (v) {
updateBundle<IndexContent?>(
'news_index', newsIndex, (cb) => IndexContent(cb!), (v) {
newsIndex = v;
}),
updateBundle<QuestionContent>('your_questions_answered',
questionsAnswered, (cb) => QuestionContent(cb), (v) {
updateBundle<QuestionContent?>('your_questions_answered',
questionsAnswered, (cb) => QuestionContent(cb!), (v) {
questionsAnswered = v;
}),
updateBundle<SymptomCheckerContent>('symptom_checker', symptomChecker,
(cb) => SymptomCheckerContent(cb), (v) {
updateBundle<SymptomCheckerContent?>('symptom_checker', symptomChecker,
(cb) => SymptomCheckerContent(cb!), (v) {
symptomChecker = v;
})
]);
Expand Down
Loading