Skip to content

Commit

Permalink
[Application] Added the crud logic for the team characters and weapons.
Browse files Browse the repository at this point in the history
The added weapons must be filtered by the character's weapon type
  • Loading branch information
Wolfteam committed Jan 19, 2022
1 parent b72c4b1 commit 26c0d75
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 19 deletions.
153 changes: 147 additions & 6 deletions lib/application/custom_build/custom_build_bloc.dart
Expand Up @@ -24,13 +24,21 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
CharacterSkillType.elementalBurst,
];
static List<CharacterSkillType> excludedSkillTypes = [CharacterSkillType.others];
static int maxNumberOfWeapons = 10;
static int maxNumberOfTeamCharacters = 10;

CustomBuildBloc(this._genshinService, this._dataService) : super(const CustomBuildState.loading()) {
on<CustomBuildEvent>(_handleEvent);
}

//TODO: REMOVE UPCOMING CHARACTERS ?
Future<void> _handleEvent(CustomBuildEvent event, Emitter<CustomBuildState> emit) async {
//todo: SHOULD I TRHOW ON INVALID REQUEST ?
//TODO: SHOULD I TRHOW ON INVALID REQUEST ?
//IN MOST CASES THERE ARE SOME VALIDATIONS FOR THINGS LIKE
// if (!state.weapons.any((el) => el.key == e.key)) {
// return state;
// }
// WHICH SHOULD NOT HAPPEN BUT MAYBE I SHOULD THROW AN EXCEPTION IN THERE
final s = await event.map(
load: (e) async => _init(e.key),
characterChanged: (e) async => state.maybeMap(
Expand All @@ -57,11 +65,18 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
loaded: (state) => _addWeapon(e, state),
orElse: () => state,
),
weaponRefinementChanged: (e) async => state.maybeMap(
loaded: (state) => _weaponRefinementChanged(e, state),
orElse: () => state,
),
weaponsOrderChanged: (e) async => state.maybeMap(
loaded: (state) => _weaponsOrderChanged(e, state),
orElse: () => state,
),
deleteWeapon: (e) async => state.maybeMap(
loaded: (state) => _deleteWeapon(e, state),
orElse: () => state,
),
weaponOrderChanged: (e) async => state,
addArtifact: (e) async => state.maybeMap(
loaded: (state) => _addArtifact(e, state),
orElse: () => state,
Expand Down Expand Up @@ -107,6 +122,22 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
loaded: (state) => _deleteArtifact(e, state),
orElse: () => state,
),
addTeamCharacter: (e) async => state.maybeMap(
loaded: (state) => _addTeamCharacter(e, state),
orElse: () => state,
),
teamCharactersOrderChanged: (e) async => state.maybeMap(
loaded: (state) => _teamCharactersOrderChanged(e, state),
orElse: () => state,
),
deleteTeamCharacter: (e) async => state.maybeMap(
loaded: (state) => _deleteTeamCharacter(e, state),
orElse: () => state,
),
deleteTeamCharacters: (e) async => state.maybeMap(
loaded: (state) => state.copyWith.call(teamCharacters: []),
orElse: () => state,
),
);

emit(s);
Expand All @@ -127,6 +158,7 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
notes: build.notes,
skillPriorities: build.skillPriorities,
artifacts: build.artifacts..sort((x, y) => x.type.index.compareTo(y.type.index)),
teamCharacters: build.teamCharacters,
subStatsSummary: _generateSubStatSummary(build.artifacts),
);
}
Expand All @@ -141,7 +173,8 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
character: character,
notes: [],
weapons: [],
artifacts: []..sort((x, y) => x.type.index.compareTo(y.type.index)),
artifacts: [],
teamCharacters: [],
skillPriorities: [],
subStatsSummary: [],
);
Expand Down Expand Up @@ -195,7 +228,56 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
throw Exception('Weapons cannot be repeated');
}
final weapon = _genshinService.getWeaponForCard(e.key);
final weapons = [...state.weapons, weapon];
final newOne = CustomBuildWeaponModel(
key: e.key,
index: state.weapons.length,
refinement: getWeaponMaxRefinementLevel(weapon.rarity) <= 0 ? 0 : 1,
name: weapon.name,
image: weapon.image,
rarity: weapon.rarity,
baseAtk: weapon.baseAtk,
subStatType: weapon.subStatType,
subStatValue: weapon.subStatValue,
);
final weapons = [...state.weapons, newOne];
return state.copyWith.call(weapons: weapons);
}

CustomBuildState _weaponsOrderChanged(_WeaponsOrderChanged e, _LoadedState state) {
final weapons = <CustomBuildWeaponModel>[];
for (var i = 0; i < e.weapons.length; i++) {
final sortableItem = e.weapons[i];
final current = state.weapons.firstWhereOrNull((el) => el.key == sortableItem.key);
if (current == null) {
throw Exception('Team Character with key = ${sortableItem.key} does not exist');
}
weapons.add(current.copyWith.call(index: i));
}

return state.copyWith.call(weapons: weapons);
}

CustomBuildState _weaponRefinementChanged(_WeaponRefinementChanged e, _LoadedState state) {
final current = state.weapons.firstWhereOrNull((el) => el.key == e.key);
if (current == null) {
return state;
}

if (current.refinement == e.newValue) {
return state;
}

final maxValue = getWeaponMaxRefinementLevel(current.rarity);
if (e.newValue > maxValue || e.newValue <= 0) {
throw Exception('The provided refinement = ${e.newValue} cannot exceed = $maxValue');
}

final index = state.weapons.indexOf(current);
final weapons = [...state.weapons];
weapons.removeAt(index);
final updated = current.copyWith.call(refinement: e.newValue);
weapons.insert(index, updated);

return state.copyWith.call(weapons: weapons);
}

Expand Down Expand Up @@ -271,6 +353,63 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
return state.copyWith.call(artifacts: updated, subStatsSummary: _generateSubStatSummary(updated));
}

CustomBuildState _addTeamCharacter(_AddTeamCharacter e, _LoadedState state) {
if (state.teamCharacters.length + 1 == maxNumberOfTeamCharacters) {
return state;
}

final char = _genshinService.getCharacterForCard(e.key);
final updatedTeamCharacters = [...state.teamCharacters];
final old = updatedTeamCharacters.firstWhereOrNull((el) => el.key == e.key);
if (old != null) {
final index = updatedTeamCharacters.indexOf(old);
updatedTeamCharacters.removeAt(index);
final updated = old.copyWith.call(
key: e.key,
image: char.image,
name: char.name,
roleType: e.roleType,
subType: e.subType,
);
updatedTeamCharacters.insert(index, updated);
} else {
final newOne = CustomBuildTeamCharacterModel(
key: e.key,
name: char.name,
image: char.image,
index: state.teamCharacters.length,
roleType: e.roleType,
subType: e.subType,
);
updatedTeamCharacters.add(newOne);
}
return state.copyWith.call(teamCharacters: updatedTeamCharacters);
}

CustomBuildState _teamCharactersOrderChanged(_TeamCharactersOrderChanged e, _LoadedState state) {
final teamCharacters = <CustomBuildTeamCharacterModel>[];
for (var i = 0; i < e.characters.length; i++) {
final sortableItem = e.characters[i];
final current = state.teamCharacters.firstWhereOrNull((el) => el.key == sortableItem.key);
if (current == null) {
throw Exception('Team Character with key = ${sortableItem.key} does not exist');
}
teamCharacters.add(current.copyWith.call(index: i));
}

return state.copyWith.call(teamCharacters: teamCharacters);
}

CustomBuildState _deleteTeamCharacter(_DeleteTeamCharacter e, _LoadedState state) {
if (!state.teamCharacters.any((el) => el.key == e.key)) {
return state;
}

final updated = [...state.teamCharacters];
updated.removeWhere((el) => el.key == e.key);
return state.copyWith.call(teamCharacters: updated);
}

Future<CustomBuildState> _saveChanges(_LoadedState state) async {
if (state.key != null) {
await _dataService.customBuilds.updateCustomBuild(
Expand All @@ -281,8 +420,9 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
state.showOnCharacterDetail,
state.isRecommended,
state.notes,
state.weapons.map((e) => e.key).toList(),
state.weapons,
[],
state.teamCharacters,
[],
);

Expand All @@ -296,9 +436,10 @@ class CustomBuildBloc extends Bloc<CustomBuildEvent, CustomBuildState> {
state.showOnCharacterDetail,
state.isRecommended,
state.notes,
state.weapons.map((e) => e.key).toList(),
state.weapons,
//TODO: THIS
[],
state.teamCharacters,
[],
);

Expand Down
33 changes: 25 additions & 8 deletions lib/application/custom_build/custom_build_event.dart
Expand Up @@ -16,11 +16,26 @@ class CustomBuildEvent with _$CustomBuildEvent {

const factory CustomBuildEvent.isRecommendedChanged({required bool newValue}) = _IsRecommendedChanged;

const factory CustomBuildEvent.addSkillPriority({required CharacterSkillType type}) = _AddSkillPriority;

const factory CustomBuildEvent.deleteSkillPriority({required int index}) = _DeleteSkillPriority;

const factory CustomBuildEvent.addNote({required String note}) = _AddNote;

const factory CustomBuildEvent.deleteNote({required int index}) = _DeleteNote;

const factory CustomBuildEvent.addWeapon({required String key}) = _AddWeapon;

const factory CustomBuildEvent.weaponRefinementChanged({
required String key,
required int newValue,
}) = _WeaponRefinementChanged;

const factory CustomBuildEvent.weaponsOrderChanged({required List<SortableItem> weapons}) = _WeaponsOrderChanged;

const factory CustomBuildEvent.deleteWeapon({required String key}) = _DeleteWeapon;

const factory CustomBuildEvent.weaponOrderChanged({required String key, required int newIndex}) = _WeaponOrderChanged;
const factory CustomBuildEvent.deleteWeapons() = _DeleteWeapons;

const factory CustomBuildEvent.addArtifact({
required String key,
Expand All @@ -35,17 +50,19 @@ class CustomBuildEvent with _$CustomBuildEvent {

const factory CustomBuildEvent.deleteArtifact({required ArtifactType type}) = _DeleteArtifact;

const factory CustomBuildEvent.addNote({required String note}) = _AddNote;

const factory CustomBuildEvent.deleteNote({required int index}) = _DeleteNote;
const factory CustomBuildEvent.deleteArtifacts() = _DeleteArtifacts;

const factory CustomBuildEvent.deleteWeapons() = _DeleteWeapons;
const factory CustomBuildEvent.addTeamCharacter({
required String key,
required CharacterRoleType roleType,
required CharacterRoleSubType subType,
}) = _AddTeamCharacter;

const factory CustomBuildEvent.deleteArtifacts() = _DeleteArtifacts;
const factory CustomBuildEvent.teamCharactersOrderChanged({required List<SortableItem> characters}) = _TeamCharactersOrderChanged;

const factory CustomBuildEvent.addSkillPriority({required CharacterSkillType type}) = _AddSkillPriority;
const factory CustomBuildEvent.deleteTeamCharacter({required String key}) = _DeleteTeamCharacter;

const factory CustomBuildEvent.deleteSkillPriority({required int index}) = _DeleteSkillPriority;
const factory CustomBuildEvent.deleteTeamCharacters() = _DeleteTeamCharacters;

const factory CustomBuildEvent.saveChanges() = _SaveChanges;

Expand Down
3 changes: 2 additions & 1 deletion lib/application/custom_build/custom_build_state.dart
Expand Up @@ -12,8 +12,9 @@ class CustomBuildState with _$CustomBuildState {
required bool showOnCharacterDetail,
required bool isRecommended,
required CharacterCardModel character,
required List<WeaponCardModel> weapons,
required List<CustomBuildWeaponModel> weapons,
required List<CustomBuildArtifactModel> artifacts,
required List<CustomBuildTeamCharacterModel> teamCharacters,
required List<CustomBuildNoteModel> notes,
required List<CharacterSkillType> skillPriorities,
required List<StatType> subStatsSummary,
Expand Down
14 changes: 12 additions & 2 deletions lib/application/weapons/weapons_bloc.dart
Expand Up @@ -22,7 +22,11 @@ class WeaponsBloc extends Bloc<WeaponsEvent, WeaponsState> {
@override
Stream<WeaponsState> mapEventToState(WeaponsEvent event) async* {
final s = event.map(
init: (e) => _buildInitialState(excludeKeys: e.excludeKeys, weaponTypes: WeaponType.values),
init: (e) => _buildInitialState(
excludeKeys: e.excludeKeys,
weaponTypes: e.weaponTypes.isEmpty ? WeaponType.values : e.weaponTypes,
areWeaponTypesEnabled: e.areWeaponTypesEnabled,
),
weaponFilterTypeChanged: (e) => currentState.copyWith.call(tempWeaponFilterType: e.filterType),
rarityChanged: (e) => currentState.copyWith.call(tempRarity: e.rarity),
sortDirectionTypeChanged: (e) => currentState.copyWith.call(tempSortDirectionType: e.sortDirectionType),
Expand All @@ -46,6 +50,7 @@ class WeaponsBloc extends Bloc<WeaponsEvent, WeaponsState> {
weaponSubStatType: currentState.weaponSubStatType,
locationType: currentState.weaponLocationType,
excludeKeys: currentState.excludeKeys,
areWeaponTypesEnabled: currentState.areWeaponTypesEnabled,
),
applyFilterChanges: (_) => _buildInitialState(
search: currentState.search,
Expand All @@ -56,6 +61,7 @@ class WeaponsBloc extends Bloc<WeaponsEvent, WeaponsState> {
weaponSubStatType: currentState.tempWeaponSubStatType,
locationType: currentState.tempWeaponLocationType,
excludeKeys: currentState.excludeKeys,
areWeaponTypesEnabled: currentState.areWeaponTypesEnabled,
),
cancelChanges: (_) => currentState.copyWith.call(
tempWeaponFilterType: currentState.weaponFilterType,
Expand All @@ -65,6 +71,7 @@ class WeaponsBloc extends Bloc<WeaponsEvent, WeaponsState> {
tempWeaponSubStatType: currentState.weaponSubStatType,
tempWeaponLocationType: currentState.weaponLocationType,
excludeKeys: currentState.excludeKeys,
areWeaponTypesEnabled: currentState.areWeaponTypesEnabled,
),
resetFilters: (_) => _buildInitialState(
excludeKeys: state.maybeMap(loaded: (state) => state.excludeKeys, orElse: () => []),
Expand All @@ -84,6 +91,7 @@ class WeaponsBloc extends Bloc<WeaponsEvent, WeaponsState> {
SortDirectionType sortDirectionType = SortDirectionType.asc,
StatType? weaponSubStatType,
ItemLocationType? locationType,
bool areWeaponTypesEnabled = true,
}) {
final isLoaded = state is _LoadedState;
var data = _genshinService.getWeaponsForCard();
Expand All @@ -92,7 +100,7 @@ class WeaponsBloc extends Bloc<WeaponsEvent, WeaponsState> {
}

if (!isLoaded) {
final selectedWeaponTypes = WeaponType.values.toList();
final selectedWeaponTypes = weaponTypes.isEmpty ? WeaponType.values.toList() : weaponTypes;
_sortData(data, weaponFilterType, sortDirectionType);
return WeaponsState.loaded(
weapons: data,
Expand All @@ -111,6 +119,7 @@ class WeaponsBloc extends Bloc<WeaponsEvent, WeaponsState> {
weaponLocationType: locationType,
tempWeaponLocationType: locationType,
excludeKeys: excludeKeys,
areWeaponTypesEnabled: areWeaponTypesEnabled,
);
}

Expand Down Expand Up @@ -152,6 +161,7 @@ class WeaponsBloc extends Bloc<WeaponsEvent, WeaponsState> {
weaponLocationType: locationType,
tempWeaponLocationType: locationType,
excludeKeys: excludeKeys,
areWeaponTypesEnabled: areWeaponTypesEnabled,
);
return s;
}
Expand Down
2 changes: 2 additions & 0 deletions lib/application/weapons/weapons_event.dart
Expand Up @@ -4,6 +4,8 @@ part of 'weapons_bloc.dart';
class WeaponsEvent with _$WeaponsEvent {
const factory WeaponsEvent.init({
@Default(<String>[]) List<String> excludeKeys,
@Default(<WeaponType>[]) List<WeaponType> weaponTypes,
@Default(true) bool areWeaponTypesEnabled,
}) = _Init;

const factory WeaponsEvent.searchChanged({
Expand Down
1 change: 1 addition & 0 deletions lib/application/weapons/weapons_state.dart
Expand Up @@ -20,5 +20,6 @@ class WeaponsState with _$WeaponsState {
ItemLocationType? weaponLocationType,
ItemLocationType? tempWeaponLocationType,
@Default(<String>[]) List<String> excludeKeys,
@Default(true) bool areWeaponTypesEnabled,
}) = _LoadedState;
}

0 comments on commit 26c0d75

Please sign in to comment.