自动释放资源
This commit is contained in:
parent
a122935747
commit
539edffcfe
@ -10,6 +10,7 @@ class SCRoomRocketLevelRes {
|
|||||||
required this.shakeThresholdPercent,
|
required this.shakeThresholdPercent,
|
||||||
required this.enabled,
|
required this.enabled,
|
||||||
required this.sort,
|
required this.sort,
|
||||||
|
this.rewards = const <SCRoomRocketRewardRes>[],
|
||||||
this.rewardPreview,
|
this.rewardPreview,
|
||||||
this.rocketKings = const <SCRoomRocketKingUserRes>[],
|
this.rocketKings = const <SCRoomRocketKingUserRes>[],
|
||||||
});
|
});
|
||||||
@ -194,6 +195,7 @@ class SCRoomRocketLevelRes {
|
|||||||
95,
|
95,
|
||||||
enabled: _boolValue(data['enabled'], fallback: true),
|
enabled: _boolValue(data['enabled'], fallback: true),
|
||||||
sort: _intValue(data['sort']),
|
sort: _intValue(data['sort']),
|
||||||
|
rewards: SCRoomRocketRewardPreviewRes._rewardList(data['rewards']),
|
||||||
rewardPreview: SCRoomRocketRewardPreviewRes.tryFromJson(
|
rewardPreview: SCRoomRocketRewardPreviewRes.tryFromJson(
|
||||||
_firstPayload([
|
_firstPayload([
|
||||||
data['rewardPreview'],
|
data['rewardPreview'],
|
||||||
@ -241,6 +243,7 @@ class SCRoomRocketLevelRes {
|
|||||||
final num shakeThresholdPercent;
|
final num shakeThresholdPercent;
|
||||||
final bool enabled;
|
final bool enabled;
|
||||||
final int sort;
|
final int sort;
|
||||||
|
final List<SCRoomRocketRewardRes> rewards;
|
||||||
final SCRoomRocketRewardPreviewRes? rewardPreview;
|
final SCRoomRocketRewardPreviewRes? rewardPreview;
|
||||||
final List<SCRoomRocketKingUserRes> rocketKings;
|
final List<SCRoomRocketKingUserRes> rocketKings;
|
||||||
|
|
||||||
@ -256,6 +259,7 @@ class SCRoomRocketLevelRes {
|
|||||||
'shakeThresholdPercent': shakeThresholdPercent,
|
'shakeThresholdPercent': shakeThresholdPercent,
|
||||||
'enabled': enabled,
|
'enabled': enabled,
|
||||||
'sort': sort,
|
'sort': sort,
|
||||||
|
'rewards': rewards.map((item) => item.toJson()).toList(),
|
||||||
'rewardPreview':
|
'rewardPreview':
|
||||||
rewardPreview == null
|
rewardPreview == null
|
||||||
? null
|
? null
|
||||||
@ -270,6 +274,71 @@ class SCRoomRocketLevelRes {
|
|||||||
'rocketKings': rocketKings.map((item) => item.toJson()).toList(),
|
'rocketKings': rocketKings.map((item) => item.toJson()).toList(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static List<SCRoomRocketLevelRes> listFromJson(dynamic value) {
|
||||||
|
if (value is! Iterable || value is String) {
|
||||||
|
return const <SCRoomRocketLevelRes>[];
|
||||||
|
}
|
||||||
|
return value.map(SCRoomRocketLevelRes.fromJson).toList(growable: false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SCRoomRocketLevelContentsRes {
|
||||||
|
SCRoomRocketLevelContentsRes({
|
||||||
|
required this.configured,
|
||||||
|
required this.sysOrigin,
|
||||||
|
required this.enabled,
|
||||||
|
required this.timezone,
|
||||||
|
required this.maxLevel,
|
||||||
|
required this.levels,
|
||||||
|
required this.updateTime,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory SCRoomRocketLevelContentsRes.fromJson(dynamic json) {
|
||||||
|
final data = _asMap(json);
|
||||||
|
return SCRoomRocketLevelContentsRes(
|
||||||
|
configured: _boolValue(data['configured']),
|
||||||
|
sysOrigin: _stringValue(data['sysOrigin']),
|
||||||
|
enabled: _boolValue(data['enabled']),
|
||||||
|
timezone: _stringValue(data['timezone'] ?? data['timeZone']),
|
||||||
|
maxLevel: _intValue(data['maxLevel']),
|
||||||
|
levels: SCRoomRocketLevelRes.listFromJson(data['levels']),
|
||||||
|
updateTime: _stringValue(data['updateTime']),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final bool configured;
|
||||||
|
final String sysOrigin;
|
||||||
|
final bool enabled;
|
||||||
|
final String timezone;
|
||||||
|
final int maxLevel;
|
||||||
|
final List<SCRoomRocketLevelRes> levels;
|
||||||
|
final String updateTime;
|
||||||
|
|
||||||
|
SCRoomRocketLevelRes? levelFor(int level) {
|
||||||
|
for (final item in levels) {
|
||||||
|
if (item.level == level) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCRoomRocketRewardPreviewRes? rewardPreviewForLevel(int level) {
|
||||||
|
return levelFor(level)?.rewardPreview;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {
|
||||||
|
'configured': configured,
|
||||||
|
'sysOrigin': sysOrigin,
|
||||||
|
'enabled': enabled,
|
||||||
|
'timezone': timezone,
|
||||||
|
'maxLevel': maxLevel,
|
||||||
|
'levels': levels.map((item) => item.toJson()).toList(),
|
||||||
|
'updateTime': updateTime,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SCRoomRocketRewardRes {
|
class SCRoomRocketRewardRes {
|
||||||
|
|||||||
@ -202,7 +202,10 @@ abstract class SocialChatRoomRepository {
|
|||||||
});
|
});
|
||||||
|
|
||||||
///查询房间火箭状态
|
///查询房间火箭状态
|
||||||
Future<SCRoomRocketStatusRes> rocketStatus(String roomId, {int? level});
|
Future<SCRoomRocketStatusRes> rocketStatus(String roomId, {int? level});
|
||||||
|
|
||||||
|
///查询火箭等级内容
|
||||||
|
Future<SCRoomRocketLevelContentsRes> roomRocketLevelContents();
|
||||||
|
|
||||||
///查询火箭王榜单
|
///查询火箭王榜单
|
||||||
Future<SCRoomRocketKingRes> roomRocketKing(
|
Future<SCRoomRocketKingRes> roomRocketKing(
|
||||||
|
|||||||
@ -1027,6 +1027,23 @@ class SCChatRoomRepository implements SocialChatRoomRepository {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///go/app/voice-room/rocket/level-contents
|
||||||
|
@override
|
||||||
|
Future<SCRoomRocketLevelContentsRes> roomRocketLevelContents() async {
|
||||||
|
const path = "/go/app/voice-room/rocket/level-contents";
|
||||||
|
_rocketApiDebug('request GET $path');
|
||||||
|
final result = await http.get<SCRoomRocketLevelContentsRes>(
|
||||||
|
path,
|
||||||
|
extra: {BaseNetworkClient.silentErrorToastKey: true},
|
||||||
|
fromJson: (json) {
|
||||||
|
_rocketApiDebug('GET $path', raw: json);
|
||||||
|
return SCRoomRocketLevelContentsRes.fromJson(json);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
_rocketApiDebug('parsed $path', result: result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
///go/app/voice-room/rocket/king
|
///go/app/voice-room/rocket/king
|
||||||
@override
|
@override
|
||||||
Future<SCRoomRocketKingRes> roomRocketKing(
|
Future<SCRoomRocketKingRes> roomRocketKing(
|
||||||
|
|||||||
@ -13,7 +13,18 @@ class RoomRocketApiMapper {
|
|||||||
static List<RoomRocketLevelItem>? levelsFromStatus(
|
static List<RoomRocketLevelItem>? levelsFromStatus(
|
||||||
SCRoomRocketStatusRes? status,
|
SCRoomRocketStatusRes? status,
|
||||||
) {
|
) {
|
||||||
final levels = status?.levels;
|
return levelsFromApiLevels(status?.levels);
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<RoomRocketLevelItem>? levelsFromLevelContents(
|
||||||
|
SCRoomRocketLevelContentsRes? contents,
|
||||||
|
) {
|
||||||
|
return levelsFromApiLevels(contents?.levels);
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<RoomRocketLevelItem>? levelsFromApiLevels(
|
||||||
|
List<SCRoomRocketLevelRes>? levels,
|
||||||
|
) {
|
||||||
if (levels == null || levels.isEmpty) {
|
if (levels == null || levels.isEmpty) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -65,6 +76,26 @@ class RoomRocketApiMapper {
|
|||||||
return rewardGroupsFromPreview(preview);
|
return rewardGroupsFromPreview(preview);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static RoomRocketRewardGroups? rewardGroupsFromLevelContents(
|
||||||
|
SCRoomRocketLevelContentsRes? contents, {
|
||||||
|
required int level,
|
||||||
|
}) {
|
||||||
|
return rewardGroupsFromPreview(contents?.rewardPreviewForLevel(level));
|
||||||
|
}
|
||||||
|
|
||||||
|
static Map<int, RoomRocketRewardGroups> rewardGroupsByLevelFromLevelContents(
|
||||||
|
SCRoomRocketLevelContentsRes? contents,
|
||||||
|
) {
|
||||||
|
final result = <int, RoomRocketRewardGroups>{};
|
||||||
|
for (final item in contents?.levels ?? const <SCRoomRocketLevelRes>[]) {
|
||||||
|
final groups = rewardGroupsFromPreview(item.rewardPreview);
|
||||||
|
if (groups != null) {
|
||||||
|
result[item.level] = groups;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static RoomRocketRewardGroups? rewardGroupsFromPreview(
|
static RoomRocketRewardGroups? rewardGroupsFromPreview(
|
||||||
SCRoomRocketRewardPreviewRes? preview,
|
SCRoomRocketRewardPreviewRes? preview,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -350,6 +350,7 @@ class _RoomRocketDialogLoader extends StatefulWidget {
|
|||||||
|
|
||||||
class _RoomRocketDialogLoaderState extends State<_RoomRocketDialogLoader> {
|
class _RoomRocketDialogLoaderState extends State<_RoomRocketDialogLoader> {
|
||||||
SCRoomRocketStatusRes? _status;
|
SCRoomRocketStatusRes? _status;
|
||||||
|
SCRoomRocketLevelContentsRes? _levelContents;
|
||||||
List<RoomRocketNoteSection>? _noteSections;
|
List<RoomRocketNoteSection>? _noteSections;
|
||||||
Map<int, RoomRocketRewardGroups> _configRewardGroupsByLevel = {};
|
Map<int, RoomRocketRewardGroups> _configRewardGroupsByLevel = {};
|
||||||
final Map<int, RoomRocketRewardGroups> _statusRewardGroupsByLevel = {};
|
final Map<int, RoomRocketRewardGroups> _statusRewardGroupsByLevel = {};
|
||||||
@ -421,7 +422,31 @@ class _RoomRocketDialogLoaderState extends State<_RoomRocketDialogLoader> {
|
|||||||
|
|
||||||
Future<void> _loadConfigs() async {
|
Future<void> _loadConfigs() async {
|
||||||
try {
|
try {
|
||||||
_rocketUiDebug('request enabled rocket configs');
|
_rocketUiDebug('request rocket level contents');
|
||||||
|
final contents = await SCChatRoomRepository().roomRocketLevelContents();
|
||||||
|
if (!mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final groups = RoomRocketApiMapper.rewardGroupsByLevelFromLevelContents(
|
||||||
|
contents,
|
||||||
|
);
|
||||||
|
setState(() {
|
||||||
|
_levelContents = contents;
|
||||||
|
_configRewardGroupsByLevel = groups;
|
||||||
|
});
|
||||||
|
_rocketUiDebug(
|
||||||
|
'rocket level contents loaded levels=${contents.levels.length} '
|
||||||
|
'rewardLevels=${groups.keys.toList()}',
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
_rocketUiDebug('rocket level contents request failed: $error');
|
||||||
|
unawaited(_loadLegacyConfigs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _loadLegacyConfigs() async {
|
||||||
|
try {
|
||||||
|
_rocketUiDebug('request legacy enabled rocket configs');
|
||||||
final configs = await SCChatRoomRepository().rocketConfigEnabled();
|
final configs = await SCChatRoomRepository().rocketConfigEnabled();
|
||||||
if (!mounted) {
|
if (!mounted) {
|
||||||
return;
|
return;
|
||||||
@ -433,10 +458,10 @@ class _RoomRocketDialogLoaderState extends State<_RoomRocketDialogLoader> {
|
|||||||
_configRewardGroupsByLevel = groups;
|
_configRewardGroupsByLevel = groups;
|
||||||
});
|
});
|
||||||
_rocketUiDebug(
|
_rocketUiDebug(
|
||||||
'rocket configs loaded rewardLevels=${groups.keys.toList()}',
|
'legacy rocket configs loaded rewardLevels=${groups.keys.toList()}',
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
_rocketUiDebug('rocket configs request failed: $error');
|
_rocketUiDebug('legacy rocket configs request failed: $error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -456,10 +481,15 @@ class _RoomRocketDialogLoaderState extends State<_RoomRocketDialogLoader> {
|
|||||||
final rewardGroups =
|
final rewardGroups =
|
||||||
selectedLevelNumber == currentLevelNumber
|
selectedLevelNumber == currentLevelNumber
|
||||||
? _mergeRewardGroups(rewardGroupsFromStatus, configRewardGroups)
|
? _mergeRewardGroups(rewardGroupsFromStatus, configRewardGroups)
|
||||||
: rewardGroupsFromStatus ?? const RoomRocketRewardGroups();
|
: rewardGroupsFromStatus ??
|
||||||
|
configRewardGroups ??
|
||||||
|
const RoomRocketRewardGroups();
|
||||||
|
final levelItems =
|
||||||
|
RoomRocketApiMapper.levelsFromLevelContents(_levelContents) ??
|
||||||
|
RoomRocketApiMapper.levelsFromStatus(status);
|
||||||
return RoomRocketDialog(
|
return RoomRocketDialog(
|
||||||
status: status,
|
status: status,
|
||||||
levels: RoomRocketApiMapper.levelsFromStatus(status),
|
levels: levelItems,
|
||||||
selectedLevel: selectedLevel,
|
selectedLevel: selectedLevel,
|
||||||
onLevelSelected: _onLevelSelected,
|
onLevelSelected: _onLevelSelected,
|
||||||
rewards:
|
rewards:
|
||||||
@ -555,6 +585,7 @@ class _RoomRocketDialogLoaderState extends State<_RoomRocketDialogLoader> {
|
|||||||
Future<void> _loadRewardForLevel(int level) async {
|
Future<void> _loadRewardForLevel(int level) async {
|
||||||
final normalizedLevel = level.clamp(1, 99).toInt();
|
final normalizedLevel = level.clamp(1, 99).toInt();
|
||||||
if (_statusRewardGroupsByLevel.containsKey(normalizedLevel) ||
|
if (_statusRewardGroupsByLevel.containsKey(normalizedLevel) ||
|
||||||
|
_configRewardGroupsByLevel.containsKey(normalizedLevel) ||
|
||||||
_loadingRewardLevels.contains(normalizedLevel)) {
|
_loadingRewardLevels.contains(normalizedLevel)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -493,10 +493,7 @@ class _RoomRocketPagViewState extends State<_RoomRocketPagView> {
|
|||||||
|
|
||||||
void _scheduleMemoryRelease(String path) {
|
void _scheduleMemoryRelease(String path) {
|
||||||
_memoryReleaseTimer?.cancel();
|
_memoryReleaseTimer?.cancel();
|
||||||
if (widget.memoryTtl <= Duration.zero) {
|
_memoryReleaseTimer = _schedulePagMemoryReleaseTimer(widget.memoryTtl, () {
|
||||||
return;
|
|
||||||
}
|
|
||||||
_memoryReleaseTimer = Timer(widget.memoryTtl, () {
|
|
||||||
if (!mounted || widget.resource.trim() != path || _pagBytes == null) {
|
if (!mounted || widget.resource.trim() != path || _pagBytes == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -572,6 +569,24 @@ Duration debugRoomRocketPagMemoryTtl() {
|
|||||||
return _pagMemoryTtl;
|
return _pagMemoryTtl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@visibleForTesting
|
||||||
|
Timer? debugScheduleRoomRocketPagMemoryRelease({
|
||||||
|
Duration memoryTtl = _pagMemoryTtl,
|
||||||
|
required VoidCallback onRelease,
|
||||||
|
}) {
|
||||||
|
return _schedulePagMemoryReleaseTimer(memoryTtl, onRelease);
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer? _schedulePagMemoryReleaseTimer(
|
||||||
|
Duration memoryTtl,
|
||||||
|
VoidCallback onRelease,
|
||||||
|
) {
|
||||||
|
if (memoryTtl <= Duration.zero) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return Timer(memoryTtl, onRelease);
|
||||||
|
}
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
String debugNormalizeRoomRocketPagResource(String resource) {
|
String debugNormalizeRoomRocketPagResource(String resource) {
|
||||||
return _normalizePagResource(resource);
|
return _normalizePagResource(resource);
|
||||||
|
|||||||
@ -45,4 +45,17 @@ void main() {
|
|||||||
test('keeps pag bytes in memory for five minutes by default', () {
|
test('keeps pag bytes in memory for five minutes by default', () {
|
||||||
expect(debugRoomRocketPagMemoryTtl(), const Duration(minutes: 5));
|
expect(debugRoomRocketPagMemoryTtl(), const Duration(minutes: 5));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('releases pag bytes when the configured ttl expires', () async {
|
||||||
|
var released = false;
|
||||||
|
final timer = debugScheduleRoomRocketPagMemoryRelease(
|
||||||
|
memoryTtl: const Duration(milliseconds: 10),
|
||||||
|
onRelease: () => released = true,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(released, isFalse);
|
||||||
|
await Future<void>.delayed(const Duration(milliseconds: 30));
|
||||||
|
expect(released, isTrue);
|
||||||
|
timer?.cancel();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:yumi/shared/business_logic/models/res/sc_room_rocket_api_res.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/sc_room_rocket_config_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/sc_room_rocket_config_res.dart';
|
||||||
import 'package:yumi/shared/business_logic/models/res/sc_room_rocket_status_res.dart';
|
import 'package:yumi/shared/business_logic/models/res/sc_room_rocket_status_res.dart';
|
||||||
import 'package:yumi/ui_kit/widgets/room/rocket/room_rocket_api_mapper.dart';
|
import 'package:yumi/ui_kit/widgets/room/rocket/room_rocket_api_mapper.dart';
|
||||||
@ -137,4 +138,74 @@ void main() {
|
|||||||
expect(groups[2]?.inRoom.single.imageUrl, 'cover-2');
|
expect(groups[2]?.inRoom.single.imageUrl, 'cover-2');
|
||||||
expect(groups[2]?.inRoom.single.expireDays, 7);
|
expect(groups[2]?.inRoom.single.expireDays, 7);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('parses rocket level contents response from go api', () {
|
||||||
|
final contents = SCRoomRocketLevelContentsRes.fromJson({
|
||||||
|
'configured': true,
|
||||||
|
'sysOrigin': 'LIKEI',
|
||||||
|
'enabled': true,
|
||||||
|
'timezone': 'Asia/Riyadh',
|
||||||
|
'maxLevel': 6,
|
||||||
|
'levels': [
|
||||||
|
{
|
||||||
|
'level': 1,
|
||||||
|
'needEnergy': 100,
|
||||||
|
'rocketIconUrl': 'icon-1',
|
||||||
|
'previewRocketUrl': 'preview-1',
|
||||||
|
'rocketAnimationUrl': 'animation-1',
|
||||||
|
'rewardPreview': {
|
||||||
|
'top1': [
|
||||||
|
{
|
||||||
|
'rewardScene': 'TOP1',
|
||||||
|
'rewardType': 'GOLD',
|
||||||
|
'rewardAmount': 100,
|
||||||
|
'rewardName': 'Lv1 top1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'level': 2,
|
||||||
|
'needEnergy': 200,
|
||||||
|
'rocketIconUrl': 'icon-2',
|
||||||
|
'previewRocketUrl': 'preview-2',
|
||||||
|
'rocketAnimationUrl': 'animation-2',
|
||||||
|
'rewards': [
|
||||||
|
{
|
||||||
|
'rewardScene': 'IGNITE',
|
||||||
|
'rewardType': 'GOLD',
|
||||||
|
'rewardAmount': 200,
|
||||||
|
'rewardName': 'Lv2 ignite',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'rewardScene': 'IN_ROOM',
|
||||||
|
'rewardType': 'NONE',
|
||||||
|
'rewardName': '轮空',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(contents.enabled, isTrue);
|
||||||
|
expect(contents.levels, hasLength(2));
|
||||||
|
expect(contents.levelFor(1)?.rocketIconUrl, 'icon-1');
|
||||||
|
expect(contents.rewardPreviewForLevel(1)?.top1.single.rewardAmount, 100);
|
||||||
|
expect(contents.rewardPreviewForLevel(2)?.ignite.single.rewardAmount, 200);
|
||||||
|
expect(contents.levelFor(2)?.rewards, hasLength(2));
|
||||||
|
|
||||||
|
final levels = RoomRocketApiMapper.levelsFromLevelContents(contents);
|
||||||
|
final allGroups = RoomRocketApiMapper.rewardGroupsByLevelFromLevelContents(
|
||||||
|
contents,
|
||||||
|
);
|
||||||
|
final groups = RoomRocketApiMapper.rewardGroupsFromLevelContents(
|
||||||
|
contents,
|
||||||
|
level: 2,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(levels?.first.imageUrl, 'icon-1');
|
||||||
|
expect(allGroups[1]?.top1.single.amount, '100');
|
||||||
|
expect(allGroups[2]?.setOff.single.amount, '200');
|
||||||
|
expect(groups?.setOff.single.amount, '200');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user