Skip to content

Commit

Permalink
[Application] Double banner items were being shown in the version_det…
Browse files Browse the repository at this point in the history
…ails_dialog.dart
  • Loading branch information
Wolfteam committed May 6, 2022
1 parent 525db1d commit 7399dfb
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 42 deletions.
@@ -1,5 +1,6 @@
import 'package:bloc/bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:intl/intl.dart';
import 'package:shiori/domain/models/models.dart';
import 'package:shiori/domain/services/genshin_service.dart';
import 'package:shiori/domain/services/telemetry_service.dart';
Expand All @@ -12,6 +13,8 @@ class BannerHistoryItemBloc extends Bloc<BannerHistoryItemEvent, BannerHistoryIt
final GenshinService _genshinService;
final TelemetryService _telemetryService;

static const periodDateFormat = 'yyyy/MM/dd';

BannerHistoryItemBloc(this._genshinService, this._telemetryService) : super(const BannerHistoryItemState.loading());

@override
Expand All @@ -26,6 +29,31 @@ class BannerHistoryItemBloc extends Bloc<BannerHistoryItemEvent, BannerHistoryIt
Future<BannerHistoryItemState> _init(double version) async {
await _telemetryService.trackBannerHistoryItemOpened(version);
final banners = _genshinService.getBanners(version);
return BannerHistoryItemState.loadedState(version: version, items: banners);
final grouped = banners
.groupListsBy(
(el) => '${DateFormat(periodDateFormat).format(el.from)}_${DateFormat(periodDateFormat).format(el.until)}',
)
.values
.map(
(e) {
final group = e.first;
final items = e.expand((el) => el.items).toList();
final finalItems = <ItemCommonWithRarityAndType>[];
//this is to avoid duplicate items (e.g: on double banners like 2.4)
for (final item in items) {
if (finalItems.any((el) => el.key == item.key)) {
continue;
}
finalItems.add(item);
}

return BannerHistoryGroupedPeriodModel(
from: DateFormat(periodDateFormat).format(group.from),
until: DateFormat(periodDateFormat).format(group.until),
items: finalItems,
);
},
).toList();
return BannerHistoryItemState.loadedState(version: version, items: grouped);
}
}
Expand Up @@ -6,6 +6,6 @@ class BannerHistoryItemState with _$BannerHistoryItemState {

const factory BannerHistoryItemState.loadedState({
required double version,
required List<BannerHistoryPeriodModel> items,
required List<BannerHistoryGroupedPeriodModel> items,
}) = _LoadedState;
}
Expand Up @@ -14,3 +14,12 @@ class BannerHistoryPeriodModel with _$BannerHistoryPeriodModel {
required List<ItemCommonWithRarityAndType> items,
}) = _BannerHistoryPeriodModel;
}

@freezed
class BannerHistoryGroupedPeriodModel with _$BannerHistoryGroupedPeriodModel {
const factory BannerHistoryGroupedPeriodModel({
required String from,
required String until,
required List<ItemCommonWithRarityAndType> items,
}) = _BannerHistoryGroupedPeriodModel;
}
@@ -1,7 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:intl/intl.dart';
import 'package:shiori/application/bloc.dart';
import 'package:shiori/domain/enums/enums.dart';
import 'package:shiori/domain/models/models.dart';
Expand All @@ -13,8 +11,6 @@ import 'package:shiori/presentation/shared/images/circle_character.dart';
import 'package:shiori/presentation/shared/images/circle_weapon.dart';
import 'package:shiori/presentation/shared/loading.dart';

const _dateFormat = 'yyyy/MM/dd';

class VersionDetailsDialog extends StatelessWidget {
final double version;

Expand All @@ -38,20 +34,7 @@ class VersionDetailsDialog extends StatelessWidget {
builder: (context, state) => state.maybeMap(
loadedState: (state) => Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: state.items
.groupListsBy((el) => '${DateFormat(_dateFormat).format(el.from)}_${DateFormat(_dateFormat).format(el.until)}')
.values
.map(
(e) {
final group = e.first;

return _VersionDetailPeriod(
from: group.from,
until: group.until,
items: e.expand((el) => el.items).toList(),
);
},
).toList(),
children: state.items.map((e) => _VersionDetailPeriod(from: e.from, until: e.until, items: e.items)).toList(),
),
orElse: () => const Loading(useScaffold: false),
),
Expand All @@ -70,8 +53,8 @@ class VersionDetailsDialog extends StatelessWidget {
}

class _VersionDetailPeriod extends StatelessWidget {
final DateTime from;
final DateTime until;
final String from;
final String until;
final List<ItemCommonWithRarityAndType> items;

const _VersionDetailPeriod({
Expand All @@ -85,8 +68,6 @@ class _VersionDetailPeriod extends StatelessWidget {
Widget build(BuildContext context) {
final s = S.of(context);
final theme = Theme.of(context);
final from = DateFormat(_dateFormat).format(this.from);
final until = DateFormat(_dateFormat).format(this.until);
final characters = items.where((el) => el.type == ItemType.character).toList()..sort((x, y) => y.rarity.compareTo(x.rarity));
final weapons = items.where((el) => el.type == ItemType.weapon).toList()..sort((x, y) => y.rarity.compareTo(x.rarity));

Expand Down
@@ -1,5 +1,6 @@
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:intl/intl.dart';
import 'package:mockito/mockito.dart';
import 'package:shiori/application/bloc.dart';
import 'package:shiori/domain/enums/enums.dart';
Expand Down Expand Up @@ -37,28 +38,43 @@ void main() {
);

group('Init', () {
void _validVersionCheck(BannerHistoryItemState state, double version) => state.map(
loading: (_) => throw Exception('Invalid state'),
loadedState: (state) {
final validItemTypes = [ItemType.character, ItemType.weapon];
expect(state.version, version);
expect(state.items.isNotEmpty, isTrue);
for (final grouped in state.items) {
final from = DateFormat(BannerHistoryItemBloc.periodDateFormat).parse(grouped.from);
final until = DateFormat(BannerHistoryItemBloc.periodDateFormat).parse(grouped.until);
expect(until.isAfter(from), isTrue);
expect(grouped.items.isNotEmpty, isTrue);

final keys = grouped.items.map((e) => e.key).toList();
expect(keys.toSet().length == keys.length, isTrue);

for (final group in grouped.items) {
checkItemKeyAndImage(group.key, group.image);
expect(group.rarity >= 4, isTrue);
expect(validItemTypes.contains(group.type), isTrue);
}
}
return null;
},
);

blocTest<BannerHistoryItemBloc, BannerHistoryItemState>(
'valid version',
build: () => BannerHistoryItemBloc(_genshinService, _telemetryService),
act: (bloc) => bloc.add(const BannerHistoryItemEvent.init(version: 1.1)),
verify: (bloc) => bloc.state.map(
loading: (_) => throw Exception('Invalid state'),
loadedState: (state) {
final validItemTypes = [ItemType.character, ItemType.weapon];
expect(state.version, 1.1);
expect(state.items.isNotEmpty, isTrue);
for (final item in state.items) {
expect(item.until.isAfter(item.from), isTrue);
expect(item.version >= 1, isTrue);
expect(BannerHistoryItemType.values.contains(item.type), isTrue);
for (final el in item.items) {
checkItemKeyAndImage(el.key, el.image);
expect(el.rarity >= 4, isTrue);
expect(validItemTypes.contains(el.type), isTrue);
}
}
},
),
verify: (bloc) => _validVersionCheck(bloc.state, 1.1),
);

blocTest<BannerHistoryItemBloc, BannerHistoryItemState>(
'valid version, double banner',
build: () => BannerHistoryItemBloc(_genshinService, _telemetryService),
act: (bloc) => bloc.add(const BannerHistoryItemEvent.init(version: 2.4)),
verify: (bloc) => _validVersionCheck(bloc.state, 2.4),
);

blocTest<BannerHistoryItemBloc, BannerHistoryItemState>(
Expand Down
4 changes: 4 additions & 0 deletions test/infrastructure/genshin_service_test.dart
Expand Up @@ -892,6 +892,10 @@ void main() {
expect(banner.version, version);
expect(banner.until.isAfter(banner.from), isTrue);
expect(banner.items.isNotEmpty, isTrue);

final keys = banner.items.map((e) => e.key).toList();
expect(keys.toSet().length == keys.length, isTrue);

for (final item in banner.items) {
checkItemKeyAndImage(item.key, item.image);
expect(item.rarity >= 4, isTrue);
Expand Down

0 comments on commit 7399dfb

Please sign in to comment.