From fd6ec6dacf90cc95bbaf1ed83b16310634af2406 Mon Sep 17 00:00:00 2001 From: Chen Asraf Date: Wed, 12 Jul 2023 01:22:45 +0300 Subject: [PATCH] feat: type matchups --- lib/core/models/pokemon_helper.dart | 64 +++++++++++++++++++ .../PokemonDetails/pokemon_details_page.dart | 63 ++++++++++++++---- 2 files changed, 116 insertions(+), 11 deletions(-) diff --git a/lib/core/models/pokemon_helper.dart b/lib/core/models/pokemon_helper.dart index 228f69b..84ac081 100644 --- a/lib/core/models/pokemon_helper.dart +++ b/lib/core/models/pokemon_helper.dart @@ -63,5 +63,69 @@ class PokemonHelper { return move.flavorTextEntries.firstWhereOrNull((n) => n.language.name == 'en')?.flavorText ?? (move.flavorTextEntries.isNotEmpty ? move.flavorTextEntries.first.flavorText : ''); } + + static List getTypeDefenseMultipliers(List types) { + final typeMap = {}; + final typeNameMap = {}; + for (final type in types) { + for (final damage in type.damageRelations.doubleDamageFrom) { + typeNameMap[damage.name] ??= damage; + typeMap[damage.name] = (typeMap[damage.name] ?? 1) * 2; + } + for (final damage in type.damageRelations.halfDamageFrom) { + typeNameMap[damage.name] ??= damage; + typeMap[damage.name] = (typeMap[damage.name] ?? 1) * 0.5; + } + for (final damage in type.damageRelations.noDamageFrom) { + typeNameMap[damage.name] ??= damage; + typeMap[damage.name] = (typeMap[damage.name] ?? 1) * 0; + } + } + return typeMap.entries.map((e) { + return TypeMultiplier(typeNameMap[e.key]!, e.value); + }).toList(); + } + + static List getTypeAttackMultipliers(List types) { + final typeMap = {}; + final typeNameMap = {}; + for (final type in types) { + for (final damage in type.damageRelations.doubleDamageTo) { + typeNameMap[damage.name] ??= damage; + typeMap[damage.name] = (typeMap[damage.name] ?? 1) * 2; + } + for (final damage in type.damageRelations.halfDamageTo) { + typeNameMap[damage.name] ??= damage; + typeMap[damage.name] = (typeMap[damage.name] ?? 1) * 0.5; + } + for (final damage in type.damageRelations.noDamageTo) { + typeNameMap[damage.name] ??= damage; + typeMap[damage.name] = (typeMap[damage.name] ?? 1) * 0; + } + } + return typeMap.entries.map((e) { + return TypeMultiplier(typeNameMap[e.key]!, e.value); + }).toList(); + } +} + +class TypeMultiplier { + TypeMultiplier(this.type, this.multiplier); + + final NamedAPIResource type; + final double multiplier; + + String get name => type.name; + String get multiplierString => + { + 0.5: '½', + 0.25: '¼', + }[multiplier] ?? + multiplier.toStringAsFixed(2).replaceAll(RegExp(r'0+$'), '').replaceAll(RegExp(r'\.$'), ''); + + @override + String toString() { + return '$name x $multiplierString'; + } } diff --git a/lib/modules/PokemonDetails/pokemon_details_page.dart b/lib/modules/PokemonDetails/pokemon_details_page.dart index a1fe471..238e1db 100644 --- a/lib/modules/PokemonDetails/pokemon_details_page.dart +++ b/lib/modules/PokemonDetails/pokemon_details_page.dart @@ -48,22 +48,60 @@ class PokemonDetailsPage extends StatelessWidget { PokemonImage(poke: poke, size: imgSize, shiny: true), ], ), - () => const Text('Weaknesses', textScaleFactor: 1.2), + () => const Text('Weak against', textScaleFactor: 1.2), () => FutureBuilder( future: Future.wait(poke.types.map((t) => t.type.get())), builder: (context, snapshot) { final data = snapshot.hasData - ? snapshot.data! - .toList() - .fold([], (prev, type) => prev..addAll(type.damageRelations.doubleDamageFrom)) - : []; + ? PokemonHelper.getTypeDefenseMultipliers(snapshot.data!.toList()).where((e) => e.multiplier >= 2) + : []; return Wrap( children: [ - for (final weakness in data) + for (final type in data) Padding( padding: const EdgeInsets.all(4.0), child: Chip( - label: Text('${weakness.name.capitalize()} x2'), + label: Text('${type.type.name.capitalize()} x ${type.multiplierString}'), + ), + ) + ], + ); + }, + ), + () => const Text('Resistant to', textScaleFactor: 1.2), + () => FutureBuilder( + future: Future.wait(poke.types.map((t) => t.type.get())), + builder: (context, snapshot) { + final data = snapshot.hasData + ? PokemonHelper.getTypeDefenseMultipliers(snapshot.data!.toList()).where((e) => e.multiplier < 1 && e.multiplier > 0) + : []; + return Wrap( + children: [ + for (final type in data) + Padding( + padding: const EdgeInsets.all(4.0), + child: Chip( + label: Text('${type.type.name.capitalize()} x ${type.multiplierString}'), + ), + ) + ], + ); + }, + ), + () => const Text('No damage from', textScaleFactor: 1.2), + () => FutureBuilder( + future: Future.wait(poke.types.map((t) => t.type.get())), + builder: (context, snapshot) { + final data = snapshot.hasData + ? PokemonHelper.getTypeDefenseMultipliers(snapshot.data!.toList()).where((e) => e.multiplier == 0) + : []; + return Wrap( + children: [ + for (final type in data) + Padding( + padding: const EdgeInsets.all(4.0), + child: Chip( + label: Text('${type.type.name.capitalize()} x ${type.multiplierString}'), ), ) ], @@ -150,7 +188,7 @@ class PokemonDetailsPage extends StatelessWidget { children: [ if (icon != null) Container( - color: Colors.purple, + // color: Colors.purple, child: CachedNetworkImage( imageUrl: icon, width: 40, @@ -163,9 +201,12 @@ class PokemonDetailsPage extends StatelessWidget { ], ), ), - body: ListView.builder( - itemBuilder: (context, index) => children[index].call(), - itemCount: children.length, + body: Padding( + padding: const EdgeInsets.all(8.0), + child: ListView.builder( + itemBuilder: (context, index) => children[index].call(), + itemCount: children.length, + ), ), ); }