diff --git a/lib/data_classes/players/index.dart b/lib/data_classes/players/index.dart index f7d16e0..681cb81 100644 --- a/lib/data_classes/players/index.dart +++ b/lib/data_classes/players/index.dart @@ -1 +1,2 @@ +export "./player_timed_stats.dart"; export "./players.dart"; diff --git a/lib/data_classes/players/player_timed_stats.dart b/lib/data_classes/players/player_timed_stats.dart index 81e4749..19b5999 100644 --- a/lib/data_classes/players/player_timed_stats.dart +++ b/lib/data_classes/players/player_timed_stats.dart @@ -1,5 +1,5 @@ import "package:freezed_annotation/freezed_annotation.dart"; -import "package:paladinsedge/models/index.dart" show BaseRank, MatchPlayerStats; +import "package:paladinsedge/models/index.dart" show Ranked, MatchPlayerStats; part "player_timed_stats.freezed.dart"; @@ -21,20 +21,31 @@ abstract class TimedStatsValues { @freezed class PlayerTimedStats with _$PlayerTimedStats { + PlayerTimedStats._(); + factory PlayerTimedStats({ + // type of timed stats required TimedStatsType timedStatsType, // for calculating rank diff - required BaseRank startingRank, - required BaseRank endingRank, + required Ranked? rankedStart, + required Ranked? rankedEnd, - // per match data - required Map matchesType, + // count of played things + required Map queuesPlayed, + required List mostPlayedChampions, - // average matches data - required int totalMatches, + // matches data required int wins, required int losses, - required MatchPlayerStats averageStats, + required Duration totalMatchesDuration, + required MatchPlayerStats totalStats, }) = _PlayerTimedStats; + + int get totalMatches => wins + losses; + num get damagePerMinute => + totalStats.totalDamageDealt / totalMatchesDuration.inMinutes; + num get healingPerMinute => + totalStats.healingDone / totalMatchesDuration.inMinutes; + MatchPlayerStats get averageStats => totalStats / totalMatches; } diff --git a/lib/data_classes/players/player_timed_stats.freezed.dart b/lib/data_classes/players/player_timed_stats.freezed.dart index 290c05c..18b7c3d 100644 --- a/lib/data_classes/players/player_timed_stats.freezed.dart +++ b/lib/data_classes/players/player_timed_stats.freezed.dart @@ -16,17 +16,19 @@ final _privateConstructorUsedError = UnsupportedError( /// @nodoc mixin _$PlayerTimedStats { +// type of timed stats TimedStatsType get timedStatsType => throw _privateConstructorUsedError; // for calculating rank diff - BaseRank get startingRank => throw _privateConstructorUsedError; - BaseRank get endingRank => - throw _privateConstructorUsedError; // per match data - Map get matchesType => - throw _privateConstructorUsedError; // average matches data - int get totalMatches => throw _privateConstructorUsedError; + Ranked? get rankedStart => throw _privateConstructorUsedError; + Ranked? get rankedEnd => + throw _privateConstructorUsedError; // count of played things + Map get queuesPlayed => throw _privateConstructorUsedError; + List get mostPlayedChampions => + throw _privateConstructorUsedError; // matches data int get wins => throw _privateConstructorUsedError; int get losses => throw _privateConstructorUsedError; - MatchPlayerStats get averageStats => throw _privateConstructorUsedError; + Duration get totalMatchesDuration => throw _privateConstructorUsedError; + MatchPlayerStats get totalStats => throw _privateConstructorUsedError; @JsonKey(ignore: true) $PlayerTimedStatsCopyWith get copyWith => @@ -41,13 +43,14 @@ abstract class $PlayerTimedStatsCopyWith<$Res> { @useResult $Res call( {TimedStatsType timedStatsType, - BaseRank startingRank, - BaseRank endingRank, - Map matchesType, - int totalMatches, + Ranked? rankedStart, + Ranked? rankedEnd, + Map queuesPlayed, + List mostPlayedChampions, int wins, int losses, - MatchPlayerStats averageStats}); + Duration totalMatchesDuration, + MatchPlayerStats totalStats}); } /// @nodoc @@ -64,35 +67,36 @@ class _$PlayerTimedStatsCopyWithImpl<$Res, $Val extends PlayerTimedStats> @override $Res call({ Object? timedStatsType = null, - Object? startingRank = null, - Object? endingRank = null, - Object? matchesType = null, - Object? totalMatches = null, + Object? rankedStart = freezed, + Object? rankedEnd = freezed, + Object? queuesPlayed = null, + Object? mostPlayedChampions = null, Object? wins = null, Object? losses = null, - Object? averageStats = null, + Object? totalMatchesDuration = null, + Object? totalStats = null, }) { return _then(_value.copyWith( timedStatsType: null == timedStatsType ? _value.timedStatsType : timedStatsType // ignore: cast_nullable_to_non_nullable as TimedStatsType, - startingRank: null == startingRank - ? _value.startingRank - : startingRank // ignore: cast_nullable_to_non_nullable - as BaseRank, - endingRank: null == endingRank - ? _value.endingRank - : endingRank // ignore: cast_nullable_to_non_nullable - as BaseRank, - matchesType: null == matchesType - ? _value.matchesType - : matchesType // ignore: cast_nullable_to_non_nullable + rankedStart: freezed == rankedStart + ? _value.rankedStart + : rankedStart // ignore: cast_nullable_to_non_nullable + as Ranked?, + rankedEnd: freezed == rankedEnd + ? _value.rankedEnd + : rankedEnd // ignore: cast_nullable_to_non_nullable + as Ranked?, + queuesPlayed: null == queuesPlayed + ? _value.queuesPlayed + : queuesPlayed // ignore: cast_nullable_to_non_nullable as Map, - totalMatches: null == totalMatches - ? _value.totalMatches - : totalMatches // ignore: cast_nullable_to_non_nullable - as int, + mostPlayedChampions: null == mostPlayedChampions + ? _value.mostPlayedChampions + : mostPlayedChampions // ignore: cast_nullable_to_non_nullable + as List, wins: null == wins ? _value.wins : wins // ignore: cast_nullable_to_non_nullable @@ -101,9 +105,13 @@ class _$PlayerTimedStatsCopyWithImpl<$Res, $Val extends PlayerTimedStats> ? _value.losses : losses // ignore: cast_nullable_to_non_nullable as int, - averageStats: null == averageStats - ? _value.averageStats - : averageStats // ignore: cast_nullable_to_non_nullable + totalMatchesDuration: null == totalMatchesDuration + ? _value.totalMatchesDuration + : totalMatchesDuration // ignore: cast_nullable_to_non_nullable + as Duration, + totalStats: null == totalStats + ? _value.totalStats + : totalStats // ignore: cast_nullable_to_non_nullable as MatchPlayerStats, ) as $Val); } @@ -119,13 +127,14 @@ abstract class _$$PlayerTimedStatsImplCopyWith<$Res> @useResult $Res call( {TimedStatsType timedStatsType, - BaseRank startingRank, - BaseRank endingRank, - Map matchesType, - int totalMatches, + Ranked? rankedStart, + Ranked? rankedEnd, + Map queuesPlayed, + List mostPlayedChampions, int wins, int losses, - MatchPlayerStats averageStats}); + Duration totalMatchesDuration, + MatchPlayerStats totalStats}); } /// @nodoc @@ -140,35 +149,36 @@ class __$$PlayerTimedStatsImplCopyWithImpl<$Res> @override $Res call({ Object? timedStatsType = null, - Object? startingRank = null, - Object? endingRank = null, - Object? matchesType = null, - Object? totalMatches = null, + Object? rankedStart = freezed, + Object? rankedEnd = freezed, + Object? queuesPlayed = null, + Object? mostPlayedChampions = null, Object? wins = null, Object? losses = null, - Object? averageStats = null, + Object? totalMatchesDuration = null, + Object? totalStats = null, }) { return _then(_$PlayerTimedStatsImpl( timedStatsType: null == timedStatsType ? _value.timedStatsType : timedStatsType // ignore: cast_nullable_to_non_nullable as TimedStatsType, - startingRank: null == startingRank - ? _value.startingRank - : startingRank // ignore: cast_nullable_to_non_nullable - as BaseRank, - endingRank: null == endingRank - ? _value.endingRank - : endingRank // ignore: cast_nullable_to_non_nullable - as BaseRank, - matchesType: null == matchesType - ? _value._matchesType - : matchesType // ignore: cast_nullable_to_non_nullable + rankedStart: freezed == rankedStart + ? _value.rankedStart + : rankedStart // ignore: cast_nullable_to_non_nullable + as Ranked?, + rankedEnd: freezed == rankedEnd + ? _value.rankedEnd + : rankedEnd // ignore: cast_nullable_to_non_nullable + as Ranked?, + queuesPlayed: null == queuesPlayed + ? _value._queuesPlayed + : queuesPlayed // ignore: cast_nullable_to_non_nullable as Map, - totalMatches: null == totalMatches - ? _value.totalMatches - : totalMatches // ignore: cast_nullable_to_non_nullable - as int, + mostPlayedChampions: null == mostPlayedChampions + ? _value._mostPlayedChampions + : mostPlayedChampions // ignore: cast_nullable_to_non_nullable + as List, wins: null == wins ? _value.wins : wins // ignore: cast_nullable_to_non_nullable @@ -177,9 +187,13 @@ class __$$PlayerTimedStatsImplCopyWithImpl<$Res> ? _value.losses : losses // ignore: cast_nullable_to_non_nullable as int, - averageStats: null == averageStats - ? _value.averageStats - : averageStats // ignore: cast_nullable_to_non_nullable + totalMatchesDuration: null == totalMatchesDuration + ? _value.totalMatchesDuration + : totalMatchesDuration // ignore: cast_nullable_to_non_nullable + as Duration, + totalStats: null == totalStats + ? _value.totalStats + : totalStats // ignore: cast_nullable_to_non_nullable as MatchPlayerStats, )); } @@ -187,48 +201,61 @@ class __$$PlayerTimedStatsImplCopyWithImpl<$Res> /// @nodoc -class _$PlayerTimedStatsImpl implements _PlayerTimedStats { +class _$PlayerTimedStatsImpl extends _PlayerTimedStats { _$PlayerTimedStatsImpl( {required this.timedStatsType, - required this.startingRank, - required this.endingRank, - required final Map matchesType, - required this.totalMatches, + required this.rankedStart, + required this.rankedEnd, + required final Map queuesPlayed, + required final List mostPlayedChampions, required this.wins, required this.losses, - required this.averageStats}) - : _matchesType = matchesType; + required this.totalMatchesDuration, + required this.totalStats}) + : _queuesPlayed = queuesPlayed, + _mostPlayedChampions = mostPlayedChampions, + super._(); +// type of timed stats @override final TimedStatsType timedStatsType; // for calculating rank diff @override - final BaseRank startingRank; + final Ranked? rankedStart; @override - final BaseRank endingRank; -// per match data - final Map _matchesType; -// per match data + final Ranked? rankedEnd; +// count of played things + final Map _queuesPlayed; +// count of played things @override - Map get matchesType { - if (_matchesType is EqualUnmodifiableMapView) return _matchesType; + Map get queuesPlayed { + if (_queuesPlayed is EqualUnmodifiableMapView) return _queuesPlayed; // ignore: implicit_dynamic_type - return EqualUnmodifiableMapView(_matchesType); + return EqualUnmodifiableMapView(_queuesPlayed); } -// average matches data + final List _mostPlayedChampions; @override - final int totalMatches; + List get mostPlayedChampions { + if (_mostPlayedChampions is EqualUnmodifiableListView) + return _mostPlayedChampions; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(_mostPlayedChampions); + } + +// matches data @override final int wins; @override final int losses; @override - final MatchPlayerStats averageStats; + final Duration totalMatchesDuration; + @override + final MatchPlayerStats totalStats; @override String toString() { - return 'PlayerTimedStats(timedStatsType: $timedStatsType, startingRank: $startingRank, endingRank: $endingRank, matchesType: $matchesType, totalMatches: $totalMatches, wins: $wins, losses: $losses, averageStats: $averageStats)'; + return 'PlayerTimedStats(timedStatsType: $timedStatsType, rankedStart: $rankedStart, rankedEnd: $rankedEnd, queuesPlayed: $queuesPlayed, mostPlayedChampions: $mostPlayedChampions, wins: $wins, losses: $losses, totalMatchesDuration: $totalMatchesDuration, totalStats: $totalStats)'; } @override @@ -238,31 +265,34 @@ class _$PlayerTimedStatsImpl implements _PlayerTimedStats { other is _$PlayerTimedStatsImpl && (identical(other.timedStatsType, timedStatsType) || other.timedStatsType == timedStatsType) && - (identical(other.startingRank, startingRank) || - other.startingRank == startingRank) && - (identical(other.endingRank, endingRank) || - other.endingRank == endingRank) && + (identical(other.rankedStart, rankedStart) || + other.rankedStart == rankedStart) && + (identical(other.rankedEnd, rankedEnd) || + other.rankedEnd == rankedEnd) && + const DeepCollectionEquality() + .equals(other._queuesPlayed, _queuesPlayed) && const DeepCollectionEquality() - .equals(other._matchesType, _matchesType) && - (identical(other.totalMatches, totalMatches) || - other.totalMatches == totalMatches) && + .equals(other._mostPlayedChampions, _mostPlayedChampions) && (identical(other.wins, wins) || other.wins == wins) && (identical(other.losses, losses) || other.losses == losses) && - (identical(other.averageStats, averageStats) || - other.averageStats == averageStats)); + (identical(other.totalMatchesDuration, totalMatchesDuration) || + other.totalMatchesDuration == totalMatchesDuration) && + (identical(other.totalStats, totalStats) || + other.totalStats == totalStats)); } @override int get hashCode => Object.hash( runtimeType, timedStatsType, - startingRank, - endingRank, - const DeepCollectionEquality().hash(_matchesType), - totalMatches, + rankedStart, + rankedEnd, + const DeepCollectionEquality().hash(_queuesPlayed), + const DeepCollectionEquality().hash(_mostPlayedChampions), wins, losses, - averageStats); + totalMatchesDuration, + totalStats); @JsonKey(ignore: true) @override @@ -272,33 +302,37 @@ class _$PlayerTimedStatsImpl implements _PlayerTimedStats { this, _$identity); } -abstract class _PlayerTimedStats implements PlayerTimedStats { +abstract class _PlayerTimedStats extends PlayerTimedStats { factory _PlayerTimedStats( {required final TimedStatsType timedStatsType, - required final BaseRank startingRank, - required final BaseRank endingRank, - required final Map matchesType, - required final int totalMatches, + required final Ranked? rankedStart, + required final Ranked? rankedEnd, + required final Map queuesPlayed, + required final List mostPlayedChampions, required final int wins, required final int losses, - required final MatchPlayerStats averageStats}) = _$PlayerTimedStatsImpl; + required final Duration totalMatchesDuration, + required final MatchPlayerStats totalStats}) = _$PlayerTimedStatsImpl; + _PlayerTimedStats._() : super._(); - @override + @override // type of timed stats TimedStatsType get timedStatsType; @override // for calculating rank diff - BaseRank get startingRank; + Ranked? get rankedStart; @override - BaseRank get endingRank; - @override // per match data - Map get matchesType; - @override // average matches data - int get totalMatches; + Ranked? get rankedEnd; + @override // count of played things + Map get queuesPlayed; @override + List get mostPlayedChampions; + @override // matches data int get wins; @override int get losses; @override - MatchPlayerStats get averageStats; + Duration get totalMatchesDuration; + @override + MatchPlayerStats get totalStats; @override @JsonKey(ignore: true) _$$PlayerTimedStatsImplCopyWith<_$PlayerTimedStatsImpl> get copyWith => diff --git a/lib/models/match/match.dart b/lib/models/match/match.dart index ea8db3f..cd9912e 100644 --- a/lib/models/match/match.dart +++ b/lib/models/match/match.dart @@ -1,5 +1,7 @@ // The match that is completed +import "dart:math"; + import "package:hive/hive.dart"; import "package:json_annotation/json_annotation.dart"; import "package:paladinsedge/constants/index.dart" show TypeIds; @@ -76,6 +78,65 @@ class MatchPlayerStats { factory MatchPlayerStats.fromJson(Map json) => _$MatchPlayerStatsFromJson(json); Map toJson() => _$MatchPlayerStatsToJson(this); + + /// adds all the values from the two MatchPlayerStats instances, + /// except for the value biggestKillStreak, which takes the max, instead of adding + MatchPlayerStats operator +(MatchPlayerStats other) { + return MatchPlayerStats( + kills: kills + other.kills, + assists: assists + other.assists, + deaths: deaths + other.deaths, + weaponDamageDealt: weaponDamageDealt + other.weaponDamageDealt, + totalDamageDealt: totalDamageDealt + other.totalDamageDealt, + damageShielded: damageShielded + other.damageShielded, + totalDamageTaken: totalDamageTaken + other.totalDamageTaken, + selfHealingDone: selfHealingDone + other.selfHealingDone, + healingDone: healingDone + other.healingDone, + biggestKillStreak: max(biggestKillStreak, other.biggestKillStreak), + totalMultiKills: totalMultiKills + other.totalMultiKills, + objectiveTime: objectiveTime + other.objectiveTime, + creditsEarned: creditsEarned + other.creditsEarned, + ); + } + + /// divides all the values in MatchPlayerStats by the divisor number, + /// except for the value biggestKillStreak, which remains unchanged + MatchPlayerStats operator /(num divisor) { + return MatchPlayerStats( + kills: kills / divisor, + assists: assists / divisor, + deaths: deaths / divisor, + weaponDamageDealt: weaponDamageDealt / divisor, + totalDamageDealt: totalDamageDealt / divisor, + damageShielded: damageShielded / divisor, + totalDamageTaken: totalDamageTaken / divisor, + selfHealingDone: selfHealingDone / divisor, + healingDone: healingDone / divisor, + biggestKillStreak: biggestKillStreak, + totalMultiKills: totalMultiKills / divisor, + objectiveTime: objectiveTime / divisor, + creditsEarned: creditsEarned / divisor, + ); + } + + /// creates a new MatchPlayerStats instance with all values 0 + static MatchPlayerStats createEmpty() { + return MatchPlayerStats( + kills: 0, + assists: 0, + deaths: 0, + weaponDamageDealt: 0, + totalDamageDealt: 0, + damageShielded: 0, + totalDamageTaken: 0, + selfHealingDone: 0, + healingDone: 0, + biggestKillStreak: 0, + totalMultiKills: 0, + objectiveTime: 0, + creditsEarned: 0, + ); + } } @JsonSerializable() @@ -204,8 +265,8 @@ class Match { /// time when the match started final DateTime matchStartTime; - /// duration of the match - final int matchDuration; + /// duration of the match, received in seconds + final Duration matchDuration; /// queue of the match final String queue; @@ -235,14 +296,14 @@ class Match { required this.team1Score, required this.team2Score, required this.matchStartTime, - required this.matchDuration, required this.queue, required this.map, required this.region, required this.isRankedMatch, required this.championBans, required this.isInComplete, - }); + required int matchDuration, + }) : matchDuration = Duration(seconds: matchDuration); factory Match.fromJson(Map json) => _$MatchFromJson(json); Map toJson() => _$MatchToJson(this); diff --git a/lib/models/match/match.g.dart b/lib/models/match/match.g.dart index 9e3418d..3bd95f3 100644 --- a/lib/models/match/match.g.dart +++ b/lib/models/match/match.g.dart @@ -169,7 +169,6 @@ Match _$MatchFromJson(Map json) => Match( team1Score: json['team1Score'] as int, team2Score: json['team2Score'] as int, matchStartTime: DateTime.parse(json['matchStartTime'] as String), - matchDuration: json['matchDuration'] as int, queue: json['queue'] as String, map: json['map'] as String, region: json['region'] as String, @@ -177,6 +176,7 @@ Match _$MatchFromJson(Map json) => Match( championBans: (json['championBans'] as List).map((e) => e as int).toList(), isInComplete: json['isInComplete'] as bool, + matchDuration: json['matchDuration'] as int, ); Map _$MatchToJson(Match instance) => { @@ -185,7 +185,7 @@ Map _$MatchToJson(Match instance) => { 'team1Score': instance.team1Score, 'team2Score': instance.team2Score, 'matchStartTime': instance.matchStartTime.toIso8601String(), - 'matchDuration': instance.matchDuration, + 'matchDuration': instance.matchDuration.inMicroseconds, 'queue': instance.queue, 'map': instance.map, 'region': instance.region, diff --git a/lib/providers/players.dart b/lib/providers/players.dart index 5211499..c6292d6 100644 --- a/lib/providers/players.dart +++ b/lib/providers/players.dart @@ -23,6 +23,7 @@ class _PlayersNotifier extends ChangeNotifier { models.PlayerInferred? playerInferred; List? combinedMatches; List? commonMatches; + data_classes.PlayerTimedStats? timedStats; /// Matches filter and sorting String selectedSort = data_classes.MatchSort.defaultSort; @@ -138,20 +139,23 @@ class _PlayersNotifier extends ChangeNotifier { combinedMatches = tempMatchesMap.values.toList(); - // sort combinedMatches based on the selectedSort + // sort combinedMatches based on the default sorting (i.e. sorting by date) if (combinedMatches != null) { combinedMatches = data_classes.MatchSort.getSortedMatches( combinedMatches: combinedMatches!, - sort: selectedSort, + sort: data_classes.MatchSort.defaultSort, + ); + playerStreak = utilities.getPlayerStreak(combinedMatches!, playerId); + timedStats = utilities.getPlayerTimedStats( + combinedMatches!, + data_classes.TimedStatsType.days1, + playerId, ); + print("TIMED :: ${timedStats!.totalMatches}"); + print("TIMED TOTAL :: ${timedStats!.totalStats.kills}"); + print("TIMED AVG :: ${timedStats!.averageStats.kills}"); } - // get the playerStreak - playerStreak = utilities.getPlayerStreak( - combinedMatches, - playerId, - ); - if (!forceUpdate) isPlayerMatchesLoading = false; notifyListeners(); diff --git a/lib/screens/match_detail/match_detail_player_card.dart b/lib/screens/match_detail/match_detail_player_card.dart index ea85bfb..361cb16 100644 --- a/lib/screens/match_detail/match_detail_player_card.dart +++ b/lib/screens/match_detail/match_detail_player_card.dart @@ -112,14 +112,11 @@ class MatchDetailPlayerCard extends HookConsumerWidget { final damagePerMinute = useMemoized( () { - // matchDuration is in seconds - final result = match.matchDuration < 1 - ? 0 - : matchPlayer.playerStats.totalDamageDealt * - 60 / - match.matchDuration; - - return result.toInt(); + final minutes = match.matchDuration.inMinutes; + final damage = matchPlayer.playerStats.totalDamageDealt; + if (minutes == 0) return damage; + + return damage / minutes; }, [match, matchPlayer], ); diff --git a/lib/screens/match_detail/match_detail_stats.dart b/lib/screens/match_detail/match_detail_stats.dart index fc25fa9..0ba0261 100644 --- a/lib/screens/match_detail/match_detail_stats.dart +++ b/lib/screens/match_detail/match_detail_stats.dart @@ -17,7 +17,7 @@ class MatchDetailStats extends StatelessWidget { final match = combinedMatch?.match; if (match == null) return const SizedBox.shrink(); final matchDuration = printDuration( - Duration(seconds: match.matchDuration), + match.matchDuration, abbreviated: true, upperTersity: DurationTersity.minute, conjugation: " ", diff --git a/lib/utilities/match.dart b/lib/utilities/match.dart index 4ed8b88..04f10bd 100644 --- a/lib/utilities/match.dart +++ b/lib/utilities/match.dart @@ -17,20 +17,22 @@ models.MatchPlayer? getMatchPlayerFromPlayerId( bool didPlayerWin( data_classes.CombinedMatch combinedMatch, - String playerId, -) { - final matchPlayer = + String playerId, { + models.MatchPlayer? matchPlayer, +}) { + final usableMatchPlayer = matchPlayer ?? getMatchPlayerFromPlayerId(combinedMatch.matchPlayers, playerId); - if (matchPlayer == null) return false; + if (usableMatchPlayer == null) return false; - return matchPlayer.team == combinedMatch.match.winningTeam; + return usableMatchPlayer.team == combinedMatch.match.winningTeam; } +/// get the winning/ loosing streak of the player, +/// assuming `combinedMatches` is sorted by date int? getPlayerStreak( - List? combinedMatches, + List combinedMatches, String? combinedMatchesPlayerId, ) { - if (combinedMatches == null) return null; if (combinedMatches.length < 5) return null; if (combinedMatchesPlayerId == null) return null; @@ -53,3 +55,72 @@ int? getPlayerStreak( return isFirstWin ? streak : -streak; } + +/// get the timed stats of the player, +/// assuming `combinedMatches` is sorted by date +data_classes.PlayerTimedStats getPlayerTimedStats( + List combinedMatches, + data_classes.TimedStatsType timedStatsType, + String playerId, +) { + final earliestDate = DateTime.now() - + data_classes.TimedStatsValues.durationValues[timedStatsType]!; + + models.Ranked? rankedStart; + models.Ranked? rankedEnd = getMatchPlayerFromPlayerId( + combinedMatches.first.matchPlayers, + playerId, + )?.playerRanked; + Map queuesPlayed = {}; + Map championsPlayed = {}; + int wins = 0; + int losses = 0; + Duration totalMatchesDuration = Duration.zero; + models.MatchPlayerStats totalStats = models.MatchPlayerStats.createEmpty(); + + for (final combinedMatch in combinedMatches) { + // assuming matches are sorted by date, we can safely break the loop + // upon encountering an earlier than expected match + if (combinedMatch.match.matchStartTime < earliestDate) break; + + final matchPlayer = getMatchPlayerFromPlayerId( + combinedMatch.matchPlayers, + playerId, + ); + if (matchPlayer == null) continue; + + rankedStart = matchPlayer.playerRanked; + queuesPlayed.update( + combinedMatch.match.queue, + (count) => count + 1, + ifAbsent: () => 0, + ); + championsPlayed.update( + matchPlayer.championId, + (count) => count + 1, + ifAbsent: () => 0, + ); + if (didPlayerWin(combinedMatch, playerId, matchPlayer: matchPlayer)) { + wins += 1; + } else { + losses += 1; + } + totalStats += matchPlayer.playerStats; + totalMatchesDuration += combinedMatch.match.matchDuration; + } + + final mostPlayedChampions = + championsPlayed.keys.sortedDescending().takeFirst(3); + + return data_classes.PlayerTimedStats( + timedStatsType: timedStatsType, + rankedStart: rankedStart, + rankedEnd: rankedEnd, + queuesPlayed: queuesPlayed, + mostPlayedChampions: mostPlayedChampions, + totalMatchesDuration: totalMatchesDuration, + wins: wins, + losses: losses, + totalStats: totalStats, + ); +} diff --git a/pubspec.yaml b/pubspec.yaml index 99c89a9..8b867bc 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,7 +30,7 @@ dependencies: sdk: flutter dio: ^5.4.0 dio_http2_adapter: ^2.4.0 - json_annotation: ^4.5.0 + json_annotation: ^4.8.1 google_fonts: ^4.0.4 bottom_navy_bar: ^6.0.0 google_sign_in: ^6.1.0 @@ -87,7 +87,7 @@ dev_dependencies: flutter_test: sdk: flutter build_runner: ^2.3.3 - json_serializable: ^6.6.1 + json_serializable: ^6.7.1 hive_generator: ^2.0.0 flutter_launcher_icons: ^0.13.0 flutter_lints: ^3.0.1