commit 5010af7384502ab338760324a617f97725a62938 Author: Rapougnac Date: Tue May 7 00:14:45 2024 +0200 Initial commit diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..effe43c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## 1.0.0 + +- Initial version. diff --git a/README.md b/README.md new file mode 100644 index 0000000..b6dc1fd --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Overfast diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/bin/main.dart b/bin/main.dart new file mode 100644 index 0000000..b6b25df --- /dev/null +++ b/bin/main.dart @@ -0,0 +1,25 @@ +import 'dart:convert'; + +import 'package:overfast_api/client.dart'; +import 'package:overfast_api/utils/types.dart'; + +void main(List args) async { + final client = Overfast(); + + // final me = client.players.player('Rapougnac-2980'); + + // final stats = await me.statsSummary(); + + // print(stats.heroes['doomfist']!.gamesWon); + + // final doom = await client.heroes.hero(Hero.doomfist,locale: Locale.frFr); + + // print(doom.description); + + // final heroes = await client.heroes.heroes(locale: Locale.frFr); + + // print(jsonEncode(heroes)); + + final hero = client.heroes.hero(HeroKey.junkerqueen, locale: Locale.frFr); + print(hero); +} diff --git a/lib/client.dart b/lib/client.dart new file mode 100644 index 0000000..52437f3 --- /dev/null +++ b/lib/client.dart @@ -0,0 +1,40 @@ +import 'package:http/http.dart' as http; +import 'package:overfast_api/heroes/heroes.dart'; +import 'package:overfast_api/players/players.dart'; + +import './utils/utils.dart' as utils; +import 'maps/maps.dart'; + +class Overfast { + final Uri baseUri; + + late final Future Function( + String, [ + Map, + ]) get; + + late final Future> Function( + String, [ + Map, + ]) getList; + + final client = http.Client(); + + + late final Maps maps; + late final Players players; + late final Heroes heroes; + + Overfast([Uri? baseUri]) + : baseUri = baseUri ?? Uri.https('overfast-api.tekrop.fr') { + get = utils.get(client, this.baseUri); + getList = utils.getList(client, this.baseUri); + maps = Maps(this); + players = Players(this); + heroes = Heroes(this); + } + + void close() { + client.close(); + } +} diff --git a/lib/heroes/heroes.dart b/lib/heroes/heroes.dart new file mode 100644 index 0000000..6287e0d --- /dev/null +++ b/lib/heroes/heroes.dart @@ -0,0 +1,34 @@ +import 'package:overfast_api/client.dart'; +import 'package:overfast_api/heroes/heroes_data.dart' as data; +import 'package:overfast_api/utils/types.dart'; + +class Heroes { + final Overfast _client; + + const Heroes(this._client); + + Future> heroes({Role? role, Locale? locale}) => + _client.getList( + '/heroes', + { + if (role != null) 'role': role.toString(), + if (locale != null) 'locale': locale.toString(), + }, + ); + + Future hero(HeroKey hero, {Locale? locale}) => + _client.get( + '/heroes/${hero.heroName}', + { + if (locale != null) 'locale': locale.toString(), + }, + ); + + Future> roles({Locale? locale}) => + _client.getList( + '/roles', + { + if (locale != null) 'locale': locale.toString(), + }, + ); +} diff --git a/lib/heroes/heroes_data.dart b/lib/heroes/heroes_data.dart new file mode 100644 index 0000000..6d38746 --- /dev/null +++ b/lib/heroes/heroes_data.dart @@ -0,0 +1,284 @@ +import 'package:overfast_api/utils/types.dart'; + +class Hero { + final String name; + final HeroKey key; + final String? portrait; + final Role role; + + const Hero({ + required this.name, + required this.key, + this.portrait, + required this.role, + }); + + factory Hero.fromJson(Map json) { + return Hero( + name: json['name'], + key: HeroKey.fromString(json['key']), + portrait: json['portrait'], + role: Role.fromString(json['role']), + ); + } + + Map toJson() { + return { + 'name': name, + 'key': key.name, + 'portrait': portrait, + 'role': role.toString(), + }; + } +} + +class HeroDetails extends Hero { + final String location; + final List abilities; + final Map? hitpoints; + final Story story; + final String description; + final int age; + final String? birthday; + + + const HeroDetails({ + required super.name, + required super.role, + super.portrait, + required this.description, + required this.story, + required this.location, + required this.abilities, + this.hitpoints, + // Stub + super.key = HeroKey.eemptyy, + required this.age, + required this.birthday, + }); + + factory HeroDetails.fromJson(Map json) { + return HeroDetails( + name: json['name'], + description: (json['description']), + portrait: json['portrait'], + role: Role.fromString(json['role']), + location: json['location'], + abilities: + (json['abilities'] as List).map((e) => Ability.fromJson(e)).toList(), + hitpoints: json['hitpoints'], + story: Story.fromJson(json['story']), + age: json['age'], + birthday: json['birthday'], + ); + } + + @override + Map toJson() { + return { + 'name': name, + 'description': description, + 'portrait': portrait, + 'role': role.toString(), + 'location': location, + 'abilities': abilities.map((e) => e.toJson()).toList(), + 'hitpoints': hitpoints, + 'story': story.toJson(), + 'age': age, + 'birthday': birthday, + }; + } +} + +class Ability { + final String name; + final String description; + final String icon; + final Video video; + + const Ability({ + required this.name, + required this.description, + required this.icon, + required this.video, + }); + + factory Ability.fromJson(Map json) { + return Ability( + name: json['name'], + description: json['description'], + icon: json['icon'], + video: Video.fromJson(json['video']), + ); + } + + Map toJson() { + return { + 'name': name, + 'description': description, + 'icon': icon, + 'video': video.toJson(), + }; + } +} + +class Video { + final String thumbnail; + final Link link; + + const Video({ + required this.thumbnail, + required this.link, + }); + + factory Video.fromJson(Map json) { + return Video( + thumbnail: json['thumbnail'], + link: Link.fromJson(json['link']), + ); + } + + Map toJson() { + return { + 'thumbnail': thumbnail, + 'link': link.toJson(), + }; + } +} + +class Link { + final String mp4; + final String webm; + + const Link({ + required this.mp4, + required this.webm, + }); + + factory Link.fromJson(Map json) { + return Link( + mp4: json['mp4'], + webm: json['webm'], + ); + } + + Map toJson() { + return { + 'mp4': mp4, + 'webm': webm, + }; + } +} + +class Story { + final String summary; + final Media? media; + final List chapters; + + const Story({ + required this.summary, + required this.media, + required this.chapters, + }); + + factory Story.fromJson(Map json) { + return Story( + summary: json['summary'], + media: json['media'] != null ? Media.fromJson(json['media']) : null, + chapters: + (json['chapters'] as List).map((e) => Chapter.fromJson(e)).toList(), + ); + } + + Map toJson() { + return { + 'summary': summary, + if (media != null) 'media': media!.toJson(), + 'chapters': chapters.map((e) => e.toJson()).toList(), + }; + } +} + +class Media { + final String type; + final String link; + + const Media({ + required this.type, + required this.link, + }); + + factory Media.fromJson(Map json) { + return Media( + type: json['type'], + link: json['link'], + ); + } + + Map toJson() { + return { + 'type': type, + 'link': link, + }; + } +} + +class Chapter { + final String title; + final String content; + final String picture; + + const Chapter({ + required this.title, + required this.content, + required this.picture, + }); + + factory Chapter.fromJson(Map json) { + return Chapter( + title: json['title'], + content: json['content'], + picture: json['picture'], + ); + } + + Map toJson() { + return { + 'title': title, + 'content': content, + 'picture': picture, + }; + } +} + +class Roles { + final Role key; + final String name; + final String icon; + final String description; + + const Roles({ + required this.key, + required this.name, + required this.icon, + required this.description, + }); + + factory Roles.fromJson(Map json) { + return Roles( + key: Role.fromString(json['key']), + name: json['name'], + icon: json['icon'], + description: json['description'], + ); + } + + Map toJson() { + return { + 'key': key.toString(), + 'name': name, + 'icon': icon, + 'description': description, + }; + } +} \ No newline at end of file diff --git a/lib/maps/maps.dart b/lib/maps/maps.dart new file mode 100644 index 0000000..8554162 --- /dev/null +++ b/lib/maps/maps.dart @@ -0,0 +1,92 @@ +import 'dart:convert'; + +import 'package:overfast_api/client.dart'; +import 'package:overfast_api/utils/utils.dart'; + +enum Gamemode { + assault, + captureTheFlag, + control, + deathmatch, + elimination, + escort, + hybrid, + push, + teamDeathmatch, + flashpoint, + clash; + + @override + String toString() => toKebabCase(name); + + static Gamemode fromString(String value) { + return Gamemode.values.firstWhere((e) => e.toString() == value); + } +} + +final class GameMap { + final String name; + final List gamemodes; + final String screenshot; + final String location; + final String? countryCode; + + const GameMap({ + required this.name, + required this.gamemodes, + required this.screenshot, + required this.location, + this.countryCode, + }); + + // Stub empty constructor + GameMap.empty() : this(name: '', gamemodes: [], screenshot: '', location: ''); + + factory GameMap.fromJson(Map json) { + return GameMap( + name: json['name'], + gamemodes: (json['gamemodes'] as List) + .map((e) => Gamemode.fromString(e)) + .cast() + .toList(), + screenshot: json['screenshot'], + location: json['location'], + countryCode: json['countryCode'], + ); + } + + Map toJson() { + return { + 'name': name, + 'gamemode': gamemodes.map((e) => e.toString()).toList(), + 'screenshot': screenshot, + 'location': location, + 'countryCode': countryCode, + }; + } +} + +final class Maps { + final Overfast _client; + + Maps(this._client); + + Future> maps({Gamemode? gameMode}) => _client.getList( + '/maps', + gameMode != null ? {'gamemode': gameMode.toString()} : {}, + ); + + Future> gamemodes() async { + // Special case, manual request + final response = await _client.client.get( + _client.baseUri.replace(path: '/maps/gamemodes'), + ); + + throwIfNecessary(response.statusCode, response.body); + + return (json.decode(response.body) as List) + .map((e) => Gamemode.fromString(e)) + .cast() + .toList(); + } +} diff --git a/lib/overfast_api.dart b/lib/overfast_api.dart new file mode 100644 index 0000000..93a3257 --- /dev/null +++ b/lib/overfast_api.dart @@ -0,0 +1 @@ +export 'client.dart'; diff --git a/lib/players/data_types.dart b/lib/players/data_types.dart new file mode 100644 index 0000000..8daaae2 --- /dev/null +++ b/lib/players/data_types.dart @@ -0,0 +1,1928 @@ +CareerProfile careerProfileFromJson(Map raw) => + CareerProfile.fromJson(raw); + +Map careerProfileToJson(CareerProfile data) => data.toJson(); + +typedef Baptiste = Ana; +typedef Bastion = Ashe; +typedef Cassidy = Ashe; +typedef Doomfist = Ashe; +typedef Echo = Ashe; +typedef JunkerQueen = Ashe; +typedef Mei = Junkrat; +typedef Ramattra = Junkrat; +typedef Moira = Mercy; +typedef Soujourn = Ashe; +typedef RoadHog = Illari; +typedef Soldier76 = Mercy; +typedef Sombra = Junkrat; +typedef Torbjorn = Ashe; +typedef Winston = Ashe; +typedef Zenyatta = Mercy; + +class CareerProfile { + final AllHeroes? allHeroes; + final Ana? ana; + final Ashe? ashe; + final Baptiste? baptiste; + final Bastion? bastion; + final Brigitte? brigitte; + final Cassidy? cassidy; + final Dva? dva; + final Doomfist? doomfist; + final Echo? echo; + final Genji? genji; + final Hanzo? hanzo; + final Illari? illari; + final JunkerQueen? junkerQueen; + final Junkrat? junkrat; + final Kiriko? kiriko; + final Lifeweaver? lifeweaver; + final Lucio? lucio; + final Mauga? mauga; + final Mei? mei; + final Mercy? mercy; + final Moira? moira; + final Orisa? orisa; + final Pharah? pharah; + final Ramattra? ramattra; + final Reaper? reaper; + final Reinhardt? reinhardt; + final RoadHog? roadhog; + final Sigma? sigma; + final Soujourn? sojourn; + final Soldier76? soldier76; + final Sombra? sombra; + final Torbjorn? torbjorn; + final Tracer? tracer; + final Widowmaker? widowmaker; + final Winston? winston; + final WreckingBall? wreckingBall; + final Zenyatta? zenyatta; + + CareerProfile({ + this.allHeroes, + this.ana, + this.ashe, + this.baptiste, + this.bastion, + this.brigitte, + this.cassidy, + this.dva, + this.doomfist, + this.echo, + this.genji, + this.hanzo, + this.illari, + this.junkerQueen, + this.junkrat, + this.kiriko, + this.lifeweaver, + this.lucio, + this.mauga, + this.mei, + this.mercy, + this.moira, + this.orisa, + this.pharah, + this.ramattra, + this.reaper, + this.reinhardt, + this.roadhog, + this.sigma, + this.sojourn, + this.soldier76, + this.sombra, + this.torbjorn, + this.tracer, + this.widowmaker, + this.winston, + this.wreckingBall, + this.zenyatta, + }); + + @override + factory CareerProfile.fromJson(Map json) => CareerProfile( + allHeroes: json["all-heroes"] == null ? null : AllHeroes.fromJson(json["all-heroes"]), + ana: json["ana"] == null ? null : Ana.fromJson(json["ana"]), + ashe: json["ashe"] == null ? null : Ashe.fromJson(json["ashe"]), + baptiste: json["baptiste"] == null ? null : Ana.fromJson(json["baptiste"]), + bastion: json["bastion"] == null ? null : Ashe.fromJson(json["bastion"]), + brigitte: json["brigitte"] == null ? null : Brigitte.fromJson(json["brigitte"]), + cassidy: json["cassidy"] == null ? null : Ashe.fromJson(json["cassidy"]), + dva: json["dva"] == null ? null : Dva.fromJson(json["dva"]), + doomfist: json["doomfist"] == null ? null : Ashe.fromJson(json["doomfist"]), + echo: json["echo"] == null ? null : Ashe.fromJson(json["echo"]), + genji: json["genji"] == null ? null : Genji.fromJson(json["genji"]), + hanzo: json["hanzo"] == null ? null : Hanzo.fromJson(json["hanzo"]), + illari: json["illari"] == null ? null : Illari.fromJson(json["illari"]), + junkerQueen: json["junker-queen"] == null ? null : Ashe.fromJson(json["junker-queen"]), + junkrat: json["junkrat"] == null ? null : Junkrat.fromJson(json["junkrat"]), + kiriko: json["kiriko"] == null ? null : Kiriko.fromJson(json["kiriko"]), + lifeweaver: json["lifeweaver"] == null ? null : Lifeweaver.fromJson(json["lifeweaver"]), + lucio: json["lucio"] == null ? null : Lucio.fromJson(json["lucio"]), + mauga: json["mauga"] == null ? null : Mauga.fromJson(json["mauga"]), + mei: json["mei"] == null ? null : Junkrat.fromJson(json["mei"]), + mercy: json["mercy"] == null ? null : Mercy.fromJson(json["mercy"]), + moira: json["moira"] == null ? null : Mercy.fromJson(json["moira"]), + orisa: json["orisa"] == null ? null : Orisa.fromJson(json["orisa"]), + pharah: json["pharah"] == null ? null : Pharah.fromJson(json["pharah"]), + ramattra: json["ramattra"] == null ? null : Junkrat.fromJson(json["ramattra"]), + reaper: json["reaper"] == null ? null : Reaper.fromJson(json["reaper"]), + reinhardt: json["reinhardt"] == null ? null : Reinhardt.fromJson(json["reinhardt"]), + roadhog: json["roadhog"] == null ? null : Illari.fromJson(json["roadhog"]), + sigma: json["sigma"] == null ? null : Sigma.fromJson(json["sigma"]), + sojourn: json["sojourn"] == null ? null : Ashe.fromJson(json["sojourn"]), + soldier76: json["soldier-76"] == null ? null : Mercy.fromJson(json["soldier-76"]), + sombra: json["sombra"] == null ? null : Junkrat.fromJson(json["sombra"]), + torbjorn: json["torbjorn"] == null ? null : Ashe.fromJson(json["torbjorn"]), + tracer: json["tracer"] == null ? null : Tracer.fromJson(json["tracer"]), + widowmaker: json["widowmaker"] == null ? null : Widowmaker.fromJson(json["widowmaker"]), + winston: json["winston"] == null ? null : Ashe.fromJson(json["winston"]), + wreckingBall: json["wrecking-ball"] == null ? null : WreckingBall.fromJson(json["wrecking-ball"]), + zenyatta: json["zenyatta"] == null ? null : Mercy.fromJson(json["zenyatta"]), + ); + + Map toJson() => { + "all-heroes": allHeroes?.toJson(), + "ana": ana?.toJson(), + "ashe": ashe?.toJson(), + "baptiste": baptiste?.toJson(), + "bastion": bastion?.toJson(), + "brigitte": brigitte?.toJson(), + "cassidy": cassidy?.toJson(), + "dva": dva?.toJson(), + "doomfist": doomfist?.toJson(), + "echo": echo?.toJson(), + "genji": genji?.toJson(), + "hanzo": hanzo?.toJson(), + "illari": illari?.toJson(), + "junker-queen": junkerQueen?.toJson(), + "junkrat": junkrat?.toJson(), + "kiriko": kiriko?.toJson(), + "lifeweaver": lifeweaver?.toJson(), + "lucio": lucio?.toJson(), + "mauga": mauga?.toJson(), + "mei": mei?.toJson(), + "mercy": mercy?.toJson(), + "moira": moira?.toJson(), + "orisa": orisa?.toJson(), + "pharah": pharah?.toJson(), + "ramattra": ramattra?.toJson(), + "reaper": reaper?.toJson(), + "reinhardt": reinhardt?.toJson(), + "roadhog": roadhog?.toJson(), + "sigma": sigma?.toJson(), + "sojourn": sojourn?.toJson(), + "soldier-76": soldier76?.toJson(), + "sombra": sombra?.toJson(), + "torbjorn": torbjorn?.toJson(), + "tracer": tracer?.toJson(), + "widowmaker": widowmaker?.toJson(), + "winston": winston?.toJson(), + "wrecking-ball": wreckingBall?.toJson(), + "zenyatta": zenyatta?.toJson(), + }; +} + +class AllHeroes { + final AllHeroesAssists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final MatchAwards? matchAwards; + + AllHeroes({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + this.matchAwards, + }); + + factory AllHeroes.fromJson(Map json) => AllHeroes( + assists: AllHeroesAssists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + matchAwards: json["match_awards"] == null + ? null + : json['match_awards'] == null ? null : MatchAwards.fromJson(json["match_awards"]), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "match_awards": matchAwards?.toJson(), + }; +} + +class AllHeroesAssists { + final int reconAssists; + final int healingDone; + final int defensiveAssists; + final int offensiveAssists; + final int assists; + + AllHeroesAssists({ + required this.reconAssists, + required this.healingDone, + required this.defensiveAssists, + required this.offensiveAssists, + required this.assists, + }); + + factory AllHeroesAssists.fromJson(Map json) => + AllHeroesAssists( + reconAssists: json["recon_assists"], + healingDone: json["healing_done"], + defensiveAssists: json["defensive_assists"], + offensiveAssists: json["offensive_assists"], + assists: json["assists"], + ); + + Map toJson() => { + "recon_assists": reconAssists, + "healing_done": healingDone, + "defensive_assists": defensiveAssists, + "offensive_assists": offensiveAssists, + "assists": assists, + }; +} + +class AllHeroesGame { + final int timePlayed; + final int gamesPlayed; + final int gamesWon; + final int gamesLost; + final int heroWins; + final int? winPercentage; + final int? knockbackKillsMostInGame; + + AllHeroesGame({ + required this.timePlayed, + required this.gamesPlayed, + required this.gamesWon, + required this.gamesLost, + required this.heroWins, + this.winPercentage, + this.knockbackKillsMostInGame, + }); + + factory AllHeroesGame.fromJson(Map json) => AllHeroesGame( + timePlayed: json["time_played"], + gamesPlayed: json["games_played"], + gamesWon: json["games_won"], + gamesLost: json["games_lost"], + heroWins: json["hero_wins"], + winPercentage: json["win_percentage"], + knockbackKillsMostInGame: json["knockback_kills_most_in_game"], + ); + + Map toJson() => { + "time_played": timePlayed, + "games_played": gamesPlayed, + "games_won": gamesWon, + "games_lost": gamesLost, + "hero_wins": heroWins, + "win_percentage": winPercentage, + "knockback_kills_most_in_game": knockbackKillsMostInGame, + }; +} + +class MatchAwards { + final int cards; + + MatchAwards({ + required this.cards, + }); + + factory MatchAwards.fromJson(Map json) => MatchAwards( + cards: json["cards"], + ); + + Map toJson() => { + "cards": cards, + }; +} + +class Ana { + final Assists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final Map heroSpecific; + final MatchAwards? matchAwards; + + Ana({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + this.matchAwards, + }); + + factory Ana.fromJson(Map json) => Ana( + assists: Assists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: Map.from(json["hero_specific"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + matchAwards: json['match_awards'] == null ? null : MatchAwards.fromJson(json["match_awards"]), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": Map.from(heroSpecific) + .map((k, v) => MapEntry(k, v)), + "match_awards": matchAwards?.toJson(), + }; +} + +class Assists { + final int? offensiveAssists; + final int? offensiveAssistsMostInGame; + final int defensiveAssists; + final int defensiveAssistsMostInGame; + final int healingDone; + final int healingDoneMostInGame; + final int assists; + final double defensiveAssistsAvgPer10Min; + final double? offensiveAssistsAvgPer10Min; + + Assists({ + this.offensiveAssists, + this.offensiveAssistsMostInGame, + required this.defensiveAssists, + required this.defensiveAssistsMostInGame, + required this.healingDone, + required this.healingDoneMostInGame, + required this.assists, + required this.defensiveAssistsAvgPer10Min, + this.offensiveAssistsAvgPer10Min, + }); + + factory Assists.fromJson(Map json) => Assists( + offensiveAssists: json["offensive_assists"], + offensiveAssistsMostInGame: json["offensive_assists_most_in_game"], + defensiveAssists: json["defensive_assists"], + defensiveAssistsMostInGame: json["defensive_assists_most_in_game"], + healingDone: json["healing_done"], + healingDoneMostInGame: json["healing_done_most_in_game"], + assists: json["assists"], + defensiveAssistsAvgPer10Min: + json["defensive_assists_avg_per_10_min"]?.toDouble(), + offensiveAssistsAvgPer10Min: + json["offensive_assists_avg_per_10_min"]?.toDouble(), + ); + + Map toJson() => { + "offensive_assists": offensiveAssists, + "offensive_assists_most_in_game": offensiveAssistsMostInGame, + "defensive_assists": defensiveAssists, + "defensive_assists_most_in_game": defensiveAssistsMostInGame, + "healing_done": healingDone, + "healing_done_most_in_game": healingDoneMostInGame, + "assists": assists, + "defensive_assists_avg_per_10_min": defensiveAssistsAvgPer10Min, + "offensive_assists_avg_per_10_min": offensiveAssistsAvgPer10Min, + }; +} + +class Ashe { + final AsheAssists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final Map heroSpecific; + + Ashe({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Ashe.fromJson(Map json) => Ashe( + assists: AsheAssists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: Map.from(json["hero_specific"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": Map.from(heroSpecific) + .map((k, v) => MapEntry(k, v)), + }; +} + +class AsheAssists { + final int assists; + + AsheAssists({ + required this.assists, + }); + + factory AsheAssists.fromJson(Map json) => AsheAssists( + assists: json["assists"], + ); + + Map toJson() => { + "assists": assists, + }; +} + +class Brigitte { + final Assists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final BrigitteHeroSpecific heroSpecific; + + Brigitte({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Brigitte.fromJson(Map json) => Brigitte( + assists: Assists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: BrigitteHeroSpecific.fromJson(json["hero_specific"]), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": heroSpecific.toJson(), + }; +} + +class BrigitteHeroSpecific { + final int selfHealing; + final int overhealthProvided; + final int overhealthProvidedMostInGame; + final int whipshotsAttempted; + final int playersKnockedBack; + final int selfHealingAvgPer10Min; + final int inspireUptimePercentage; + final int whipshotAccuracy; + final int overhealthProvidedAvgPer10Min; + final double playersKnockedBackAvgPer10MinNyi; + + BrigitteHeroSpecific({ + required this.selfHealing, + required this.overhealthProvided, + required this.overhealthProvidedMostInGame, + required this.whipshotsAttempted, + required this.playersKnockedBack, + required this.selfHealingAvgPer10Min, + required this.inspireUptimePercentage, + required this.whipshotAccuracy, + required this.overhealthProvidedAvgPer10Min, + required this.playersKnockedBackAvgPer10MinNyi, + }); + + factory BrigitteHeroSpecific.fromJson(Map json) => + BrigitteHeroSpecific( + selfHealing: json["self_healing"], + overhealthProvided: json["overhealth_provided"], + overhealthProvidedMostInGame: json["overhealth_provided_most_in_game"], + whipshotsAttempted: json["whipshots_attempted"], + playersKnockedBack: json["players_knocked_back"], + selfHealingAvgPer10Min: json["self_healing_avg_per_10_min"], + inspireUptimePercentage: json["inspire_uptime_percentage"], + whipshotAccuracy: json["whipshot_accuracy"], + overhealthProvidedAvgPer10Min: + json["overhealth_provided_avg_per_10_min"], + playersKnockedBackAvgPer10MinNyi: + json["players_knocked_back_avg_per_10_min_nyi"]?.toDouble(), + ); + + Map toJson() => { + "self_healing": selfHealing, + "overhealth_provided": overhealthProvided, + "overhealth_provided_most_in_game": overhealthProvidedMostInGame, + "whipshots_attempted": whipshotsAttempted, + "players_knocked_back": playersKnockedBack, + "self_healing_avg_per_10_min": selfHealingAvgPer10Min, + "inspire_uptime_percentage": inspireUptimePercentage, + "whipshot_accuracy": whipshotAccuracy, + "overhealth_provided_avg_per_10_min": overhealthProvidedAvgPer10Min, + "players_knocked_back_avg_per_10_min_nyi": + playersKnockedBackAvgPer10MinNyi, + }; +} + +class Dva { + final AsheAssists assists; + final Map average; + final Map best; + final Map combat; + final DvaGame game; + final DvaHeroSpecific heroSpecific; + + Dva({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Dva.fromJson(Map json) => Dva( + assists: AsheAssists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: DvaGame.fromJson(json["game"]), + heroSpecific: DvaHeroSpecific.fromJson(json["hero_specific"]), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": heroSpecific.toJson(), + }; +} + +class DvaGame { + final int timePlayed; + final int gamesPlayed; + final int gamesLost; + + DvaGame({ + required this.timePlayed, + required this.gamesPlayed, + required this.gamesLost, + }); + + factory DvaGame.fromJson(Map json) => DvaGame( + timePlayed: json["time_played"], + gamesPlayed: json["games_played"], + gamesLost: json["games_lost"], + ); + + Map toJson() => { + "time_played": timePlayed, + "games_played": gamesPlayed, + "games_lost": gamesLost, + }; +} + +class DvaHeroSpecific { + final int microMissileKills; + final int? callMechKills; + final int microMissileKillsMostInGame; + final int? callMechKillsMostInGame; + final double microMissileKillsAvgPer10Min; + + DvaHeroSpecific({ + required this.microMissileKills, + required this.callMechKills, + required this.microMissileKillsMostInGame, + required this.callMechKillsMostInGame, + required this.microMissileKillsAvgPer10Min, + }); + + factory DvaHeroSpecific.fromJson(Map json) => + DvaHeroSpecific( + microMissileKills: json["micro_missile_kills"], + callMechKills: json["call_mech_kills"], + microMissileKillsMostInGame: json["micro_missile_kills_most_in_game"], + callMechKillsMostInGame: json["call_mech_kills_most_in_game"], + microMissileKillsAvgPer10Min: + json["micro_missile_kills_avg_per_10_min"]?.toDouble(), + ); + + Map toJson() => { + "micro_missile_kills": microMissileKills, + "call_mech_kills": callMechKills, + "micro_missile_kills_most_in_game": microMissileKillsMostInGame, + "call_mech_kills_most_in_game": callMechKillsMostInGame, + "micro_missile_kills_avg_per_10_min": microMissileKillsAvgPer10Min, + }; +} + +class Genji { + final AsheAssists? assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final GenjiHeroSpecific heroSpecific; + + Genji({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Genji.fromJson(Map json) => Genji( + assists: json['assists'] == null ? null : AsheAssists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: GenjiHeroSpecific.fromJson(json["hero_specific"]), + ); + + Map toJson() => { + "assists": assists?.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": heroSpecific.toJson(), + }; +} + +class GenjiHeroSpecific { + final int dragonbladeKills; + final int dragonbladeKillsMostInGame; + final int damageReflected; + final int damageReflectedMostInGame; + final int swiftStrikeResets; + final int swiftStrikeResetsMostInGame; + final double dragonbladeKillsAvgPer10Min; + final int damageReflectedAvgPer10Min; + + GenjiHeroSpecific({ + required this.dragonbladeKills, + required this.dragonbladeKillsMostInGame, + required this.damageReflected, + required this.damageReflectedMostInGame, + required this.swiftStrikeResets, + required this.swiftStrikeResetsMostInGame, + required this.dragonbladeKillsAvgPer10Min, + required this.damageReflectedAvgPer10Min, + }); + + factory GenjiHeroSpecific.fromJson(Map json) => + GenjiHeroSpecific( + dragonbladeKills: json["dragonblade_kills"], + dragonbladeKillsMostInGame: json["dragonblade_kills_most_in_game"], + damageReflected: json["damage_reflected"], + damageReflectedMostInGame: json["damage_reflected_most_in_game"], + swiftStrikeResets: json["swift_strike_resets"], + swiftStrikeResetsMostInGame: json["swift_strike_resets_most_in_game"], + dragonbladeKillsAvgPer10Min: + json["dragonblade_kills_avg_per_10_min"]?.toDouble(), + damageReflectedAvgPer10Min: json["damage_reflected_avg_per_10_min"], + ); + + Map toJson() => { + "dragonblade_kills": dragonbladeKills, + "dragonblade_kills_most_in_game": dragonbladeKillsMostInGame, + "damage_reflected": damageReflected, + "damage_reflected_most_in_game": damageReflectedMostInGame, + "swift_strike_resets": swiftStrikeResets, + "swift_strike_resets_most_in_game": swiftStrikeResetsMostInGame, + "dragonblade_kills_avg_per_10_min": dragonbladeKillsAvgPer10Min, + "damage_reflected_avg_per_10_min": damageReflectedAvgPer10Min, + }; +} + +class Hanzo { + final HanzoAssists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final HanzoHeroSpecific heroSpecific; + + Hanzo({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Hanzo.fromJson(Map json) => Hanzo( + assists: HanzoAssists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: HanzoHeroSpecific.fromJson(json["hero_specific"]), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": heroSpecific.toJson(), + }; +} + +class HanzoAssists { + final int reconAssists; + final int reconAssistsMostInGame; + final int assists; + final double reconAssistsAvgPer10Min; + + HanzoAssists({ + required this.reconAssists, + required this.reconAssistsMostInGame, + required this.assists, + required this.reconAssistsAvgPer10Min, + }); + + factory HanzoAssists.fromJson(Map json) => HanzoAssists( + reconAssists: json["recon_assists"], + reconAssistsMostInGame: json["recon_assists_most_in_game"], + assists: json["assists"], + reconAssistsAvgPer10Min: + json["recon_assists_avg_per_10_min"]?.toDouble(), + ); + + Map toJson() => { + "recon_assists": reconAssists, + "recon_assists_most_in_game": reconAssistsMostInGame, + "assists": assists, + "recon_assists_avg_per_10_min": reconAssistsAvgPer10Min, + }; +} + +class HanzoHeroSpecific { + final int dragonstrikeKills; + final int dragonstrikeKillsMostInGame; + final int stormArrowKills; + final int stormArrowKillsMostInGame; + final int longRangeFinalBlows; + final int longRangeFinalBlowsMostInGame; + final double longRangeFinalBlowsAvgPer10Min; + final double dragonstrikeKillsAvgPer10Min; + final double stormArrowKillsAvgPer10Min; + + HanzoHeroSpecific({ + required this.dragonstrikeKills, + required this.dragonstrikeKillsMostInGame, + required this.stormArrowKills, + required this.stormArrowKillsMostInGame, + required this.longRangeFinalBlows, + required this.longRangeFinalBlowsMostInGame, + required this.longRangeFinalBlowsAvgPer10Min, + required this.dragonstrikeKillsAvgPer10Min, + required this.stormArrowKillsAvgPer10Min, + }); + + factory HanzoHeroSpecific.fromJson(Map json) => + HanzoHeroSpecific( + dragonstrikeKills: json["dragonstrike_kills"], + dragonstrikeKillsMostInGame: json["dragonstrike_kills_most_in_game"], + stormArrowKills: json["storm_arrow_kills"], + stormArrowKillsMostInGame: json["storm_arrow_kills_most_in_game"], + longRangeFinalBlows: json["long_range_final_blows"], + longRangeFinalBlowsMostInGame: + json["long_range_final_blows_most_in_game"], + longRangeFinalBlowsAvgPer10Min: + json["long_range_final_blows_avg_per_10_min"]?.toDouble(), + dragonstrikeKillsAvgPer10Min: + json["dragonstrike_kills_avg_per_10_min"]?.toDouble(), + stormArrowKillsAvgPer10Min: + json["storm_arrow_kills_avg_per_10_min"]?.toDouble(), + ); + + Map toJson() => { + "dragonstrike_kills": dragonstrikeKills, + "dragonstrike_kills_most_in_game": dragonstrikeKillsMostInGame, + "storm_arrow_kills": stormArrowKills, + "storm_arrow_kills_most_in_game": stormArrowKillsMostInGame, + "long_range_final_blows": longRangeFinalBlows, + "long_range_final_blows_most_in_game": longRangeFinalBlowsMostInGame, + "long_range_final_blows_avg_per_10_min": longRangeFinalBlowsAvgPer10Min, + "dragonstrike_kills_avg_per_10_min": dragonstrikeKillsAvgPer10Min, + "storm_arrow_kills_avg_per_10_min": stormArrowKillsAvgPer10Min, + }; +} + +class Illari { + final IllariAssists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final Map heroSpecific; + + Illari({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Illari.fromJson(Map json) => Illari( + assists: IllariAssists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: Map.from(json["hero_specific"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": Map.from(heroSpecific) + .map((k, v) => MapEntry(k, v)), + }; +} + +class IllariAssists { + final int offensiveAssists; + final int offensiveAssistsMostInGame; + final int healingDone; + final int healingDoneMostInGame; + final int assists; + final double offensiveAssistsAvgPer10Min; + + IllariAssists({ + required this.offensiveAssists, + required this.offensiveAssistsMostInGame, + required this.healingDone, + required this.healingDoneMostInGame, + required this.assists, + required this.offensiveAssistsAvgPer10Min, + }); + + factory IllariAssists.fromJson(Map json) => IllariAssists( + offensiveAssists: json["offensive_assists"], + offensiveAssistsMostInGame: json["offensive_assists_most_in_game"], + healingDone: json["healing_done"], + healingDoneMostInGame: json["healing_done_most_in_game"], + assists: json["assists"], + offensiveAssistsAvgPer10Min: + json["offensive_assists_avg_per_10_min"]?.toDouble(), + ); + + Map toJson() => { + "offensive_assists": offensiveAssists, + "offensive_assists_most_in_game": offensiveAssistsMostInGame, + "healing_done": healingDone, + "healing_done_most_in_game": healingDoneMostInGame, + "assists": assists, + "offensive_assists_avg_per_10_min": offensiveAssistsAvgPer10Min, + }; +} + +class Junkrat { + final JunkratAssists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final Map heroSpecific; + + Junkrat({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Junkrat.fromJson(Map json) => Junkrat( + assists: JunkratAssists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: Map.from(json["hero_specific"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": Map.from(heroSpecific) + .map((k, v) => MapEntry(k, v)), + }; +} + +class JunkratAssists { + final int offensiveAssists; + final int? offensiveAssistsMostInGame; + final int assists; + final double offensiveAssistsAvgPer10Min; + + JunkratAssists({ + required this.offensiveAssists, + this.offensiveAssistsMostInGame, + required this.assists, + required this.offensiveAssistsAvgPer10Min, + }); + + factory JunkratAssists.fromJson(Map json) => JunkratAssists( + offensiveAssists: json["offensive_assists"], + offensiveAssistsMostInGame: json["offensive_assists_most_in_game"], + assists: json["assists"], + offensiveAssistsAvgPer10Min: + json["offensive_assists_avg_per_10_min"]?.toDouble(), + ); + + Map toJson() => { + "offensive_assists": offensiveAssists, + "offensive_assists_most_in_game": offensiveAssistsMostInGame, + "assists": assists, + "offensive_assists_avg_per_10_min": offensiveAssistsAvgPer10Min, + }; +} + +class Kiriko { + final Assists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final KirikoHeroSpecific heroSpecific; + + Kiriko({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Kiriko.fromJson(Map json) => Kiriko( + assists: Assists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: KirikoHeroSpecific.fromJson(json["hero_specific"]), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": heroSpecific.toJson(), + }; +} + +class KirikoHeroSpecific { + final int negativeEffectsCleansedMostInGame; + final int kitsuneRushAssists; + final int kitsuneRushAssistsMostInGame; + final int kunaiKills; + final int kunaiKillsMostInGame; + final double kunaiKillsAvgPer10Min; + final double negativeEffectsCleansedAvgPer10Min; + final double kitsuneRushAssistsAvgPer10Min; + + KirikoHeroSpecific({ + required this.negativeEffectsCleansedMostInGame, + required this.kitsuneRushAssists, + required this.kitsuneRushAssistsMostInGame, + required this.kunaiKills, + required this.kunaiKillsMostInGame, + required this.kunaiKillsAvgPer10Min, + required this.negativeEffectsCleansedAvgPer10Min, + required this.kitsuneRushAssistsAvgPer10Min, + }); + + factory KirikoHeroSpecific.fromJson(Map json) => + KirikoHeroSpecific( + negativeEffectsCleansedMostInGame: + json["negative_effects_cleansed_most_in_game"], + kitsuneRushAssists: json["kitsune_rush_assists"], + kitsuneRushAssistsMostInGame: json["kitsune_rush_assists_most_in_game"], + kunaiKills: json["kunai_kills"], + kunaiKillsMostInGame: json["kunai_kills_most_in_game"], + kunaiKillsAvgPer10Min: json["kunai_kills_avg_per_10_min"]?.toDouble(), + negativeEffectsCleansedAvgPer10Min: + json["negative_effects_cleansed_avg_per_10_min"]?.toDouble(), + kitsuneRushAssistsAvgPer10Min: + json["kitsune_rush_assists_avg_per_10_min"]?.toDouble(), + ); + + Map toJson() => { + "negative_effects_cleansed_most_in_game": + negativeEffectsCleansedMostInGame, + "kitsune_rush_assists": kitsuneRushAssists, + "kitsune_rush_assists_most_in_game": kitsuneRushAssistsMostInGame, + "kunai_kills": kunaiKills, + "kunai_kills_most_in_game": kunaiKillsMostInGame, + "kunai_kills_avg_per_10_min": kunaiKillsAvgPer10Min, + "negative_effects_cleansed_avg_per_10_min": + negativeEffectsCleansedAvgPer10Min, + "kitsune_rush_assists_avg_per_10_min": kitsuneRushAssistsAvgPer10Min, + }; +} + +class Lifeweaver { + final Assists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final LifeweaverHeroSpecific heroSpecific; + + Lifeweaver({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Lifeweaver.fromJson(Map json) => Lifeweaver( + assists: Assists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: LifeweaverHeroSpecific.fromJson(json["hero_specific"]), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": heroSpecific.toJson(), + }; +} + +class LifeweaverHeroSpecific { + final int selfHealing; + final int selfHealingMostInGame; + final int lifeGripDeathsPrevented; + final int lifeGripDeathsPreventedMostInGame; + final int thornVolleyKills; + final int thornVolleyKillsMostInGame; + final int selfHealingAvgPer10Min; + final double lifeGripDeathsPreventedAvgPer10Min; + final double thornVolleyKillsAvgPer10Min; + + LifeweaverHeroSpecific({ + required this.selfHealing, + required this.selfHealingMostInGame, + required this.lifeGripDeathsPrevented, + required this.lifeGripDeathsPreventedMostInGame, + required this.thornVolleyKills, + required this.thornVolleyKillsMostInGame, + required this.selfHealingAvgPer10Min, + required this.lifeGripDeathsPreventedAvgPer10Min, + required this.thornVolleyKillsAvgPer10Min, + }); + + factory LifeweaverHeroSpecific.fromJson(Map json) => + LifeweaverHeroSpecific( + selfHealing: json["self_healing"], + selfHealingMostInGame: json["self_healing_most_in_game"], + lifeGripDeathsPrevented: json["life_grip_deaths_prevented"], + lifeGripDeathsPreventedMostInGame: + json["life_grip_deaths_prevented_most_in_game"], + thornVolleyKills: json["thorn_volley_kills"], + thornVolleyKillsMostInGame: json["thorn_volley_kills_most_in_game"], + selfHealingAvgPer10Min: json["self_healing_avg_per_10_min"], + lifeGripDeathsPreventedAvgPer10Min: + json["life_grip_deaths_prevented_avg_per_10_min"]?.toDouble(), + thornVolleyKillsAvgPer10Min: + json["thorn_volley_kills_avg_per_10_min"]?.toDouble(), + ); + + Map toJson() => { + "self_healing": selfHealing, + "self_healing_most_in_game": selfHealingMostInGame, + "life_grip_deaths_prevented": lifeGripDeathsPrevented, + "life_grip_deaths_prevented_most_in_game": + lifeGripDeathsPreventedMostInGame, + "thorn_volley_kills": thornVolleyKills, + "thorn_volley_kills_most_in_game": thornVolleyKillsMostInGame, + "self_healing_avg_per_10_min": selfHealingAvgPer10Min, + "life_grip_deaths_prevented_avg_per_10_min": + lifeGripDeathsPreventedAvgPer10Min, + "thorn_volley_kills_avg_per_10_min": thornVolleyKillsAvgPer10Min, + }; +} + +class Lucio { + final Assists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final LucioHeroSpecific heroSpecific; + + Lucio({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Lucio.fromJson(Map json) => Lucio( + assists: Assists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: LucioHeroSpecific.fromJson(json["hero_specific"]), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": heroSpecific.toJson(), + }; +} + +class LucioHeroSpecific { + final int soundBarriersProvided; + final int soundBarriersProvidedMostInGame; + final int selfHealing; + final int selfHealingMostInGame; + final int playersKnockedBackMostInGame; + final int selfHealingAvgPer10Min; + final double playersKnockedBackAvgPer10Min; + final double soundBarriersProvidedAvgPer10Min; + + LucioHeroSpecific({ + required this.soundBarriersProvided, + required this.soundBarriersProvidedMostInGame, + required this.selfHealing, + required this.selfHealingMostInGame, + required this.playersKnockedBackMostInGame, + required this.selfHealingAvgPer10Min, + required this.playersKnockedBackAvgPer10Min, + required this.soundBarriersProvidedAvgPer10Min, + }); + + factory LucioHeroSpecific.fromJson(Map json) => + LucioHeroSpecific( + soundBarriersProvided: json["sound_barriers_provided"], + soundBarriersProvidedMostInGame: + json["sound_barriers_provided_most_in_game"], + selfHealing: json["self_healing"], + selfHealingMostInGame: json["self_healing_most_in_game"], + playersKnockedBackMostInGame: json["players_knocked_back_most_in_game"], + selfHealingAvgPer10Min: json["self_healing_avg_per_10_min"], + playersKnockedBackAvgPer10Min: + json["players_knocked_back_avg_per_10_min"]?.toDouble(), + soundBarriersProvidedAvgPer10Min: + json["sound_barriers_provided_avg_per_10_min"]?.toDouble(), + ); + + Map toJson() => { + "sound_barriers_provided": soundBarriersProvided, + "sound_barriers_provided_most_in_game": soundBarriersProvidedMostInGame, + "self_healing": selfHealing, + "self_healing_most_in_game": selfHealingMostInGame, + "players_knocked_back_most_in_game": playersKnockedBackMostInGame, + "self_healing_avg_per_10_min": selfHealingAvgPer10Min, + "players_knocked_back_avg_per_10_min": playersKnockedBackAvgPer10Min, + "sound_barriers_provided_avg_per_10_min": + soundBarriersProvidedAvgPer10Min, + }; +} + +class Mauga { + final Assists assists; + final Map average; + final Map best; + final Map combat; + final DvaGame game; + final Map heroSpecific; + + Mauga({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Mauga.fromJson(Map json) => Mauga( + assists: Assists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: DvaGame.fromJson(json["game"]), + heroSpecific: Map.from(json["hero_specific"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": Map.from(heroSpecific) + .map((k, v) => MapEntry(k, v)), + }; +} + +class Mercy { + final Assists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final Map heroSpecific; + + Mercy({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Mercy.fromJson(Map json) => Mercy( + assists: Assists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: Map.from(json["hero_specific"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": Map.from(heroSpecific) + .map((k, v) => MapEntry(k, v)), + }; +} + +class Orisa { + final JunkratAssists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final OrisaHeroSpecific heroSpecific; + + Orisa({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Orisa.fromJson(Map json) => Orisa( + assists: JunkratAssists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: OrisaHeroSpecific.fromJson(json["hero_specific"]), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": heroSpecific.toJson(), + }; +} + +class OrisaHeroSpecific { + final int terraSurgeKills; + final int terraSurgeKillsMostInGame; + final int energyJavelinKills; + final int javelinSpinKills; + final int energyJavelinKillsNyi; + final int javelinSpinKillsNyi; + final double terraSurgeKillsAvgPer10Min; + final int javelinSpinKillsAvgPer10Min; + final double energyJavelinKillsAvgPer10Min; + + OrisaHeroSpecific({ + required this.terraSurgeKills, + required this.terraSurgeKillsMostInGame, + required this.energyJavelinKills, + required this.javelinSpinKills, + required this.energyJavelinKillsNyi, + required this.javelinSpinKillsNyi, + required this.terraSurgeKillsAvgPer10Min, + required this.javelinSpinKillsAvgPer10Min, + required this.energyJavelinKillsAvgPer10Min, + }); + + factory OrisaHeroSpecific.fromJson(Map json) => + OrisaHeroSpecific( + terraSurgeKills: json["terra_surge_kills"], + terraSurgeKillsMostInGame: json["terra_surge_kills_most_in_game"], + energyJavelinKills: json["energy_javelin_kills"], + javelinSpinKills: json["javelin_spin_kills"], + energyJavelinKillsNyi: json["energy_javelin_kills_nyi"], + javelinSpinKillsNyi: json["javelin_spin_kills_nyi"], + terraSurgeKillsAvgPer10Min: + json["terra_surge_kills_avg_per_10_min"]?.toDouble(), + javelinSpinKillsAvgPer10Min: json["javelin_spin_kills_avg_per_10_min"], + energyJavelinKillsAvgPer10Min: + json["energy_javelin_kills_avg_per_10_min"]?.toDouble(), + ); + + Map toJson() => { + "terra_surge_kills": terraSurgeKills, + "terra_surge_kills_most_in_game": terraSurgeKillsMostInGame, + "energy_javelin_kills": energyJavelinKills, + "javelin_spin_kills": javelinSpinKills, + "energy_javelin_kills_nyi": energyJavelinKillsNyi, + "javelin_spin_kills_nyi": javelinSpinKillsNyi, + "terra_surge_kills_avg_per_10_min": terraSurgeKillsAvgPer10Min, + "javelin_spin_kills_avg_per_10_min": javelinSpinKillsAvgPer10Min, + "energy_javelin_kills_avg_per_10_min": energyJavelinKillsAvgPer10Min, + }; +} + +class Pharah { + final AsheAssists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final PharahHeroSpecific heroSpecific; + + Pharah({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Pharah.fromJson(Map json) => Pharah( + assists: AsheAssists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: PharahHeroSpecific.fromJson(json["hero_specific"]), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": heroSpecific.toJson(), + }; +} + +class PharahHeroSpecific { + final int rocketDirectHits; + final int rocketDirectHitsMostInGame; + final double rocketDirectHitsAvgPer10Min; + final int airtimePercentage; + final int directHitAccuracy; + + PharahHeroSpecific({ + required this.rocketDirectHits, + required this.rocketDirectHitsMostInGame, + required this.rocketDirectHitsAvgPer10Min, + required this.airtimePercentage, + required this.directHitAccuracy, + }); + + factory PharahHeroSpecific.fromJson(Map json) => + PharahHeroSpecific( + rocketDirectHits: json["rocket_direct_hits"], + rocketDirectHitsMostInGame: json["rocket_direct_hits_most_in_game"], + rocketDirectHitsAvgPer10Min: + json["rocket_direct_hits_avg_per_10_min"]?.toDouble(), + airtimePercentage: json["airtime_percentage"], + directHitAccuracy: json["direct_hit_accuracy"], + ); + + Map toJson() => { + "rocket_direct_hits": rocketDirectHits, + "rocket_direct_hits_most_in_game": rocketDirectHitsMostInGame, + "rocket_direct_hits_avg_per_10_min": rocketDirectHitsAvgPer10Min, + "airtime_percentage": airtimePercentage, + "direct_hit_accuracy": directHitAccuracy, + }; +} + +class Reaper { + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final ReaperHeroSpecific heroSpecific; + + Reaper({ + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Reaper.fromJson(Map json) => Reaper( + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: ReaperHeroSpecific.fromJson(json["hero_specific"]), + ); + + Map toJson() => { + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": heroSpecific.toJson(), + }; +} + +class ReaperHeroSpecific { + final int deathBlossomKills; + final int deathBlossomKillsMostInGame; + final int selfHealing; + final int selfHealingMostInGame; + final int selfHealingAvgPer10Min; + final double deathBlossomKillsAvgPer10Min; + + ReaperHeroSpecific({ + required this.deathBlossomKills, + required this.deathBlossomKillsMostInGame, + required this.selfHealing, + required this.selfHealingMostInGame, + required this.selfHealingAvgPer10Min, + required this.deathBlossomKillsAvgPer10Min, + }); + + factory ReaperHeroSpecific.fromJson(Map json) => + ReaperHeroSpecific( + deathBlossomKills: json["death_blossom_kills"], + deathBlossomKillsMostInGame: json["death_blossom_kills_most_in_game"], + selfHealing: json["self_healing"], + selfHealingMostInGame: json["self_healing_most_in_game"], + selfHealingAvgPer10Min: json["self_healing_avg_per_10_min"], + deathBlossomKillsAvgPer10Min: + json["death_blossom_kills_avg_per_10_min"]?.toDouble(), + ); + + Map toJson() => { + "death_blossom_kills": deathBlossomKills, + "death_blossom_kills_most_in_game": deathBlossomKillsMostInGame, + "self_healing": selfHealing, + "self_healing_most_in_game": selfHealingMostInGame, + "self_healing_avg_per_10_min": selfHealingAvgPer10Min, + "death_blossom_kills_avg_per_10_min": deathBlossomKillsAvgPer10Min, + }; +} + +class Reinhardt { + final JunkratAssists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final Map heroSpecific; + final MatchAwards? matchAwards; + + Reinhardt({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + this.matchAwards, + }); + + factory Reinhardt.fromJson(Map json) => Reinhardt( + assists: JunkratAssists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: Map.from(json["hero_specific"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + matchAwards: json['match_awards'] == null ? null : MatchAwards.fromJson(json["match_awards"]), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": Map.from(heroSpecific) + .map((k, v) => MapEntry(k, v)), + "match_awards": matchAwards?.toJson(), + }; +} + +class Sigma { + final JunkratAssists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final SigmaHeroSpecific heroSpecific; + + Sigma({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Sigma.fromJson(Map json) => Sigma( + assists: JunkratAssists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: SigmaHeroSpecific.fromJson(json["hero_specific"]), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": heroSpecific.toJson(), + }; +} + +class SigmaHeroSpecific { + final int accretionKillsMostInGame; + final int accretionKills; + final int graviticFluxKills; + final int graviticFluxKillsMostInGame; + final int overhealthCreated; + final int overhealthCreatedMostInGame; + final double accretionKillsAvgPer10Min; + final int overhealthCreatedAvgPer10Min; + final double graviticFluxKillsAvgPer10Min; + + SigmaHeroSpecific({ + required this.accretionKillsMostInGame, + required this.accretionKills, + required this.graviticFluxKills, + required this.graviticFluxKillsMostInGame, + required this.overhealthCreated, + required this.overhealthCreatedMostInGame, + required this.accretionKillsAvgPer10Min, + required this.overhealthCreatedAvgPer10Min, + required this.graviticFluxKillsAvgPer10Min, + }); + + factory SigmaHeroSpecific.fromJson(Map json) => + SigmaHeroSpecific( + accretionKillsMostInGame: json["accretion_kills_most_in_game"], + accretionKills: json["accretion_kills"], + graviticFluxKills: json["gravitic_flux_kills"], + graviticFluxKillsMostInGame: json["gravitic_flux_kills_most_in_game"], + overhealthCreated: json["overhealth_created"], + overhealthCreatedMostInGame: json["overhealth_created_most_in_game"], + accretionKillsAvgPer10Min: + json["accretion_kills_avg_per_10_min"]?.toDouble(), + overhealthCreatedAvgPer10Min: json["overhealth_created_avg_per_10_min"], + graviticFluxKillsAvgPer10Min: + json["gravitic_flux_kills_avg_per_10_min"]?.toDouble(), + ); + + Map toJson() => { + "accretion_kills_most_in_game": accretionKillsMostInGame, + "accretion_kills": accretionKills, + "gravitic_flux_kills": graviticFluxKills, + "gravitic_flux_kills_most_in_game": graviticFluxKillsMostInGame, + "overhealth_created": overhealthCreated, + "overhealth_created_most_in_game": overhealthCreatedMostInGame, + "accretion_kills_avg_per_10_min": accretionKillsAvgPer10Min, + "overhealth_created_avg_per_10_min": overhealthCreatedAvgPer10Min, + "gravitic_flux_kills_avg_per_10_min": graviticFluxKillsAvgPer10Min, + }; +} + +class Tracer { + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final Map heroSpecific; + + Tracer({ + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Tracer.fromJson(Map json) => Tracer( + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: Map.from(json["hero_specific"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + ); + + Map toJson() => { + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": Map.from(heroSpecific) + .map((k, v) => MapEntry(k, v)), + }; +} + +class Widowmaker { + final HanzoAssists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final Map heroSpecific; + + Widowmaker({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory Widowmaker.fromJson(Map json) => Widowmaker( + assists: HanzoAssists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: Map.from(json["hero_specific"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": Map.from(heroSpecific) + .map((k, v) => MapEntry(k, v)), + }; +} + +class WreckingBall { + final AsheAssists assists; + final Map average; + final Map best; + final Map combat; + final AllHeroesGame game; + final WreckingBallHeroSpecific heroSpecific; + + WreckingBall({ + required this.assists, + required this.average, + required this.best, + required this.combat, + required this.game, + required this.heroSpecific, + }); + + factory WreckingBall.fromJson(Map json) => WreckingBall( + assists: AsheAssists.fromJson(json["assists"]), + average: Map.from(json["average"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + best: Map.from(json["best"]).map((k, v) => MapEntry(k, v)), + combat: Map.from(json["combat"]) + .map((k, v) => MapEntry(k, v?.toDouble())), + game: AllHeroesGame.fromJson(json["game"]), + heroSpecific: WreckingBallHeroSpecific.fromJson(json["hero_specific"]), + ); + + Map toJson() => { + "assists": assists.toJson(), + "average": + Map.from(average).map((k, v) => MapEntry(k, v)), + "best": Map.from(best).map((k, v) => MapEntry(k, v)), + "combat": + Map.from(combat).map((k, v) => MapEntry(k, v)), + "game": game.toJson(), + "hero_specific": heroSpecific.toJson(), + }; +} + +class WreckingBallHeroSpecific { + final int piledriverKills; + final int grapplingClawKills; + final int minefieldKills; + final int grapplingClawKillsMostInGame; + final int minefieldKillsMostInGame; + final int piledriverKillsMostInGame; + final double piledriverKillsAvgPer10Min; + final double grapplingClawKillsAvgPer10Min; + final double minefieldKillsAvgPer10Min; + + WreckingBallHeroSpecific({ + required this.piledriverKills, + required this.grapplingClawKills, + required this.minefieldKills, + required this.grapplingClawKillsMostInGame, + required this.minefieldKillsMostInGame, + required this.piledriverKillsMostInGame, + required this.piledriverKillsAvgPer10Min, + required this.grapplingClawKillsAvgPer10Min, + required this.minefieldKillsAvgPer10Min, + }); + + factory WreckingBallHeroSpecific.fromJson(Map json) => + WreckingBallHeroSpecific( + piledriverKills: json["piledriver_kills"], + grapplingClawKills: json["grappling_claw_kills"], + minefieldKills: json["minefield_kills"], + grapplingClawKillsMostInGame: json["grappling_claw_kills_most_in_game"], + minefieldKillsMostInGame: json["minefield_kills_most_in_game"], + piledriverKillsMostInGame: json["piledriver_kills_most_in_game"], + piledriverKillsAvgPer10Min: + json["piledriver_kills_avg_per_10_min"]?.toDouble(), + grapplingClawKillsAvgPer10Min: + json["grappling_claw_kills_avg_per_10_min"]?.toDouble(), + minefieldKillsAvgPer10Min: + json["minefield_kills_avg_per_10_min"]?.toDouble(), + ); + + Map toJson() => { + "piledriver_kills": piledriverKills, + "grappling_claw_kills": grapplingClawKills, + "minefield_kills": minefieldKills, + "grappling_claw_kills_most_in_game": grapplingClawKillsMostInGame, + "minefield_kills_most_in_game": minefieldKillsMostInGame, + "piledriver_kills_most_in_game": piledriverKillsMostInGame, + "piledriver_kills_avg_per_10_min": piledriverKillsAvgPer10Min, + "grappling_claw_kills_avg_per_10_min": grapplingClawKillsAvgPer10Min, + "minefield_kills_avg_per_10_min": minefieldKillsAvgPer10Min, + }; +} diff --git a/lib/players/player.dart b/lib/players/player.dart new file mode 100644 index 0000000..38c987d --- /dev/null +++ b/lib/players/player.dart @@ -0,0 +1,314 @@ +import 'package:overfast_api/client.dart'; +import 'package:overfast_api/utils/types.dart'; + +class PlayerSummary { + final String username; + final String? avatar; + final String? namecard; + final String? title; + final PlayerEndorsement endorsement; + final PlatformCompetitiveRank? competitiveRank; + + const PlayerSummary({ + required this.username, + this.avatar, + this.namecard, + this.title, + required this.endorsement, + required this.competitiveRank, + }); + + factory PlayerSummary.fromJson(Map json) { + return PlayerSummary( + username: json['username'], + avatar: json['avatar'], + namecard: json['namecard'], + title: json['title'], + endorsement: PlayerEndorsement.fromJson(json['endorsement']), + competitiveRank: PlatformCompetitiveRank.fromJson(json['competitive']), + ); + } + + Map toJson() { + return { + 'username': username, + 'avatar': avatar, + 'namecard': namecard, + 'title': title, + 'endorsement': endorsement.toJson(), + 'competitiveRank': competitiveRank?.toJson(), + }; + } +} + +class PlayerEndorsement { + final int level; + final String frame; + + const PlayerEndorsement({ + required this.level, + required this.frame, + }); + + factory PlayerEndorsement.fromJson(Map json) { + return PlayerEndorsement( + level: json['level'], + frame: json['frame'], + ); + } + + Map toJson() { + return { + 'level': level, + 'frame': frame, + }; + } +} + +class PlatformCompetitiveRank { + final CompetitiveRank? pc; + final CompetitiveRank? console; + + const PlatformCompetitiveRank({ + this.pc, + this.console, + }); + + factory PlatformCompetitiveRank.fromJson(Map json) { + return PlatformCompetitiveRank( + pc: json['pc'] != null ? CompetitiveRank.fromJson(json['pc']) : null, + console: json['console'] != null + ? CompetitiveRank.fromJson(json['console']) + : null, + ); + } + + Map toJson() { + return { + 'pc': pc?.toJson(), + 'console': console?.toJson(), + }; + } +} + +class CompetitiveRank { + final int season; + final RoleDetails? tank; + final RoleDetails? damage; + final RoleDetails? support; + final RoleDetails? openQueue; + + const CompetitiveRank({ + required this.season, + required this.tank, + required this.damage, + required this.support, + required this.openQueue, + }); + + factory CompetitiveRank.fromJson(Map json) { + return CompetitiveRank( + season: json['season'], + tank: json['tank'] == null ? null : RoleDetails.fromJson(json['tank']), + damage: + json['damage'] == null ? null : RoleDetails.fromJson(json['damage']), + support: json['support'] == null + ? null + : RoleDetails.fromJson(json['support']), + openQueue: + json['open'] == null ? null : RoleDetails.fromJson(json['open']), + ); + } + + Map toJson() { + return { + 'season': season, + 'tank': tank?.toJson(), + 'damage': damage?.toJson(), + 'support': support?.toJson(), + }; + } +} + +class RoleDetails { + final String division; + final int tier; + final String roleIcon; + final String rankIcon; + final String tierIcon; + + const RoleDetails({ + required this.division, + required this.tier, + required this.roleIcon, + required this.rankIcon, + required this.tierIcon, + }); + + factory RoleDetails.fromJson(Map json) { + return RoleDetails( + division: json['division'], + tier: json['tier'], + roleIcon: json['role_icon'], + rankIcon: json['rank_icon'], + tierIcon: json['tier_icon'], + ); + } + + Map toJson() { + return { + 'division': division, + 'tier': tier, + 'roleIcon': roleIcon, + 'rankIcon': rankIcon, + 'tierIcon': tierIcon, + }; + } +} + +class StatsSummary { + final StatsRecap general; + final Map heroes; + final Map roles; + + const StatsSummary({ + required this.general, + required this.heroes, + required this.roles, + }); + + factory StatsSummary.fromJson(Map json) { + return StatsSummary( + general: StatsRecap.fromJson(json['general']), + heroes: Map.from(json['heroes']).map( + (key, value) => MapEntry(key, StatsRecap.fromJson(value)), + ), + roles: Map.from(json['roles']).map( + (key, value) => MapEntry(key, StatsRecap.fromJson(value)), + ), + ); + } + + Map toJson() { + return { + 'general': general.toJson(), + 'heroes': heroes.map((key, value) => MapEntry(key, value.toJson())), + 'roles': roles.map((key, value) => MapEntry(key, value.toJson())), + }; + } +} + +class StatsRecap { + final int gamesPlayed; + final int gamesWon; + final int gamesLost; + final Duration timePlayed; + final double winrate; + final double kda; + final SubStatsRecap total; + final SubStatsRecap average; + + const StatsRecap({ + required this.gamesPlayed, + required this.gamesWon, + required this.gamesLost, + required this.timePlayed, + required this.winrate, + required this.kda, + required this.total, + required this.average, + }); + + factory StatsRecap.fromJson(Map json) { + return StatsRecap( + gamesPlayed: json['games_played'], + gamesWon: json['games_won'], + gamesLost: json['games_lost'], + timePlayed: Duration(seconds: json['time_played']), + winrate: json['winrate'], + kda: json['kda'], + total: SubStatsRecap.fromJson(json['total']), + average: SubStatsRecap.fromJson(json['average']), + ); + } + + Map toJson() { + return { + 'games_played': gamesPlayed, + 'games_won': gamesWon, + 'games_lost': gamesLost, + 'time_played': timePlayed.inSeconds, + 'winrate': winrate, + 'kda': kda, + 'total': total.toJson(), + 'average': average.toJson(), + }; + } +} + +class SubStatsRecap { + final num eliminations; + final num assists; + final num deaths; + final num damage; + final num healing; + + const SubStatsRecap({ + required this.eliminations, + required this.assists, + required this.deaths, + required this.damage, + required this.healing, + }); + + factory SubStatsRecap.fromJson(Map json) { + return SubStatsRecap( + eliminations: json['eliminations'], + assists: json['assists'], + deaths: json['deaths'], + damage: json['damage'], + healing: json['healing'], + ); + } + + Map toJson() { + return { + 'eliminations': eliminations, + 'assists': assists, + 'deaths': deaths, + 'damage': damage, + 'healing': healing, + }; + } +} + +class Player { + final String playerId; + + final Overfast _client; + + const Player(this._client, {required this.playerId}); + + // I.. don't know how to properly type this. + Future career({ + Platform? platform, + Gamemode gamemode = Gamemode.competitive, + HeroKey? hero = HeroKey.allHeroes, + }) { + return _client.get( + '/players/$playerId/stats/career', + { + if (platform != null) 'platform': platform.toString(), + 'gamemode': gamemode.name, + if (hero != null) 'hero': hero.toString(), + }, + ); + } + + Future summary() => + _client.get('/players/$playerId/summary'); + + Future statsSummary() => + _client.get('/players/$playerId/stats/summary'); + +} diff --git a/lib/players/players.dart b/lib/players/players.dart new file mode 100644 index 0000000..bd47b12 --- /dev/null +++ b/lib/players/players.dart @@ -0,0 +1,93 @@ +import 'package:overfast_api/client.dart'; +import 'package:overfast_api/players/player.dart'; + +class SearchResponse { + final int total; + final List results; + + const SearchResponse({ + required this.total, + required this.results, + }); + + factory SearchResponse.fromJson(Map json) { + return SearchResponse( + total: json['total'], + results: (json['results'] as List) + .map((e) => SearchResult.fromJson(e)) + .toList(), + ); + } + + Map toJson() { + return { + 'total': total, + 'results': results.map((e) => e.toJson()).toList(), + }; + } +} + +class SearchResult { + final String playerId; + final String name; + final String? avatar; + final String? namecard; + final String? title; + final String careerUrl; + final String blizzardId; + + const SearchResult({ + required this.playerId, + required this.name, + this.avatar, + this.namecard, + this.title, + required this.careerUrl, + required this.blizzardId, + }); + + factory SearchResult.fromJson(Map json) { + return SearchResult( + playerId: json['player_id'], + name: json['name'], + avatar: json['avatar'], + namecard: json['namecard'], + title: json['title'], + careerUrl: json['career_url'], + blizzardId: json['blizzard_id'], + ); + } + + Map toJson() { + return { + 'playerId': playerId, + 'name': name, + 'avatar': avatar, + 'namecard': namecard, + 'title': title, + 'careerUrl': careerUrl, + 'blizzardId': blizzardId, + }; + } +} + +class Players { + final Overfast _client; + const Players(this._client); + + Future search( + String query, { + String orderBy = 'name:desc', + int? offset, + int? limit, + }) async { + return _client.get('/players', { + 'name': query, + 'orderBy': orderBy, + if (offset != null) 'offset': offset.toString(), + if (limit != null) 'limit': limit.toString(), + }); + } + + Player player(String playerId) => Player(_client, playerId: playerId); +} diff --git a/lib/utils/get.dart b/lib/utils/get.dart new file mode 100644 index 0000000..e66f172 --- /dev/null +++ b/lib/utils/get.dart @@ -0,0 +1,76 @@ +import 'dart:convert'; + +import 'package:http/http.dart' as http; +import 'package:overfast_api/heroes/heroes_data.dart'; +import 'package:overfast_api/maps/maps.dart'; +import 'package:overfast_api/players/data_types.dart'; +import 'package:overfast_api/players/player.dart'; +import 'package:overfast_api/players/players.dart'; +// import 'package:overfast_api/players/data_types.dart'; + +final fromJsonMap = )>{ + GameMap: GameMap.fromJson, + Map: (json) => json, + PlayerSummary: PlayerSummary.fromJson, + SearchResponse: SearchResponse.fromJson, + CareerProfile: CareerProfile.fromJson, + Hero: Hero.fromJson, + HeroDetails: HeroDetails.fromJson, + Roles: Roles.fromJson, + StatsSummary: StatsSummary.fromJson, +}; + +Future Function(String, [Map]) get( + http.Client client, + Uri baseUri, +) { + return ( + String path, [ + Map params = const {}, + ]) async { + final uri = baseUri.replace(path: path, queryParameters: params); + final response = await client.get(uri); + + throwIfNecessary(response.statusCode, response.body); + + return fromJsonMap[T]!(json.decode(response.body)); + }; +} + +Future> Function(String, [Map]) + getList( + http.Client client, + Uri baseUri, +) { + return ( + String path, [ + Map params = const {}, + ]) async { + final uri = baseUri.replace(path: path, queryParameters: params); + final response = await client.get(uri); + + throwIfNecessary(response.statusCode, response.body); + + return (json.decode(response.body) as List) + .map((e) => fromJsonMap[T]!(e)).cast() + .toList(); + }; +} + +void throwIfNecessary(int code, String body) { + if (code == 422) { + throw Exception('Invalid parameters\n${json.decode(body)['detail']}'); + } + + if (code == 500) { + throw Exception('Internal server error'); + } + + if (code == 504) { + throw Exception('Blizzard Server error'); + } + + if (code == 404) { + throw Exception('Not found\n${json.decode(body)['error']}'); + } +} diff --git a/lib/utils/types.dart b/lib/utils/types.dart new file mode 100644 index 0000000..3ebc3f9 --- /dev/null +++ b/lib/utils/types.dart @@ -0,0 +1,99 @@ +import 'utils.dart'; + +enum HeroKey { + allHeroes, + ana, + ashe, + baptiste, + bastion, + brigitte, + cassidy, + dva, + doomfist, + echo, + genji, + hanzo, + illari, + junkrat, + junkerqueen('junker-queen'), + kiriko, + lifeweaver, + lucio, + mauga, + mei, + mercy, + moira, + orisa, + pharah, + ramattra, + reaper, + reinhardt, + roadhog, + sigma, + sojourn, + soldier76('soldier-76'), + sombra, + symmetra, + torbjorn, + tracer, + widowmaker, + winston, + wreckingball('wrecking-ball'), + venture, + zarya, + zenyatta, + eemptyy; + + final String? _properName; + + const HeroKey([this._properName]); + + String get heroName => _properName ?? name; + + static HeroKey fromString(String value) { + return HeroKey.values.firstWhere((e) => e.name == value || e._properName == value); + } +} + +enum Locale { + deDe, + enGb, + enUs, + esEs, + esMx, + frFr, + itIt, + jaJp, + koKr, + plPl, + ptBr, + ruRu, + zhCn; + + @override + String toString() => toKebabCase(name); + + static Locale fromString(String value) { + return Locale.values.firstWhere((e) => e.name == value); + } +} + +enum Platform { + pc, + console, +} + +enum Gamemode { + quickplay, + competitive, +} + +enum Role { + tank, + damage, + support; + + static Role fromString(String value) { + return Role.values.firstWhere((e) => e.name == value); + } +} diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart new file mode 100644 index 0000000..3adc4c0 --- /dev/null +++ b/lib/utils/utils.dart @@ -0,0 +1,7 @@ +export './get.dart'; + +String toKebabCase(String text) { + return text.replaceAllMapped(RegExp(r'([A-Z])'), (match) { + return '-${match.group(1)?.toLowerCase()}'; + }); +} diff --git a/out.json b/out.json new file mode 100644 index 0000000..9445918 --- /dev/null +++ b/out.json @@ -0,0 +1,66 @@ +{ + "best": { + "eliminations_most_in_game": 56, + "final_blows_most_in_game": 32, + "all_damage_done_most_in_game": 27149, + "healing_done_most_in_game": 16982, + "defensive_assists_most_in_game": 34, + "offensive_assists_most_in_game": 21, + "objective_kills_most_in_game": 26, + "objective_time_most_in_game": 355, + "multikill_best": 4, + "solo_kills_most_in_game": 32, + "time_spent_on_fire_most_in_game": 98, + "melee_final_blows_most_in_game": 8, + "environmental_kills_most_in_game": 3, + "kill_streak_best": 22, + "hero_damage_done_most_in_game": 22881, + "barrier_damage_done_most_in_game": 7789, + "assists_most_in_game": 35, + "objective_contest_time_most_in_game": 216, + "recon_assists_most_in_game": 9 + }, + "average": { + "objective_kills_avg_per_10_min": 5.71, + "objective_time_avg_per_10_min": 77, + "final_blows_avg_per_10_min": 8.65, + "time_spent_on_fire_avg_per_10_min": 89, + "objective_contest_time_avg_per_10_min": 42, + "solo_kills_avg_per_10_min": 1.4, + "hero_damage_done_avg_per_10_min": 7948, + "deaths_avg_per_10_min": 6.45, + "eliminations_avg_per_10_min": 17.39, + "assists_avg_per_10_min": 4.69, + "healing_done_avg_per_10_min": 1160 + }, + "game": { + "time_played": 274097, + "games_played": 413, + "games_won": 219, + "games_tied": 2, + "games_lost": 192, + "hero_wins": 219 + }, + "combat": { + "environmental_kills": 63, + "deaths": 2948, + "objective_kills": 2608, + "final_blows": 3950, + "objective_time": 35000, + "melee_final_blows": 526, + "time_spent_on_fire": 40814, + "eliminations": 7946, + "objective_contest_time": 18984, + "solo_kills": 641, + "multikills": 59, + "hero_damage_done": 3631039, + "damage_done": 3631039 + }, + "assists": { + "recon_assists": 136, + "healing_done": 529954, + "defensive_assists": 651, + "offensive_assists": 377, + "assists": 2143 + } +} diff --git a/pubspec.lock b/pubspec.lock new file mode 100644 index 0000000..f75d756 --- /dev/null +++ b/pubspec.lock @@ -0,0 +1,389 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + _fe_analyzer_shared: + dependency: transitive + description: + name: _fe_analyzer_shared + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" + url: "https://pub.dev" + source: hosted + version: "67.0.0" + analyzer: + dependency: transitive + description: + name: analyzer + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" + url: "https://pub.dev" + source: hosted + version: "6.4.1" + args: + dependency: transitive + description: + name: args + sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + url: "https://pub.dev" + source: hosted + version: "2.4.2" + async: + dependency: transitive + description: + name: async + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" + url: "https://pub.dev" + source: hosted + version: "2.11.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + collection: + dependency: transitive + description: + name: collection + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + url: "https://pub.dev" + source: hosted + version: "1.18.0" + convert: + dependency: transitive + description: + name: convert + sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + url: "https://pub.dev" + source: hosted + version: "3.1.1" + coverage: + dependency: transitive + description: + name: coverage + sha256: "8acabb8306b57a409bf4c83522065672ee13179297a6bb0cb9ead73948df7c76" + url: "https://pub.dev" + source: hosted + version: "1.7.2" + crypto: + dependency: transitive + description: + name: crypto + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab + url: "https://pub.dev" + source: hosted + version: "3.0.3" + file: + dependency: transitive + description: + name: file + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 + url: "https://pub.dev" + source: hosted + version: "4.0.0" + glob: + dependency: transitive + description: + name: glob + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + http: + dependency: "direct main" + description: + name: http + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + http_multi_server: + dependency: transitive + description: + name: http_multi_server + sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + http_parser: + dependency: transitive + description: + name: http_parser + sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + url: "https://pub.dev" + source: hosted + version: "4.0.2" + io: + dependency: transitive + description: + name: io + sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + js: + dependency: transitive + description: + name: js + sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf + url: "https://pub.dev" + source: hosted + version: "0.7.1" + lints: + dependency: "direct dev" + description: + name: lints + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 + url: "https://pub.dev" + source: hosted + version: "3.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + url: "https://pub.dev" + source: hosted + version: "0.12.16+1" + meta: + dependency: transitive + description: + name: meta + sha256: "25dfcaf170a0190f47ca6355bdd4552cb8924b430512ff0cafb8db9bd41fe33b" + url: "https://pub.dev" + source: hosted + version: "1.14.0" + mime: + dependency: transitive + description: + name: mime + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + node_preamble: + dependency: transitive + description: + name: node_preamble + sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db" + url: "https://pub.dev" + source: hosted + version: "2.0.2" + package_config: + dependency: transitive + description: + name: package_config + sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + path: + dependency: transitive + description: + name: path + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + url: "https://pub.dev" + source: hosted + version: "1.9.0" + pool: + dependency: transitive + description: + name: pool + sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a" + url: "https://pub.dev" + source: hosted + version: "1.5.1" + pub_semver: + dependency: transitive + description: + name: pub_semver + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + shelf: + dependency: transitive + description: + name: shelf + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + url: "https://pub.dev" + source: hosted + version: "1.4.1" + shelf_packages_handler: + dependency: transitive + description: + name: shelf_packages_handler + sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e" + url: "https://pub.dev" + source: hosted + version: "3.0.2" + shelf_static: + dependency: transitive + description: + name: shelf_static + sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e + url: "https://pub.dev" + source: hosted + version: "1.1.2" + shelf_web_socket: + dependency: transitive + description: + name: shelf_web_socket + sha256: "9ca081be41c60190ebcb4766b2486a7d50261db7bd0f5d9615f2d653637a84c1" + url: "https://pub.dev" + source: hosted + version: "1.0.4" + source_map_stack_trace: + dependency: transitive + description: + name: source_map_stack_trace + sha256: "84cf769ad83aa6bb61e0aa5a18e53aea683395f196a6f39c4c881fb90ed4f7ae" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + source_maps: + dependency: transitive + description: + name: source_maps + sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703" + url: "https://pub.dev" + source: hosted + version: "0.10.12" + source_span: + dependency: transitive + description: + name: source_span + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" + url: "https://pub.dev" + source: hosted + version: "1.11.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 + url: "https://pub.dev" + source: hosted + version: "2.1.2" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" + url: "https://pub.dev" + source: hosted + version: "1.2.0" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + test: + dependency: "direct dev" + description: + name: test + sha256: d87214d19fb311997d8128ec501a980f77cb240ac4e7e219accf452813ff473c + url: "https://pub.dev" + source: hosted + version: "1.25.3" + test_api: + dependency: transitive + description: + name: test_api + sha256: "2419f20b0c8677b2d67c8ac4d1ac7372d862dc6c460cdbb052b40155408cd794" + url: "https://pub.dev" + source: hosted + version: "0.7.1" + test_core: + dependency: transitive + description: + name: test_core + sha256: "2236f70be1e5ab405c675e88c36935a87dad9e05a506b57dd5c0f617f5aebcb2" + url: "https://pub.dev" + source: hosted + version: "0.6.1" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c + url: "https://pub.dev" + source: hosted + version: "1.3.2" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: a75f83f14ad81d5fe4b3319710b90dec37da0e22612326b696c9e1b8f34bbf48 + url: "https://pub.dev" + source: hosted + version: "14.2.0" + watcher: + dependency: transitive + description: + name: watcher + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" + url: "https://pub.dev" + source: hosted + version: "2.4.5" + webkit_inspection_protocol: + dependency: transitive + description: + name: webkit_inspection_protocol + sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + yaml: + dependency: transitive + description: + name: yaml + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" + url: "https://pub.dev" + source: hosted + version: "3.1.2" +sdks: + dart: ">=3.3.1 <4.0.0" diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 0000000..631864c --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,13 @@ +name: overfast_api +description: A wrapper for the Overfast API. +version: 0.0.1 + +environment: + sdk: ^3.3.1 + +dependencies: + http: ^1.2.1 + +dev_dependencies: + lints: ^3.0.0 + test: ^1.24.0 diff --git a/test.ts b/test.ts new file mode 100644 index 0000000..96359b1 --- /dev/null +++ b/test.ts @@ -0,0 +1,47 @@ +type HEROES_KEYS = + | "ana" + | "ashe" + | "baptiste" + | "bastion" + | "brigitte" + | "cassidy" + | "dva" + | "doomfist" + | "echo" + | "genji" + | "hanzo" + | "junker-queen" + | "junkrat" + | "kiriko" + | "lucio" + | "mei" + | "mercy" + | "moira" + | "orisa" + | "pharah" + | "ramattra" + | "reaper" + | "reinhardt" + | "roadhog" + | "sigma" + | "sojourn" + | "soldier-76" + | "sombra" + | "symmetra" + | "torbjorn" + | "tracer" + | "widowmaker" + | "winston" + | "wrecking-ball" + | "zarya" + | "zenyatta"; + +type NEW_HEROES_KEYS = T extends HEROES_KEYS + ? HEROES_KEYS + : T | HEROES_KEYS; + +function fn(key: NEW_HEROES_KEYS) { + console.log(key); +} + +// fn('') \ No newline at end of file diff --git a/test/overfast_api_test.dart b/test/overfast_api_test.dart new file mode 100644 index 0000000..e69de29