Skip to content

Commit

Permalink
Show the custom builds on the character detail
Browse files Browse the repository at this point in the history
Minor improvements
  • Loading branch information
Wolfteam committed Jan 21, 2022
1 parent e5791e3 commit 0e1279c
Show file tree
Hide file tree
Showing 25 changed files with 428 additions and 236 deletions.
69 changes: 36 additions & 33 deletions lib/application/character/character_bloc.dart
Expand Up @@ -86,6 +86,41 @@ class CharacterBloc extends Bloc<CharacterEvent, CharacterState> {

final birthday = _localeService.formatCharBirthDate(char.birthday);
final isInInventory = _dataService.isItemInInventory(char.key, ItemType.character);
final builds = char.builds.map((build) {
return CharacterBuildCardModel(
isRecommended: build.isRecommended,
type: build.type,
subType: build.subType,
skillPriorities: build.skillPriorities,
subStatsToFocus: build.subStatsToFocus,
weapons: build.weaponKeys.map((e) => _genshinService.getWeaponForCard(e)).toList(),
artifacts: build.artifacts.map(
(e) {
final one = e.oneKey != null ? _genshinService.getArtifactForCard(e.oneKey!) : null;
final multiples = e.multiples
.map(
(m) => CharacterBuildMultipleArtifactModel(
quantity: m.quantity,
artifact: _genshinService.getArtifactForCard(m.key),
),
)
.toList();

if (multiples.isNotEmpty) {
final count = multiples.map((e) => e.quantity).fold(0, (int p, int c) => p + c);
final diff = artifactOrder.length - count;
if (diff >= 1) {
multiples.add(CharacterBuildMultipleArtifactModel(quantity: diff, artifact: multiples.last.artifact));
}
}
return CharacterBuildArtifactModel(one: one, multiples: _flatMultiBuild(multiples), stats: e.stats);
},
).toList(),
);
}).toList();

builds.addAll(_dataService.customBuilds.getCustomBuildsForCharacter(char.key));
builds.sort((x, y) => x.isRecommended ? -1 : 1);

return CharacterState.loaded(
key: char.key,
Expand Down Expand Up @@ -145,39 +180,7 @@ class CharacterBloc extends Bloc<CharacterEvent, CharacterState> {
);
}).toList(),
multiTalentAscensionMaterials: multiTalents,
builds: char.builds.map((build) {
return CharacterBuildCardModel(
isRecommended: build.isRecommended,
type: build.type,
subType: build.subType,
skillPriorities: build.skillPriorities,
subStatsToFocus: build.subStatsToFocus,
weapons: build.weaponKeys.map((e) => _genshinService.getWeaponForCard(e)).toList(),
artifacts: build.artifacts.map(
(e) {
final one = e.oneKey != null ? _genshinService.getArtifactForCard(e.oneKey!) : null;
final multiples = e.multiples
.map(
(m) => CharacterBuildMultipleArtifactModel(
quantity: m.quantity,
artifact: _genshinService.getArtifactForCard(m.key),
),
)
.toList();

if (multiples.isNotEmpty) {
final count = multiples.map((e) => e.quantity).fold(0, (int p, int c) => p + c);
final diff = artifactOrder.length - count;
if (diff >= 1) {
multiples.add(CharacterBuildMultipleArtifactModel(quantity: diff, artifact: multiples.last.artifact));
}
}
return CharacterBuildArtifactModel(one: one, multiples: _flatMultiBuild(multiples), stats: e.stats);
},
).toList(),
);
}).toList()
..sort((x, y) => x.isRecommended ? -1 : 1),
builds: builds,
subStatType: char.subStatType,
stats: char.stats,
);
Expand Down
37 changes: 15 additions & 22 deletions lib/application/custom_build/custom_build_bloc.dart
Expand Up @@ -33,7 +33,6 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
on<CustomBuildEvent>(_handleEvent);
}

//TODO: REMOVE UPCOMING CHARACTERS ?
Future<void> _handleEvent(CustomBuildEvent event, Emitter<CustomBuildState> emit) async {
//TODO: SHOULD I TRHOW ON INVALID REQUEST ?
//IN MOST CASES THERE ARE SOME VALIDATIONS FOR THINGS LIKE
Expand Down Expand Up @@ -160,7 +159,7 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
skillPriorities: build.skillPriorities,
artifacts: build.artifacts..sort((x, y) => x.type.index.compareTo(y.type.index)),
teamCharacters: build.teamCharacters,
subStatsSummary: _generateSubStatSummary(build.artifacts),
subStatsSummary: _genshinService.generateSubStatSummary(build.artifacts),
);
}

Expand Down Expand Up @@ -221,7 +220,16 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
return state;
}
final newCharacter = _genshinService.getCharacterForCard(e.newKey);
return state.copyWith.call(character: newCharacter);
_LoadedState updatedState = state.copyWith.call(character: newCharacter);
if (newCharacter.weaponType != state.character.weaponType) {
updatedState = updatedState.copyWith.call(weapons: []);
}

if (updatedState.teamCharacters.any((el) => el.key == e.newKey)) {
updatedState.teamCharacters.removeWhere((el) => el.key == e.newKey);
}

return updatedState;
}

CustomBuildState _addWeapon(_AddWeapon e, _LoadedState state) {
Expand Down Expand Up @@ -304,6 +312,7 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
final updatedSubStats = [...old.subStats]..removeWhere((el) => el == e.statType);
final updated = old.copyWith.call(
type: e.type,
name: translation.name,
image: img,
key: e.key,
rarity: fullArtifact.maxRarity,
Expand All @@ -314,6 +323,7 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
} else {
final newOne = CustomBuildArtifactModel(
type: e.type,
name: translation.name,
image: img,
key: e.key,
rarity: fullArtifact.maxRarity,
Expand Down Expand Up @@ -341,7 +351,7 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
final artifacts = [...state.artifacts];
artifacts.removeAt(index);
artifacts.insert(index, updated);
return state.copyWith.call(artifacts: artifacts, subStatsSummary: _generateSubStatSummary(artifacts));
return state.copyWith.call(artifacts: artifacts, subStatsSummary: _genshinService.generateSubStatSummary(artifacts));
}

CustomBuildState _deleteArtifact(_DeleteArtifact e, _LoadedState state) {
Expand All @@ -351,7 +361,7 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {

final updated = [...state.artifacts];
updated.removeWhere((el) => el.type == e.type);
return state.copyWith.call(artifacts: updated, subStatsSummary: _generateSubStatSummary(updated));
return state.copyWith.call(artifacts: updated, subStatsSummary: _genshinService.generateSubStatSummary(updated));
}

CustomBuildState _addTeamCharacter(_AddTeamCharacter e, _LoadedState state) {
Expand Down Expand Up @@ -447,21 +457,4 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
_customBuildsBloc.add(const CustomBuildsEvent.load());
return _init(build.key, state.title);
}

List<StatType> _generateSubStatSummary(List<CustomBuildArtifactModel> artifacts) {
final weightMap = <StatType, int>{};

for (final artifact in artifacts) {
int weight = artifact.subStats.length;
for (var i = 0; i < artifact.subStats.length; i++) {
final subStat = artifact.subStats[i];
final ifAbsent = weightMap.containsKey(subStat) ? i : weight;
weightMap.update(subStat, (value) => value + weight, ifAbsent: () => ifAbsent);
weight--;
}
}

final sorted = weightMap.entries.sorted((a, b) => b.value.compareTo(a.value));
return sorted.map((e) => e.key).toList();
}
}
2 changes: 1 addition & 1 deletion lib/application/custom_build/custom_build_event.dart
Expand Up @@ -69,5 +69,5 @@ class CustomBuildEvent with _$CustomBuildEvent {

const factory CustomBuildEvent.saveChanges() = _SaveChanges;

//TODO: SHARE, SBUSTATS, TALENETS, ARTIFACT'S PIECE BONUS
//TODO: SHARE
}
2 changes: 2 additions & 0 deletions lib/domain/models/characters/character_build_card_model.dart
Expand Up @@ -10,6 +10,7 @@ class CharacterBuildCardModel {
final List<WeaponCardModel> weapons;
final List<CharacterBuildArtifactModel> artifacts;
final List<StatType> subStatsToFocus;
final bool isCustomBuild;

CharacterBuildCardModel({
required this.isRecommended,
Expand All @@ -19,6 +20,7 @@ class CharacterBuildCardModel {
required this.weapons,
required this.artifacts,
required this.subStatsToFocus,
this.isCustomBuild = false,
});
}

Expand Down
Expand Up @@ -8,6 +8,7 @@ class CustomBuildArtifactModel with _$CustomBuildArtifactModel {
const factory CustomBuildArtifactModel({
required String key,
required ArtifactType type,
required String name,
required StatType statType,
required String image,
required int rarity,
Expand Down
1 change: 1 addition & 0 deletions lib/domain/models/custom_builds/custom_build_model.dart
Expand Up @@ -19,5 +19,6 @@ class CustomBuildModel with _$CustomBuildModel {
required List<CustomBuildTeamCharacterModel> teamCharacters,
required List<CustomBuildNoteModel> notes,
required List<CharacterSkillType> skillPriorities,
required List<StatType> subStatsSummary,
}) = _CustomBuildModel;
}
1 change: 1 addition & 0 deletions lib/domain/services/genshin_service.dart
Expand Up @@ -85,4 +85,5 @@ abstract class GenshinService {
List<ArtifactCardBonusModel> getArtifactBonus(TranslationArtifactFile translation);
List<String> getArtifactRelatedParts(String fullImagePath, String image, int bonus);
String getArtifactRelatedPart(String fullImagePath, String image, int bonus, ArtifactType type);
List<StatType> generateSubStatSummary(List<CustomBuildArtifactModel> artifacts);
}
Expand Up @@ -40,4 +40,6 @@ abstract class CustomBuildsDataService {
);

Future<void> deleteCustomBuild(int key);

List<CharacterBuildCardModel> getCustomBuildsForCharacter(String charKey);
}
18 changes: 18 additions & 0 deletions lib/infrastructure/genshin_service.dart
Expand Up @@ -782,6 +782,24 @@ class GenshinServiceImpl implements GenshinService {
return imgs.firstWhere((el) => el.endsWith('$order.png'));
}

@override
List<StatType> generateSubStatSummary(List<CustomBuildArtifactModel> artifacts) {
final weightMap = <StatType, int>{};

for (final artifact in artifacts) {
int weight = artifact.subStats.length;
for (var i = 0; i < artifact.subStats.length; i++) {
final subStat = artifact.subStats[i];
final ifAbsent = weightMap.containsKey(subStat) ? i : weight;
weightMap.update(subStat, (value) => value + weight, ifAbsent: () => ifAbsent);
weight--;
}
}

final sorted = weightMap.entries.sorted((a, b) => b.value.compareTo(a.value));
return sorted.map((e) => e.key).toList();
}

CharacterCardModel _toCharacterForCard(CharacterFileModel character) {
final translation = getCharacterTranslation(character.key);

Expand Down
81 changes: 55 additions & 26 deletions lib/infrastructure/persistence/custom_builds_data_service.dart
Expand Up @@ -134,6 +134,30 @@ class CustomBuildsDataServiceImpl implements CustomBuildsDataService {
]);
}

@override
List<CharacterBuildCardModel> getCustomBuildsForCharacter(String charKey) {
return _buildsBox.values.where((el) => el.showOnCharacterDetail && el.characterKey == charKey).map((e) {
final build = getCustomBuild(e.key as int);
final artifacts = build.artifacts.map((e) => _genshinService.getArtifactForCard(e.key)).toList();
return CharacterBuildCardModel(
isRecommended: e.isRecommended,
isCustomBuild: true,
type: CharacterRoleType.values[e.roleType],
subType: CharacterRoleSubType.values[e.roleSubType],
skillPriorities: e.skillPriorities.map((e) => CharacterSkillType.values[e]).toList(),
subStatsToFocus: _genshinService.generateSubStatSummary(build.artifacts),
weapons: build.weapons.map((e) => _genshinService.getWeaponForCard(e.key)).toList(),
artifacts: [
CharacterBuildArtifactModel(
one: null,
stats: build.artifacts.map((e) => e.statType).toList(),
multiples: artifacts,
),
],
);
}).toList();
}

Future<void> _deleteCustomBuildRelatedParts(int key) {
return Future.wait([
_deleteWeapons(key),
Expand Down Expand Up @@ -205,12 +229,32 @@ class CustomBuildsDataServiceImpl implements CustomBuildsDataService {

CustomBuildModel _mapToCustomBuildModel(
CustomBuild build,
List<CustomBuildNote> notes,
List<CustomBuildWeapon> weapons,
List<CustomBuildArtifact> artifacts,
List<CustomBuildTeamCharacter> teamCharacters,
List<CustomBuildNote> buildNotes,
List<CustomBuildWeapon> buildWeapons,
List<CustomBuildArtifact> buildArtifacts,
List<CustomBuildTeamCharacter> buildTeamCharacters,
) {
final character = _genshinService.getCharacterForCard(build.characterKey);
final artifacts = buildArtifacts.map((e) {
final fullArtifact = _genshinService.getArtifact(e.itemKey);
final translation = _genshinService.getArtifactTranslation(e.itemKey);
final image = _genshinService.getArtifactRelatedPart(
fullArtifact.fullImagePath,
fullArtifact.image,
translation.bonus.length,
ArtifactType.values[e.type],
);
return CustomBuildArtifactModel(
key: e.itemKey,
name: translation.name,
type: ArtifactType.values[e.type],
statType: StatType.values[e.statType],
image: image,
rarity: fullArtifact.maxRarity,
subStats: e.subStats.map((e) => StatType.values[e]).toList(),
);
}).toList()
..sort((x, y) => x.type.index.compareTo(y.type.index));
return CustomBuildModel(
key: build.key as int,
title: build.title,
Expand All @@ -219,7 +263,7 @@ class CustomBuildsDataServiceImpl implements CustomBuildsDataService {
showOnCharacterDetail: build.showOnCharacterDetail,
isRecommended: build.isRecommended,
character: character,
weapons: weapons.map((e) {
weapons: buildWeapons.map((e) {
final weapon = _genshinService.getWeaponForCard(e.weaponKey);
return CustomBuildWeaponModel(
key: e.weaponKey,
Expand All @@ -232,28 +276,13 @@ class CustomBuildsDataServiceImpl implements CustomBuildsDataService {
subStatType: weapon.subStatType,
subStatValue: weapon.subStatValue,
);
}).toList(),
artifacts: artifacts.map((e) {
final fullArtifact = _genshinService.getArtifact(e.itemKey);
final translation = _genshinService.getArtifactTranslation(e.itemKey);
final image = _genshinService.getArtifactRelatedPart(
fullArtifact.fullImagePath,
fullArtifact.image,
translation.bonus.length,
ArtifactType.values[e.type],
);
return CustomBuildArtifactModel(
key: e.itemKey,
type: ArtifactType.values[e.type],
statType: StatType.values[e.statType],
image: image,
rarity: fullArtifact.maxRarity,
subStats: e.subStats.map((e) => StatType.values[e]).toList(),
);
}).toList(),
}).toList()
..sort((x, y) => x.index.compareTo(y.index)),
artifacts: artifacts,
subStatsSummary: _genshinService.generateSubStatSummary(artifacts),
skillPriorities: build.skillPriorities.map((e) => CharacterSkillType.values[e]).toList(),
notes: notes.map((e) => CustomBuildNoteModel(index: e.index, note: e.note)).toList()..sort((x, y) => x.index.compareTo(y.index)),
teamCharacters: teamCharacters.map((e) {
notes: buildNotes.map((e) => CustomBuildNoteModel(index: e.index, note: e.note)).toList()..sort((x, y) => x.index.compareTo(y.index)),
teamCharacters: buildTeamCharacters.map((e) {
final char = _genshinService.getCharacterForCard(e.characterKey);
return CustomBuildTeamCharacterModel(
key: e.characterKey,
Expand Down
11 changes: 11 additions & 0 deletions lib/presentation/artifacts/widgets/artifact_card.dart
Expand Up @@ -9,6 +9,8 @@ import 'package:transparent_image/transparent_image.dart';

import 'artifact_stats.dart';

final replaceDigitRegex = RegExp(r'\d{1}');

class ArtifactCard extends StatelessWidget {
final String keyName;
final String name;
Expand Down Expand Up @@ -92,6 +94,15 @@ class ArtifactCard extends StatelessWidget {
height: imgHeight,
placeholder: MemoryImage(kTransparentImage),
image: AssetImage(image),
imageErrorBuilder: (context, error, stack) {
//This can happen when trying to load sets like 'Prayer to xxx'
final path = image.replaceFirst(replaceDigitRegex, '4');
return Image.asset(
path,
width: imgWidth,
height: imgHeight,
);
},
),
Tooltip(
message: name,
Expand Down

0 comments on commit 0e1279c

Please sign in to comment.