Settings multi-select filters Top/category/tag lists via Helix (with over-fetch for multiple languages). Larger Helix pages, safer cursors, and scroll near-end loading restore pagination; GQL page-2 integrity failures end the list cleanly. Co-authored-by: Cursor <cursoragent@cursor.com>
62 lines
1.6 KiB
Dart
62 lines
1.6 KiB
Dart
import 'package:json_annotation/json_annotation.dart';
|
|
|
|
part 'stream.g.dart';
|
|
|
|
// Object for live Twitch streams.
|
|
@JsonSerializable(createToJson: false, fieldRename: FieldRename.snake)
|
|
class StreamTwitch {
|
|
final String userId;
|
|
final String userLogin;
|
|
final String userName;
|
|
final String gameId;
|
|
final String gameName;
|
|
final String title;
|
|
final int viewerCount;
|
|
final String startedAt;
|
|
final String thumbnailUrl;
|
|
|
|
/// ISO 639-1 broadcast language from Helix (`de`, `en`, …). Empty when unknown.
|
|
@JsonKey(defaultValue: '')
|
|
final String language;
|
|
|
|
const StreamTwitch(
|
|
this.userId,
|
|
this.userLogin,
|
|
this.userName,
|
|
this.gameId,
|
|
this.gameName,
|
|
this.title,
|
|
this.viewerCount,
|
|
this.startedAt,
|
|
this.thumbnailUrl, [
|
|
this.language = '',
|
|
]);
|
|
|
|
factory StreamTwitch.fromJson(Map<String, dynamic> json) =>
|
|
_$StreamTwitchFromJson(json);
|
|
}
|
|
|
|
@JsonSerializable(createToJson: false, fieldRename: FieldRename.snake)
|
|
class StreamsTwitch {
|
|
final List<StreamTwitch> data;
|
|
final Map<String, String> pagination;
|
|
|
|
const StreamsTwitch(this.data, this.pagination);
|
|
|
|
factory StreamsTwitch.fromJson(Map<String, dynamic> json) {
|
|
final rawPagination = json['pagination'];
|
|
final pagination = <String, String>{};
|
|
if (rawPagination is Map) {
|
|
final cursor = rawPagination['cursor'];
|
|
if (cursor is String && cursor.isNotEmpty) {
|
|
pagination['cursor'] = cursor;
|
|
}
|
|
}
|
|
return StreamsTwitch(
|
|
(json['data'] as List<dynamic>)
|
|
.map((e) => StreamTwitch.fromJson(e as Map<String, dynamic>))
|
|
.toList(),
|
|
pagination,
|
|
);
|
|
}
|
|
}
|