diff --git a/packages/app_center/build.yaml b/packages/app_center/build.yaml new file mode 100644 index 000000000..49f821472 --- /dev/null +++ b/packages/app_center/build.yaml @@ -0,0 +1,7 @@ +targets: + $default: + builders: + json_serializable: + options: + any_map: true + explicit_to_json: true diff --git a/packages/app_center/lib/ratings/ratings_data.dart b/packages/app_center/lib/ratings/ratings_data.dart index 30010a3cb..b5ffbadb0 100644 --- a/packages/app_center/lib/ratings/ratings_data.dart +++ b/packages/app_center/lib/ratings/ratings_data.dart @@ -3,6 +3,7 @@ import 'package:app_center_ratings_client/app_center_ratings_client.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; part 'ratings_data.freezed.dart'; +part 'ratings_data.g.dart'; @freezed class RatingsData with _$RatingsData { @@ -12,4 +13,7 @@ class RatingsData with _$RatingsData { required Rating? rating, required VoteStatus? voteStatus, }) = _RatingsData; + + factory RatingsData.fromJson(Map json) => + _$RatingsDataFromJson(json); } diff --git a/packages/app_center/lib/ratings/ratings_model.dart b/packages/app_center/lib/ratings/ratings_model.dart index 79a492519..c9824b014 100644 --- a/packages/app_center/lib/ratings/ratings_model.dart +++ b/packages/app_center/lib/ratings/ratings_model.dart @@ -1,5 +1,7 @@ +import 'package:app_center/providers/file_system_provider.dart'; import 'package:app_center/ratings/ratings_data.dart'; import 'package:app_center/ratings/ratings_service.dart'; +import 'package:app_center/snapd/cache_file.dart'; import 'package:app_center/snapd/snap_model.dart'; import 'package:app_center_ratings_client/app_center_ratings_client.dart'; import 'package:clock/clock.dart'; @@ -17,6 +19,17 @@ class RatingsModel extends _$RatingsModel { final snap = (await ref.watch(snapModelProvider(snapName).future)).snap; final snapId = snap.id; + final cacheFile = _getCacheFile(snapId); + + RatingsData? cachedRatingsData; + if (cacheFile.existsSync() && cacheFile.isValidSync()) { + cachedRatingsData = await cacheFile.readRatingsData(); + } + + if (cachedRatingsData != null) { + return cachedRatingsData; + } + final results = await Future.wait([ _ratings.getRating(snapId), _ratings.getSnapVotes(snapId), @@ -25,12 +38,15 @@ class RatingsModel extends _$RatingsModel { final rating = results[0] as Rating; final votes = results[1] as List; - return RatingsData( + final ratingsData = RatingsData( snapId: snapId, snapRevision: snap.revision, rating: rating, voteStatus: _getUserVote(snap.revision, votes), ); + + cacheFile.writeRatingsDataSync(ratingsData); + return ratingsData; } Future castVote(VoteStatus voteStatus) async { @@ -47,6 +63,8 @@ class RatingsModel extends _$RatingsModel { ); await _ratings.vote(vote); state = AsyncData(ratingsData.copyWith(voteStatus: voteStatus)); + await _getCacheFile(ratingsData.snapId).deleteIfExists(); + ref.invalidateSelf(); } } @@ -58,6 +76,14 @@ class RatingsModel extends _$RatingsModel { } return null; } + + CacheFile _getCacheFile(String snapId) { + return CacheFile.fromFileName( + 'ratings-$snapId', + fileSystem: ref.read(fileSystemProvider), + expiry: const Duration(days: 1), + ); + } } enum VoteStatus { diff --git a/packages/app_center/lib/snapd/cache_file.dart b/packages/app_center/lib/snapd/cache_file.dart index 25ed4df38..d1ada8c36 100644 --- a/packages/app_center/lib/snapd/cache_file.dart +++ b/packages/app_center/lib/snapd/cache_file.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:io'; +import 'package:app_center/ratings/ratings_data.dart'; import 'package:file/file.dart'; import 'package:file/local.dart'; import 'package:flutter/services.dart'; @@ -92,6 +93,12 @@ class CacheFile { .toList(); } + Future deleteIfExists() async { + if (await _file.exists()) { + await _file.delete(); + } + } + Future writeSnap(Snap snap) => write(snap.toJson()); void writeSnapSync(Snap snap) => writeSync(snap.toJson()); @@ -99,6 +106,15 @@ class CacheFile { void writeSnapListSync(List snaps) { return writeSync(snaps.map((snap) => snap.toJson()).toList()); } + + Future readRatingsData() async { + final data = await read() as Map?; + return data != null ? RatingsData.fromJson(data.cast()) : null; + } + + void writeRatingsDataSync(RatingsData ratingsData) { + return writeSync(ratingsData.toJson()); + } } extension CacheObject on Object { diff --git a/packages/app_center/pubspec.yaml b/packages/app_center/pubspec.yaml index a42cb816c..c731dc0ad 100644 --- a/packages/app_center/pubspec.yaml +++ b/packages/app_center/pubspec.yaml @@ -34,6 +34,7 @@ dependencies: handy_window: ^0.4.0 http: ^1.2.2 intl: any + json_annotation: ^4.9.0 jwt_decode: ^0.3.1 meta: ^1.15.0 package_info_plus: ^8.0.2 @@ -64,6 +65,7 @@ dev_dependencies: freezed: ^2.5.7 integration_test: sdk: flutter + json_serializable: ^6.8.0 mockito: ^5.4.4 riverpod_generator: ^2.4.3 ubuntu_lints: ^0.4.0 diff --git a/packages/app_center_ratings_client/build.yaml b/packages/app_center_ratings_client/build.yaml new file mode 100644 index 000000000..49f821472 --- /dev/null +++ b/packages/app_center_ratings_client/build.yaml @@ -0,0 +1,7 @@ +targets: + $default: + builders: + json_serializable: + options: + any_map: true + explicit_to_json: true diff --git a/packages/app_center_ratings_client/lib/src/ratings.dart b/packages/app_center_ratings_client/lib/src/ratings.dart index 745287c4b..dc71c3097 100644 --- a/packages/app_center_ratings_client/lib/src/ratings.dart +++ b/packages/app_center_ratings_client/lib/src/ratings.dart @@ -5,15 +5,17 @@ import 'package:app_center_ratings_client/src/generated/ratings_features_common. import 'package:freezed_annotation/freezed_annotation.dart'; part 'ratings.freezed.dart'; +part 'ratings.g.dart'; @freezed class Rating with _$Rating { - @JsonSerializable(explicitToJson: true) const factory Rating({ required String snapId, required int totalVotes, required RatingsBand ratingsBand, }) = _Rating; + + factory Rating.fromJson(Map json) => _$RatingFromJson(json); } enum RatingsBand { diff --git a/packages/app_center_ratings_client/lib/src/ratings.freezed.dart b/packages/app_center_ratings_client/lib/src/ratings.freezed.dart index 5bdfbce84..b256fdc52 100644 --- a/packages/app_center_ratings_client/lib/src/ratings.freezed.dart +++ b/packages/app_center_ratings_client/lib/src/ratings.freezed.dart @@ -14,12 +14,19 @@ T _$identity(T value) => value; final _privateConstructorUsedError = UnsupportedError( 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); +Rating _$RatingFromJson(Map json) { + return _Rating.fromJson(json); +} + /// @nodoc mixin _$Rating { String get snapId => throw _privateConstructorUsedError; int get totalVotes => throw _privateConstructorUsedError; RatingsBand get ratingsBand => throw _privateConstructorUsedError; + /// Serializes this Rating to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + /// Create a copy of Rating /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -115,14 +122,16 @@ class __$$RatingImplCopyWithImpl<$Res> } /// @nodoc - -@JsonSerializable(explicitToJson: true) +@JsonSerializable() class _$RatingImpl implements _Rating { const _$RatingImpl( {required this.snapId, required this.totalVotes, required this.ratingsBand}); + factory _$RatingImpl.fromJson(Map json) => + _$$RatingImplFromJson(json); + @override final String snapId; @override @@ -147,6 +156,7 @@ class _$RatingImpl implements _Rating { other.ratingsBand == ratingsBand)); } + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash(runtimeType, snapId, totalVotes, ratingsBand); @@ -157,6 +167,13 @@ class _$RatingImpl implements _Rating { @pragma('vm:prefer-inline') _$$RatingImplCopyWith<_$RatingImpl> get copyWith => __$$RatingImplCopyWithImpl<_$RatingImpl>(this, _$identity); + + @override + Map toJson() { + return _$$RatingImplToJson( + this, + ); + } } abstract class _Rating implements Rating { @@ -165,6 +182,8 @@ abstract class _Rating implements Rating { required final int totalVotes, required final RatingsBand ratingsBand}) = _$RatingImpl; + factory _Rating.fromJson(Map json) = _$RatingImpl.fromJson; + @override String get snapId; @override diff --git a/packages/app_center_ratings_client/pubspec.yaml b/packages/app_center_ratings_client/pubspec.yaml index ade221e0d..7a5578c13 100644 --- a/packages/app_center_ratings_client/pubspec.yaml +++ b/packages/app_center_ratings_client/pubspec.yaml @@ -17,6 +17,7 @@ dependencies: dev_dependencies: build_runner: ^2.4.12 + json_serializable: ^6.8.0 mockito: ^5.4.4 test: ^1.25.8 ubuntu_lints: ^0.4.0