Skip to content

Commit

Permalink
[Application] Created multiple chart blocs.
Browse files Browse the repository at this point in the history
  • Loading branch information
Wolfteam committed May 9, 2022
1 parent 68aa60e commit 0a5f47a
Show file tree
Hide file tree
Showing 17 changed files with 315 additions and 100 deletions.
5 changes: 4 additions & 1 deletion lib/application/bloc.dart
Expand Up @@ -13,7 +13,10 @@ export 'calculator_asc_materials/sessions_order/calculator_asc_materials_session
export 'changelog/changelog_bloc.dart';
export 'character/character_bloc.dart';
export 'characters/characters_bloc.dart';
export 'charts/charts_bloc.dart';
export 'charts/birthdays/chart_birthdays_bloc.dart';
export 'charts/elements/chart_elements_bloc.dart';
export 'charts/elements/chart_elements_bloc.dart';
export 'charts/tops/chart_tops_bloc.dart';
export 'custom_build/custom_build_bloc.dart';
export 'custom_builds/custom_builds_bloc.dart';
export 'donations/donations_bloc.dart';
Expand Down
28 changes: 28 additions & 0 deletions lib/application/charts/birthdays/chart_birthdays_bloc.dart
@@ -0,0 +1,28 @@
import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:shiori/domain/models/models.dart';
import 'package:shiori/domain/services/genshin_service.dart';

part 'chart_birthdays_bloc.freezed.dart';
part 'chart_birthdays_event.dart';
part 'chart_birthdays_state.dart';

class ChartBirthdaysBloc extends Bloc<ChartBirthdaysEvent, ChartBirthdaysState> {
final GenshinService _genshinService;

ChartBirthdaysBloc(this._genshinService) : super(const ChartBirthdaysState.loading());

@override
Stream<ChartBirthdaysState> mapEventToState(ChartBirthdaysEvent event) async* {
final s = await event.map(
init: (e) async => _init(),
);

yield s;
}

Future<ChartBirthdaysState> _init() async {
final birthdays = _genshinService.getCharacterBirthdaysForCharts();
return ChartBirthdaysState.initial(birthdays: birthdays);
}
}
6 changes: 6 additions & 0 deletions lib/application/charts/birthdays/chart_birthdays_event.dart
@@ -0,0 +1,6 @@
part of 'chart_birthdays_bloc.dart';

@freezed
class ChartBirthdaysEvent with _$ChartBirthdaysEvent {
const factory ChartBirthdaysEvent.init() = _Init;
}
10 changes: 10 additions & 0 deletions lib/application/charts/birthdays/chart_birthdays_state.dart
@@ -0,0 +1,10 @@
part of 'chart_birthdays_bloc.dart';

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

const factory ChartBirthdaysState.initial({
required List<ChartBirthdayMonthModel> birthdays,
}) = _LoadedState;
}
69 changes: 0 additions & 69 deletions lib/application/charts/charts_bloc.dart

This file was deleted.

10 changes: 0 additions & 10 deletions lib/application/charts/charts_event.dart

This file was deleted.

14 changes: 0 additions & 14 deletions lib/application/charts/charts_state.dart

This file was deleted.

156 changes: 156 additions & 0 deletions lib/application/charts/elements/chart_elements_bloc.dart
@@ -0,0 +1,156 @@
import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:shiori/domain/app_constants.dart';
import 'package:shiori/domain/enums/enums.dart';
import 'package:shiori/domain/extensions/double_extensions.dart';
import 'package:shiori/domain/models/models.dart';
import 'package:shiori/domain/services/genshin_service.dart';

part 'chart_elements_bloc.freezed.dart';
part 'chart_elements_event.dart';
part 'chart_elements_state.dart';

class ChartElementsBloc extends Bloc<ChartElementsEvent, ChartElementsState> {
final GenshinService _genshinService;
final List<double> versions;

ChartElementsBloc(this._genshinService)
: versions = _genshinService.getBannerHistoryVersions(SortDirectionType.asc),
super(const ChartElementsState.loading());

@override
Stream<ChartElementsState> mapEventToState(ChartElementsEvent event) async* {
final s = event.map(
init: (e) => _init(e.maxNumberOfColumns),
elementSelected: (e) => state.maybeMap(
loaded: (state) => _elementSelectionChanged(state, e.type),
orElse: () => throw Exception('Invalid state'),
),
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;
}

//Some versions were skipped (e.g: 1.7, 1.8, 1.9), that's why we use this function
//to determine if the version can be skipped or no
bool isValidVersion(double value) {
return versions.contains(value.truncateToDecimalPlaces());
}

ChartElementsState _init(int maxNumberOfColumns) {
final firstVersion = versions.first;
final lastVersion = versions.first + (maxNumberOfColumns / 10);
final elements = _genshinService.getElementsForCharts(firstVersion, lastVersion);
return ChartElementsState.loaded(
maxNumberOfColumns: maxNumberOfColumns,
firstVersion: firstVersion,
lastVersion: lastVersion,
elements: elements,
filteredElements: elements,
canGoToFirstPage: _canGoToFirstPage(firstVersion),
canGoToLastPage: _canGoToLastPage(firstVersion),
canGoToNextPage: _canGoToNextPage(firstVersion),
canGoToPreviousPage: _canGoToPreviousPage(firstVersion),
);
}

ChartElementsState _elementSelectionChanged(_InitialState state, ElementType type) {
final selectedTypes = [...state.selectedElementTypes];
if (selectedTypes.contains(type)) {
selectedTypes.remove(type);
} else {
selectedTypes.add(type);
}

return state.copyWith(selectedElementTypes: selectedTypes, filteredElements: _getFilteredElements(state.elements, selectedTypes));
}

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;

ChartElementsState _goToFirstOrLastPage(_InitialState state, bool toFirstPage) {
final firstVersion = versions.first;
if (toFirstPage) {
return _newVersionChanged(state, firstVersion);
}

final possibleVersionA = (firstVersion + _getStep(state)).truncateToDecimalPlaces();
final possibleVersionB = (versions.last - _getStep(state)).truncateToDecimalPlaces();
if (possibleVersionA > possibleVersionB && possibleVersionB > firstVersion) {
return _newVersionChanged(state, possibleVersionB);
}
return _newVersionChanged(state, possibleVersionA);
}

ChartElementsState _goToNextPage(_InitialState 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) {
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) {
final step = _getStep(state);
double newLastVersion = (newFirstVersion + step).truncateToDecimalPlaces();

if (newLastVersion > versions.last) {
newLastVersion = versions.last;
}
if (newFirstVersion < versions.first) {
throw Exception('First version = $newFirstVersion cannot be greater than = ${versions.first}');
}

if (newLastVersion > versions.last) {
throw Exception('Last version = $newLastVersion cannot be greater than = ${versions.last}');
}

assert(newFirstVersion != newLastVersion, 'New and last version cannot be equal');

final elements = _genshinService.getElementsForCharts(newFirstVersion, newLastVersion);
return state.copyWith(
elements: elements,
filteredElements: _getFilteredElements(elements, state.selectedElementTypes),
firstVersion: newFirstVersion,
lastVersion: newLastVersion,
canGoToFirstPage: _canGoToFirstPage(newFirstVersion),
canGoToLastPage: _canGoToLastPage(newLastVersion),
canGoToNextPage: _canGoToNextPage(newFirstVersion) && _canGoToLastPage(newLastVersion),
canGoToPreviousPage: _canGoToPreviousPage(newFirstVersion) && _canGoToFirstPage(newFirstVersion),
);
}

bool _canGoToFirstPage(double version) => version > versions.first;

bool _canGoToNextPage(double version) => version + gameVersionIncrementsBy <= versions.last;

bool _canGoToPreviousPage(double version) => version - gameVersionIncrementsBy >= versions.first;

bool _canGoToLastPage(double version) => version < versions.last;
}
20 changes: 20 additions & 0 deletions lib/application/charts/elements/chart_elements_event.dart
@@ -0,0 +1,20 @@
part of 'chart_elements_bloc.dart';

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

const factory ChartElementsEvent.elementSelected({
required ElementType type,
}) = _ElementSelected;

const factory ChartElementsEvent.goToNextPage() = _GoToNextPage;

const factory ChartElementsEvent.goToPreviousPage() = _GoToPreviousPage;

const factory ChartElementsEvent.goToFirstPage() = _GoToFirstPage;

const factory ChartElementsEvent.goToLastPage() = _GoToLastPage;
}
19 changes: 19 additions & 0 deletions lib/application/charts/elements/chart_elements_state.dart
@@ -0,0 +1,19 @@
part of 'chart_elements_bloc.dart';

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

const factory ChartElementsState.loaded({
required int maxNumberOfColumns,
required double firstVersion,
required double lastVersion,
required List<ChartElementItemModel> elements,
required List<ChartElementItemModel> filteredElements,
required bool canGoToFirstPage,
required bool canGoToNextPage,
required bool canGoToPreviousPage,
required bool canGoToLastPage,
@Default(<ElementType>[]) List<ElementType> selectedElementTypes,
}) = _InitialState;
}
41 changes: 41 additions & 0 deletions lib/application/charts/tops/chart_tops_bloc.dart
@@ -0,0 +1,41 @@
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';
import 'package:shiori/domain/services/telemetry_service.dart';

part 'chart_tops_bloc.freezed.dart';
part 'chart_tops_event.dart';
part 'chart_tops_state.dart';

class ChartTopsBloc extends Bloc<ChartTopsEvent, ChartTopsState> {
final GenshinService _genshinService;
final TelemetryService _telemetryService;

ChartTopsBloc(this._genshinService, this._telemetryService) : super(const ChartTopsState.loading());

@override
Stream<ChartTopsState> mapEventToState(ChartTopsEvent event) async* {
final s = await event.map(
init: (e) async => _init(),
);

yield s;
}

Future<ChartTopsState> _init() async {
await _telemetryService.trackChartsOpened();
final tops = [
..._genshinService.getTopCharts(ChartType.topFiveStarCharacterMostReruns),
..._genshinService.getTopCharts(ChartType.topFiveStarCharacterLeastReruns),
..._genshinService.getTopCharts(ChartType.topFiveStarWeaponMostReruns),
..._genshinService.getTopCharts(ChartType.topFiveStarWeaponLeastReruns),
..._genshinService.getTopCharts(ChartType.topFourStarCharacterMostReruns),
..._genshinService.getTopCharts(ChartType.topFourStarCharacterLeastReruns),
..._genshinService.getTopCharts(ChartType.topFourStarWeaponMostReruns),
..._genshinService.getTopCharts(ChartType.topFourStarWeaponLeastReruns),
];
return ChartTopsState.loaded(tops: tops);
}
}

0 comments on commit 0a5f47a

Please sign in to comment.