Skip to content

Commit

Permalink
[Application] Added initial chart ascension stats bloc
Browse files Browse the repository at this point in the history
  • Loading branch information
Wolfteam committed May 18, 2022
1 parent 59887ac commit baf2740
Show file tree
Hide file tree
Showing 7 changed files with 199 additions and 9 deletions.
154 changes: 154 additions & 0 deletions lib/application/charts/ascension_stats/chart_ascension_stats_bloc.dart
@@ -0,0 +1,154 @@
import 'dart:math';

import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:shiori/domain/enums/enums.dart';
import 'package:shiori/domain/models/models.dart';
import 'package:shiori/domain/services/genshin_service.dart';

part 'chart_ascension_stats_bloc.freezed.dart';
part 'chart_ascension_stats_event.dart';
part 'chart_ascension_stats_state.dart';

const _firstPage = 1;

class ChartAscensionStatsBloc extends Bloc<ChartAscensionStatsEvent, ChartAscensionStatsState> {
final List<ChartAscensionStatModel> _characterAscensionStats;
final List<ChartAscensionStatModel> _weaponAscensionStats;

ChartAscensionStatsBloc(GenshinService genshinService)
: _characterAscensionStats = genshinService.getItemAscensionStatsForCharts(ItemType.character),
_weaponAscensionStats = genshinService.getItemAscensionStatsForCharts(ItemType.weapon),
super(const ChartAscensionStatsState.loading());

@override
Stream<ChartAscensionStatsState> mapEventToState(ChartAscensionStatsEvent event) async* {
final s = event.map(
init: (e) => _init(e.type, e.maxNumberOfColumns),
goToNextPage: (e) => state.maybeMap(
loaded: _goToNextPage,
orElse: () => throw Exception('Invalid state'),
),
goToPreviousPage: (e) => state.maybeMap(
loaded: _goToPreviousPage,
orElse: () => throw Exception('Invalid state'),
),
goToFirstPage: (e) => state.maybeMap(
loaded: (state) => _goToFirstOrLastPage(state, true),
orElse: () => throw Exception('Invalid state'),
),
goToLastPage: (e) => state.maybeMap(
loaded: (state) => _goToFirstOrLastPage(state, false),
orElse: () => throw Exception('Invalid state'),
),
);

yield s;
}

ChartAscensionStatsState _init(ItemType itemType, int maxNumberOfColumns) {
if (state.mapOrNull(loaded: (state) => state.itemType) == itemType) {
return state;
}

final ascensionStats = <ChartAscensionStatModel>[];
switch (itemType) {
case ItemType.character:
ascensionStats.addAll(_characterAscensionStats.take(maxNumberOfColumns));
break;
case ItemType.weapon:
ascensionStats.addAll(_weaponAscensionStats.take(maxNumberOfColumns));
break;
default:
throw Exception('ItemType = $itemType is not valid');
}

final maxPage = _getMaxPage(itemType, maxNumberOfColumns);
return ChartAscensionStatsState.loaded(
canGoToFirstPage: _canGoToFirstPage(_firstPage),
canGoToPreviousPage: _canGoToPreviousPage(_firstPage),
canGoToNextPage: _canGoToNextPage(_firstPage, maxPage),
canGoToLastPage: _canGoToLastPage(_firstPage, maxPage),
currentPage: _firstPage,
maxPage: _getMaxPage(itemType, maxNumberOfColumns),
maxNumberOfColumns: maxNumberOfColumns,
itemType: itemType,
maxCount: ascensionStats.map((e) => e.quantity).reduce(max),
ascensionStats: ascensionStats,
);
}

int _getMaxPage(ItemType itemType, int take) {
if (take <= 0) {
throw Exception('Take = $take is not valid');
}
double pages = 0;
switch (itemType) {
case ItemType.character:
pages = _characterAscensionStats.length / take;
break;
case ItemType.weapon:
pages = _weaponAscensionStats.length / take;
break;
default:
throw Exception('ItemType = $itemType is not valid');
}
return pages.ceil();
}

ChartAscensionStatsState _goToFirstOrLastPage(_LoadedState state, bool toFirstPage) {
final page = toFirstPage ? _firstPage : state.maxPage;
return _pageChanged(state, page);
}

ChartAscensionStatsState _goToNextPage(_LoadedState state) {
if (!_canGoToNextPage(state.currentPage, state.maxPage)) {
throw Exception('Cannot go to the next page');
}
final newPage = state.currentPage + 1;
return _pageChanged(state, newPage);
}

ChartAscensionStatsState _goToPreviousPage(_LoadedState state) {
if (!_canGoToPreviousPage(state.currentPage)) {
throw Exception('Cannot go to the previous page');
}
final newPage = state.currentPage - 1;
return _pageChanged(state, newPage);
}

ChartAscensionStatsState _pageChanged(_LoadedState state, int newPage) {
if (newPage < _firstPage) {
throw Exception('The newPage = $newPage cannot be less than $_firstPage');
}

final skip = state.maxNumberOfColumns * (newPage - 1);
final ascensionStats = <ChartAscensionStatModel>[];
switch (state.itemType) {
case ItemType.character:
ascensionStats.addAll(_characterAscensionStats.skip(skip).take(state.maxNumberOfColumns));
break;
case ItemType.weapon:
ascensionStats.addAll(_weaponAscensionStats.skip(skip).take(state.maxNumberOfColumns));
break;
default:
throw Exception('ItemType = ${state.itemType} is not valid');
}
return state.copyWith(
canGoToFirstPage: _canGoToFirstPage(newPage),
canGoToLastPage: _canGoToLastPage(newPage, state.maxPage),
canGoToNextPage: _canGoToNextPage(newPage, state.maxPage) && _canGoToLastPage(newPage, state.maxPage),
canGoToPreviousPage: _canGoToPreviousPage(newPage) && _canGoToFirstPage(newPage),
ascensionStats: ascensionStats,
currentPage: newPage,
);
}

bool _canGoToFirstPage(int currentPage) => currentPage > _firstPage;

bool _canGoToNextPage(int currentPage, int maxPage) => currentPage + 1 <= maxPage;

bool _canGoToPreviousPage(int currentPage) => currentPage - 1 >= _firstPage;

bool _canGoToLastPage(int currentPage, int maxPage) => currentPage < maxPage;
}
@@ -0,0 +1,17 @@
part of 'chart_ascension_stats_bloc.dart';

@freezed
class ChartAscensionStatsEvent with _$ChartAscensionStatsEvent {
const factory ChartAscensionStatsEvent.init({
required ItemType type,
required int maxNumberOfColumns,
}) = _Init;

const factory ChartAscensionStatsEvent.goToNextPage() = _GoToNextPage;

const factory ChartAscensionStatsEvent.goToPreviousPage() = _GoToPreviousPage;

const factory ChartAscensionStatsEvent.goToFirstPage() = _GoToFirstPage;

const factory ChartAscensionStatsEvent.goToLastPage() = _GoToLastPage;
}
@@ -0,0 +1,19 @@
part of 'chart_ascension_stats_bloc.dart';

@freezed
class ChartAscensionStatsState with _$ChartAscensionStatsState {
const factory ChartAscensionStatsState.loading() = _LoadingState;

const factory ChartAscensionStatsState.loaded({
required int currentPage,
required int maxPage,
required int maxNumberOfColumns,
required bool canGoToFirstPage,
required bool canGoToNextPage,
required bool canGoToPreviousPage,
required bool canGoToLastPage,
required ItemType itemType,
required int maxCount,
required List<ChartAscensionStatModel> ascensionStats,
}) = _LoadedState;
}
2 changes: 1 addition & 1 deletion lib/application/charts/birthdays/chart_birthdays_bloc.dart
Expand Up @@ -23,6 +23,6 @@ class ChartBirthdaysBloc extends Bloc<ChartBirthdaysEvent, ChartBirthdaysState>

Future<ChartBirthdaysState> _init() async {
final birthdays = _genshinService.getCharacterBirthdaysForCharts();
return ChartBirthdaysState.initial(birthdays: birthdays);
return ChartBirthdaysState.loaded(birthdays: birthdays);
}
}
Expand Up @@ -4,7 +4,7 @@ part of 'chart_birthdays_bloc.dart';
class ChartBirthdaysState with _$ChartBirthdaysState {
const factory ChartBirthdaysState.loading() = _LoadingState;

const factory ChartBirthdaysState.initial({
const factory ChartBirthdaysState.loaded({
required List<ChartBirthdayMonthModel> birthdays,
}) = _LoadedState;
}
12 changes: 6 additions & 6 deletions lib/application/charts/elements/chart_elements_bloc.dart
Expand Up @@ -70,7 +70,7 @@ class ChartElementsBloc extends Bloc<ChartElementsEvent, ChartElementsState> {
);
}

ChartElementsState _elementSelectionChanged(_InitialState state, ElementType type) {
ChartElementsState _elementSelectionChanged(_LoadedState state, ElementType type) {
final selectedTypes = [...state.selectedElementTypes];
if (selectedTypes.contains(type)) {
selectedTypes.remove(type);
Expand All @@ -84,9 +84,9 @@ class ChartElementsBloc extends Bloc<ChartElementsEvent, ChartElementsState> {
List<ChartElementItemModel> _getFilteredElements(List<ChartElementItemModel> elements, List<ElementType> selectedTypes) =>
selectedTypes.isEmpty ? elements : elements.where((el) => selectedTypes.contains(el.type)).toList();

double _getStep(_InitialState state) => state.maxNumberOfColumns * gameVersionIncrementsBy;
double _getStep(_LoadedState state) => state.maxNumberOfColumns * gameVersionIncrementsBy;

ChartElementsState _goToFirstOrLastPage(_InitialState state, bool toFirstPage) {
ChartElementsState _goToFirstOrLastPage(_LoadedState state, bool toFirstPage) {
final firstVersion = versions.first;
if (toFirstPage) {
return _newVersionChanged(state, firstVersion);
Expand All @@ -100,23 +100,23 @@ class ChartElementsBloc extends Bloc<ChartElementsEvent, ChartElementsState> {
return _newVersionChanged(state, possibleVersionA);
}

ChartElementsState _goToNextPage(_InitialState state) {
ChartElementsState _goToNextPage(_LoadedState state) {
if (!_canGoToNextPage(state.firstVersion)) {
throw Exception('Cannot go to the next page');
}
final newVersion = (state.firstVersion + gameVersionIncrementsBy).truncateToDecimalPlaces();
return _newVersionChanged(state, newVersion);
}

ChartElementsState _goToPreviousPage(_InitialState state) {
ChartElementsState _goToPreviousPage(_LoadedState state) {
if (!_canGoToPreviousPage(state.firstVersion)) {
throw Exception('Cannot go to the previous page');
}
final newVersion = (state.firstVersion - gameVersionIncrementsBy).truncateToDecimalPlaces();
return _newVersionChanged(state, newVersion);
}

ChartElementsState _newVersionChanged(_InitialState state, double newFirstVersion) {
ChartElementsState _newVersionChanged(_LoadedState state, double newFirstVersion) {
final step = _getStep(state);
double newLastVersion = (newFirstVersion + step).truncateToDecimalPlaces();

Expand Down
2 changes: 1 addition & 1 deletion lib/application/charts/elements/chart_elements_state.dart
Expand Up @@ -15,5 +15,5 @@ class ChartElementsState with _$ChartElementsState {
required bool canGoToPreviousPage,
required bool canGoToLastPage,
@Default(<ElementType>[]) List<ElementType> selectedElementTypes,
}) = _InitialState;
}) = _LoadedState;
}

0 comments on commit baf2740

Please sign in to comment.