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

feat: Add rated category snaps to the Games tab #1740

Open
wants to merge 25 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e23614e
feat: Add support for charts by category
ashuntu Feb 23, 2024
b7b543c
test: Add tests for rating client and service
ashuntu Mar 14, 2024
fa741f0
Add rated snap category list
ashuntu Jun 27, 2024
392d913
Redesign rated app cards
ashuntu Jul 9, 2024
cb3a031
Add rated category model provider
ashuntu Jul 12, 2024
465986a
Add missing trailing commas
ashuntu Jul 12, 2024
7597a60
Reduce numbered font size
ashuntu Aug 28, 2024
f0e098e
Remove outline on hover for rated cards
ashuntu Aug 28, 2024
bc5042d
Fix spacing of rated app cards on large screens
ashuntu Aug 28, 2024
955fcc3
Use existing theme styles for text and spacing
ashuntu Aug 30, 2024
0d84dc6
Switch while loop to simplified for loop
ashuntu Oct 15, 2024
5a7aa89
Simplify findById search
ashuntu Oct 15, 2024
4e1ac10
Rename 'rating' to 'rank' for clarity on its usage
ashuntu Oct 15, 2024
73e1b4e
Add explicit mapping to chart categories
ashuntu Oct 15, 2024
6c0d382
Ensure all custom categories are mapped to charts
ashuntu Oct 16, 2024
f48a9b0
Remove unnecessary color definition
ashuntu Oct 16, 2024
01cf48b
Split ranked app cards into dedicated card and grid widgets
ashuntu Oct 16, 2024
8e1006e
Remove unneeded categories for Games ranked grid
ashuntu Oct 17, 2024
58fbb98
Fix error on assertion when no snap is found
ashuntu Oct 17, 2024
f69dea0
Regenerate riverpod category model
ashuntu Oct 17, 2024
23375de
Fallback to old behavior when no ratings server is found
ashuntu Oct 17, 2024
7686f38
Fail silently on parse errors in assertions
ashuntu Oct 18, 2024
2498a6b
Temporary disable TLS
ashuntu Oct 18, 2024
12c5e53
Revert "Temporary disable TLS"
ashuntu Oct 18, 2024
0b59668
Fix trailing comma analyzer issue
ashuntu Oct 18, 2024
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
12 changes: 10 additions & 2 deletions packages/app_center/lib/games/games_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,16 @@ class GamesPage extends ConsumerWidget {
const SizedBox(height: kPagePadding),
],
),
const CategorySnapList(
category: SnapCategoryEnum.games,
const RatedCategorySnapList(
categories: [
SnapCategoryEnum.games,
SnapCategoryEnum.kdeGames,
SnapCategoryEnum.gnomeGames,
SnapCategoryEnum.gameLaunchers,
SnapCategoryEnum.gameEmulators,
SnapCategoryEnum.gameContentCreation,
SnapCategoryEnum.gameDev,
d-loose marked this conversation as resolved.
Show resolved Hide resolved
],
),
SliverList.list(
children: [
Expand Down
2 changes: 1 addition & 1 deletion packages/app_center/lib/games/games_page_featured.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class FeaturedCarousel extends ConsumerStatefulWidget {

class _FeaturedCarouselState extends ConsumerState<FeaturedCarousel> {
late YaruCarouselController controller;
late Iterable<Snap> snaps;
Iterable<Snap> snaps = [];

@override
Widget build(BuildContext context) {
Expand Down
33 changes: 33 additions & 0 deletions packages/app_center/lib/ratings/rated_category_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:app_center/ratings/ratings_service.dart';
import 'package:app_center/snapd/snapd.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:snapd/snapd.dart';
import 'package:ubuntu_service/ubuntu_service.dart';

part 'rated_category_model.g.dart';

@riverpod
class RatedCategoryModel extends _$RatedCategoryModel {
late final _ratings = getService<RatingsService>();
late final _snapd = getService<SnapdService>();

@override
Future<List<Snap>> build(
List<SnapCategoryEnum> categories,
int numberOfSnaps,
) async {
final snaps = <Snap>[];

for (final category in categories) {
final chart = await _ratings.getChart(category);
for (var i = 0; snaps.length < numberOfSnaps && i < chart.length; i++) {
final snap = await _snapd.findById(chart[i].rating.snapId);
if (snap != null && snap.screenshotUrls.isNotEmpty) {
snaps.add(snap);
}
}
}

return snaps;
}
}
199 changes: 199 additions & 0 deletions packages/app_center/lib/ratings/rated_category_model.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 55 additions & 6 deletions packages/app_center/lib/ratings/ratings_service.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import 'dart:convert';
import 'dart:io';

import 'package:app_center_ratings_client/app_center_ratings_client.dart';
import 'package:app_center/snapd/snap_category_enum.dart';
import 'package:app_center_ratings_client/app_center_ratings_client.dart'
as ratings;
import 'package:crypto/crypto.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:glib/glib.dart';
import 'package:jwt_decode/jwt_decode.dart';
Expand All @@ -11,7 +14,7 @@ class RatingsService {
RatingsService(this.client, {@visibleForTesting String? id})
: _id = id ?? _generateId();

final RatingsClient client;
final ratings.RatingsClient client;
String? _jwt;
final String _id;

Expand All @@ -27,12 +30,21 @@ class RatingsService {
}
}

Future<Rating?> getRating(String snapId) async {
Future<ratings.Rating?> getRating(String snapId) async {
await _ensureValidToken();
return client.getRating(snapId, _jwt!);
}

Future<void> vote(Vote vote) async {
Future<List<ratings.ChartData>> getChart(SnapCategoryEnum category) async {
await _ensureValidToken();
return client.getChart(
ratings.Timeframe.unspecified,
_jwt!,
category.toProto(),
);
}

Future<void> vote(ratings.Vote vote) async {
await _ensureValidToken();
await client.vote(vote.snapId, vote.snapRevision, vote.voteUp, _jwt!);
}
Expand All @@ -42,13 +54,50 @@ class RatingsService {
await client.delete(_jwt!);
}

Future<List<Vote>> listMyVotes(String snapFilter) async {
Future<List<ratings.Vote>> listMyVotes(String snapFilter) async {
await _ensureValidToken();
return client.listMyVotes(snapFilter, _jwt!);
}

Future<List<Vote>> getSnapVotes(String snapId) async {
Future<List<ratings.Vote>> getSnapVotes(String snapId) async {
await _ensureValidToken();
return client.getSnapVotes(snapId, _jwt!);
}
}

extension CategoryToChartConversion on SnapCategoryEnum {
ratings.Category toProto() => switch (this) {
SnapCategoryEnum.artAndDesign => ratings.Category.ART_AND_DESIGN,
SnapCategoryEnum.booksAndReference =>
ratings.Category.BOOK_AND_REFERENCE,
SnapCategoryEnum.development => ratings.Category.DEVELOPMENT,
SnapCategoryEnum.devicesAndIot => ratings.Category.DEVICES_AND_IOT,
SnapCategoryEnum.education => ratings.Category.EDUCATION,
SnapCategoryEnum.entertainment => ratings.Category.ENTERTAINMENT,
SnapCategoryEnum.featured => ratings.Category.FEATURED,
SnapCategoryEnum.finance => ratings.Category.FINANCE,
SnapCategoryEnum.gameDev => ratings.Category.GAMES,
SnapCategoryEnum.gameEmulators => ratings.Category.GAMES,
SnapCategoryEnum.games => ratings.Category.GAMES,
SnapCategoryEnum.gnomeGames => ratings.Category.GAMES,
SnapCategoryEnum.kdeGames => ratings.Category.GAMES,
SnapCategoryEnum.gameLaunchers => ratings.Category.GAMES,
SnapCategoryEnum.gameContentCreation => ratings.Category.GAMES,
SnapCategoryEnum.healthAndFitness =>
ratings.Category.HEALTH_AND_FITNESS,
SnapCategoryEnum.musicAndAudio => ratings.Category.MUSIC_AND_AUDIO,
SnapCategoryEnum.newsAndWeather => ratings.Category.NEWS_AND_WEATHER,
SnapCategoryEnum.personalisation => ratings.Category.PERSONALISATION,
SnapCategoryEnum.photoAndVideo => ratings.Category.PHOTO_AND_VIDEO,
SnapCategoryEnum.productivity => ratings.Category.PRODUCTIVITY,
SnapCategoryEnum.science => ratings.Category.SCIENCE,
SnapCategoryEnum.security => ratings.Category.SECURITY,
SnapCategoryEnum.serverAndCloud => ratings.Category.SERVER_AND_CLOUD,
SnapCategoryEnum.social => ratings.Category.SOCIAL,
SnapCategoryEnum.utilities => ratings.Category.UTILITIES,
SnapCategoryEnum.unknown =>
throw ArgumentError('Category $this cannot be converted'),
SnapCategoryEnum.ubuntuDesktop =>
throw ArgumentError('Category $this cannot be converted'),
};
}
15 changes: 15 additions & 0 deletions packages/app_center/lib/snapd/snapd_service.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import 'package:app_center/snapd/snapd_cache.dart';
import 'package:app_center/snapd/snapd_watcher.dart';
import 'package:collection/collection.dart';
import 'package:snapd/snapd.dart';

class SnapdService extends SnapdClient with SnapdCache, SnapdWatcher {
Future<void> waitChange(String changeId) =>
watchChange(changeId).firstWhere((change) => change.ready);

Future<Snap?> findById(String snapId) async {
final queryParams = {
'series': '16',
'remote': 'true',
'snap-id': snapId,
};
final result =
await getAssertions(assertion: 'snap-declaration', params: queryParams);
final declaration = SnapDeclaration.fromJson(result);
final findResult = await find(name: declaration.snapName);
d-loose marked this conversation as resolved.
Show resolved Hide resolved
return findResult
.singleWhereOrNull((element) => element.id == declaration.snapId);
}
}
2 changes: 1 addition & 1 deletion packages/app_center/lib/src/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
"developmentPageLabel": "Development",
"gamesPageLabel": "Games",
"gamesPageTitle": "What's Hot",
"gamesPageTop": "Top Games",
"gamesPageTop": "Top Rated",
"gamesPageFeatured": "Featured Titles",
"gamesPageBundles": "App Bundles",
"unknownPublisher": "Unknown publisher",
Expand Down
Loading
Loading