火箭功能修复
This commit is contained in:
parent
0c4acb28e5
commit
cedfc912cf
@ -1,4 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math' as math;
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
@ -4188,7 +4190,18 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
||||
if (currentStatus == null || !currentStatus.isEnabled) {
|
||||
return;
|
||||
}
|
||||
final nextLevel = _nextRoomRocketLevelAfterLaunch(launch.safeLevel);
|
||||
final currentLevel =
|
||||
(currentStatus.currentLevel ?? currentStatus.level?.toInt() ?? 1)
|
||||
.clamp(1, 99)
|
||||
.toInt();
|
||||
final currentPercent = _roomRocketStatusPercent(currentStatus);
|
||||
if (currentStatus.currentEnergy == 0 &&
|
||||
currentPercent <= 0 &&
|
||||
currentLevel >= launch.safeLevel) {
|
||||
return;
|
||||
}
|
||||
final launchedLevel = math.max(currentLevel, launch.safeLevel);
|
||||
final nextLevel = _nextRoomRocketLevelAfterLaunch(launchedLevel);
|
||||
final nextLevelInfo = _roomRocketLevelFor(nextLevel);
|
||||
final update = SCRoomRocketStatusRes(
|
||||
roomId: launch.roomId,
|
||||
@ -4226,6 +4239,21 @@ class RealTimeCommunicationManager extends ChangeNotifier {
|
||||
return normalizedLevel;
|
||||
}
|
||||
|
||||
double _roomRocketStatusPercent(SCRoomRocketStatusRes status) {
|
||||
final value = status.displayPercent ?? status.energyPercent;
|
||||
if (value != null) {
|
||||
final raw = value.toDouble();
|
||||
final percent = raw > 0 && raw <= 1 ? raw * 100 : raw;
|
||||
return percent.clamp(0, 100).toDouble();
|
||||
}
|
||||
final currentEnergy = status.currentEnergy;
|
||||
final maxEnergy = status.maxEnergy ?? status.needEnergy;
|
||||
if (currentEnergy == null || maxEnergy == null || maxEnergy <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return ((currentEnergy / maxEnergy) * 100).clamp(0, 100).toDouble();
|
||||
}
|
||||
|
||||
SCRoomRocketLevelRes? _roomRocketLevelFor(int level) {
|
||||
final normalizedLevel = level.clamp(1, 99).toInt();
|
||||
for (final item
|
||||
|
||||
@ -4912,6 +4912,9 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
_markRoomRocketLaunchEffectConsumed(launch);
|
||||
_holdRoomRocketRewardPopupUntilLaunchEnds(launch);
|
||||
rtcProvider.advanceRoomRocketStatusAfterLaunch(launch);
|
||||
rtcProvider.scheduleRoomRocketPostLaunchStatusRefresh(
|
||||
roomId: launch.roomId,
|
||||
);
|
||||
rtcProvider.handleRoomRocketLaunchBroadcast(launch);
|
||||
if (shouldFetchReward) {
|
||||
_scheduleRoomRocketRewardPopupAfterHold(
|
||||
@ -5571,14 +5574,10 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
required Map<String, dynamic> payload,
|
||||
required RoomRocketLaunchBroadcastMessage launch,
|
||||
}) {
|
||||
final currentPercent = _roomRocketPayloadPercent(payload);
|
||||
if (currentPercent < 99.5) {
|
||||
if (!_roomRocketPayloadIndicatesFullOrLaunch(payload)) {
|
||||
return false;
|
||||
}
|
||||
final previousPercent = _roomRocketStatusPercent(
|
||||
rtcProvider.roomRocketStatus,
|
||||
);
|
||||
if (previousPercent < 99.5) {
|
||||
if (!(rtcProvider.roomRocketStatus?.shouldDisplayFullProgress ?? false)) {
|
||||
return true;
|
||||
}
|
||||
final launchKey = _roomRocketLaunchNoticeKey(launch);
|
||||
@ -5592,6 +5591,29 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
!_recentRoomRocketLaunchLooseTimes.containsKey(looseLaunchKey));
|
||||
}
|
||||
|
||||
bool _roomRocketPayloadIndicatesFullOrLaunch(Map<String, dynamic> payload) {
|
||||
final status = _payloadText(payload['status']).toUpperCase();
|
||||
if (status.contains('LAUNCH')) {
|
||||
return true;
|
||||
}
|
||||
final currentEnergy = _payloadNum(
|
||||
payload['currentEnergy'] ?? payload['current_energy'],
|
||||
);
|
||||
final maxEnergy = _payloadNum(
|
||||
payload['maxEnergy'] ??
|
||||
payload['max_energy'] ??
|
||||
payload['needEnergy'] ??
|
||||
payload['need_energy'],
|
||||
);
|
||||
if (currentEnergy != null &&
|
||||
maxEnergy != null &&
|
||||
maxEnergy > 0 &&
|
||||
currentEnergy >= maxEnergy) {
|
||||
return true;
|
||||
}
|
||||
return _roomRocketPayloadPercent(payload) >= 100;
|
||||
}
|
||||
|
||||
RoomRocketLaunchBroadcastMessage _buildRoomRocketLaunchFromStatusPayload({
|
||||
required RealTimeCommunicationManager rtcProvider,
|
||||
required Map<String, dynamic> payload,
|
||||
@ -5655,30 +5677,6 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
);
|
||||
}
|
||||
|
||||
double _roomRocketStatusPercent(dynamic status) {
|
||||
if (status == null) {
|
||||
return 0;
|
||||
}
|
||||
final displayPercent = _payloadNum(status.displayPercent);
|
||||
if (displayPercent != null) {
|
||||
final raw = displayPercent.toDouble();
|
||||
final percent = raw > 0 && raw <= 1 ? raw * 100 : raw;
|
||||
return percent.clamp(0, 100).toDouble();
|
||||
}
|
||||
final energyPercent = _payloadNum(status.energyPercent);
|
||||
if (energyPercent != null) {
|
||||
final raw = energyPercent.toDouble();
|
||||
final percent = raw > 0 && raw <= 1 ? raw * 100 : raw;
|
||||
return percent.clamp(0, 100).toDouble();
|
||||
}
|
||||
final currentEnergy = _payloadNum(status.currentEnergy);
|
||||
final maxEnergy = _payloadNum(status.maxEnergy ?? status.needEnergy);
|
||||
if (currentEnergy == null || maxEnergy == null || maxEnergy <= 0) {
|
||||
return 0;
|
||||
}
|
||||
return ((currentEnergy / maxEnergy) * 100).clamp(0, 100).toDouble();
|
||||
}
|
||||
|
||||
double _roomRocketPayloadPercent(Map<String, dynamic> payload) {
|
||||
final value = _payloadNum(
|
||||
payload['displayPercent'] ??
|
||||
@ -6021,6 +6019,28 @@ class RealTimeMessagingManager extends ChangeNotifier {
|
||||
priority: 1000,
|
||||
);
|
||||
OverlayManager().addMessage(msg);
|
||||
final currentContext = context;
|
||||
if (currentContext != null &&
|
||||
currentContext.mounted &&
|
||||
_isCurrentVoiceRoom(launchRoomId)) {
|
||||
final launch = RoomRocketLaunchBroadcastMessage.fromJson({
|
||||
...payload,
|
||||
'roomId': launchRoomId,
|
||||
'level': rocketLevel,
|
||||
'rocketLevel': rocketLevel,
|
||||
'rocketIconUrl': rocketIconUrl,
|
||||
});
|
||||
if (launch.isValid) {
|
||||
final rtcProvider = Provider.of<RealTimeCommunicationManager>(
|
||||
currentContext,
|
||||
listen: false,
|
||||
);
|
||||
rtcProvider.advanceRoomRocketStatusAfterLaunch(launch);
|
||||
rtcProvider.scheduleRoomRocketPostLaunchStatusRefresh(
|
||||
roomId: launchRoomId,
|
||||
);
|
||||
}
|
||||
}
|
||||
_scheduleRoomRocketStatusRefreshForCurrentRoom(launchRoomId);
|
||||
} else if (type == SCRoomMsgType.voiceRoomRocketLaunchBroadcast) {
|
||||
_handleVoiceRoomRocketLaunchBroadcast(
|
||||
|
||||
@ -319,6 +319,26 @@ class SCRoomRocketStatusRes {
|
||||
normalizedStatus != 'DISABLED';
|
||||
}
|
||||
|
||||
bool get isLaunchState {
|
||||
final normalizedStatus = (_status ?? '').trim().toUpperCase();
|
||||
return normalizedStatus.contains('LAUNCH');
|
||||
}
|
||||
|
||||
bool get hasFullEnergy {
|
||||
final current = _currentEnergy;
|
||||
final max = _maxEnergy ?? _needEnergy;
|
||||
return current != null && max != null && max > 0 && current >= max;
|
||||
}
|
||||
|
||||
bool get hasFullPercent {
|
||||
final percent = _normalizedPercent(_displayPercent ?? _energyPercent);
|
||||
return percent != null && percent >= 100;
|
||||
}
|
||||
|
||||
bool get shouldDisplayFullProgress {
|
||||
return hasFullEnergy || hasFullPercent || isLaunchState;
|
||||
}
|
||||
|
||||
int? get roundNo => _roundNo;
|
||||
|
||||
bool? get displayRound => _displayRound;
|
||||
@ -529,6 +549,15 @@ class SCRoomRocketStatusRes {
|
||||
return num.tryParse(value?.toString().trim() ?? '');
|
||||
}
|
||||
|
||||
static double? _normalizedPercent(num? value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
final raw = value.toDouble();
|
||||
final percent = raw > 0 && raw <= 1 ? raw * 100 : raw;
|
||||
return percent.clamp(0, 100).toDouble();
|
||||
}
|
||||
|
||||
static bool? _boolValue(dynamic value) {
|
||||
if (value is bool) {
|
||||
return value;
|
||||
|
||||
@ -60,8 +60,18 @@ class RoomRocketDialog extends StatelessWidget {
|
||||
selectedLevel.clamp(0, math.max(0, resolvedLevels.length - 1)).toInt();
|
||||
final selectedLevelItem = resolvedLevels[resolvedSelectedLevel];
|
||||
final percent = _percentForSelectedLevel(status, selectedLevelItem.level);
|
||||
final displayPercent = _displayPercentForSelectedLevel(
|
||||
status,
|
||||
selectedLevelItem.level,
|
||||
percent,
|
||||
);
|
||||
final progressPercent = _progressPercentForSelectedLevel(
|
||||
status,
|
||||
selectedLevelItem.level,
|
||||
percent,
|
||||
);
|
||||
final resolvedProgressStage =
|
||||
progressStage ?? RoomRocketProgressStage.fromPercent(percent);
|
||||
progressStage ?? RoomRocketProgressStage.fromPercent(progressPercent);
|
||||
final resolvedBottomStage =
|
||||
bottomStage ??
|
||||
(resolvedCrew.isEmpty
|
||||
@ -97,6 +107,7 @@ class RoomRocketDialog extends StatelessWidget {
|
||||
child: _RocketCanvas(
|
||||
scale: scale,
|
||||
percent: percent,
|
||||
displayPercent: displayPercent,
|
||||
progressStage: resolvedProgressStage,
|
||||
bottomStage: resolvedBottomStage,
|
||||
status: status,
|
||||
@ -207,6 +218,48 @@ class RoomRocketDialog extends StatelessWidget {
|
||||
}
|
||||
return _normalizePercent(status?.displayPercent ?? status?.energyPercent);
|
||||
}
|
||||
|
||||
static int _displayPercentForSelectedLevel(
|
||||
SCRoomRocketStatusRes? status,
|
||||
int selectedLevel,
|
||||
double percent,
|
||||
) {
|
||||
final currentLevel =
|
||||
(status?.currentLevel ?? status?.level?.toInt() ?? selectedLevel)
|
||||
.clamp(1, 99)
|
||||
.toInt();
|
||||
if (selectedLevel < currentLevel) {
|
||||
return 100;
|
||||
}
|
||||
if (selectedLevel > currentLevel) {
|
||||
return 0;
|
||||
}
|
||||
if (status?.shouldDisplayFullProgress ?? percent >= 100) {
|
||||
return 100;
|
||||
}
|
||||
return percent.round().clamp(0, 99).toInt();
|
||||
}
|
||||
|
||||
static double _progressPercentForSelectedLevel(
|
||||
SCRoomRocketStatusRes? status,
|
||||
int selectedLevel,
|
||||
double percent,
|
||||
) {
|
||||
final currentLevel =
|
||||
(status?.currentLevel ?? status?.level?.toInt() ?? selectedLevel)
|
||||
.clamp(1, 99)
|
||||
.toInt();
|
||||
if (selectedLevel < currentLevel) {
|
||||
return 100;
|
||||
}
|
||||
if (selectedLevel > currentLevel) {
|
||||
return 0;
|
||||
}
|
||||
if (status?.shouldDisplayFullProgress ?? percent >= 100) {
|
||||
return 100;
|
||||
}
|
||||
return percent;
|
||||
}
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
@ -214,6 +267,22 @@ String debugRoomRocketTitleText({required int level, required int round}) {
|
||||
return _roomRocketTitleText(level: level, round: round);
|
||||
}
|
||||
|
||||
@visibleForTesting
|
||||
int debugRoomRocketDisplayPercentText({
|
||||
required SCRoomRocketStatusRes? status,
|
||||
required int selectedLevel,
|
||||
}) {
|
||||
final percent = RoomRocketDialog._percentForSelectedLevel(
|
||||
status,
|
||||
selectedLevel,
|
||||
);
|
||||
return RoomRocketDialog._displayPercentForSelectedLevel(
|
||||
status,
|
||||
selectedLevel,
|
||||
percent,
|
||||
);
|
||||
}
|
||||
|
||||
String _roomRocketTitleText({required int level, required int round}) {
|
||||
final normalizedLevel = level.clamp(1, 99).toInt();
|
||||
final normalizedRound = round.clamp(1, 99).toInt();
|
||||
@ -352,6 +421,7 @@ class _RocketCanvas extends StatelessWidget {
|
||||
const _RocketCanvas({
|
||||
required this.scale,
|
||||
required this.percent,
|
||||
required this.displayPercent,
|
||||
required this.progressStage,
|
||||
required this.bottomStage,
|
||||
required this.status,
|
||||
@ -373,6 +443,7 @@ class _RocketCanvas extends StatelessWidget {
|
||||
|
||||
final double scale;
|
||||
final double percent;
|
||||
final int displayPercent;
|
||||
final RoomRocketProgressStage progressStage;
|
||||
final RoomRocketBottomStage bottomStage;
|
||||
final SCRoomRocketStatusRes? status;
|
||||
@ -506,7 +577,7 @@ class _RocketCanvas extends StatelessWidget {
|
||||
top: s(373),
|
||||
width: s(56),
|
||||
child: _GradientText(
|
||||
'${percent.round()}%',
|
||||
'$displayPercent%',
|
||||
fontSize: s(16),
|
||||
fontWeight: FontWeight.w600,
|
||||
textAlign: TextAlign.center,
|
||||
|
||||
@ -42,4 +42,49 @@ void main() {
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test('rocket progress text caps rounded non-full progress at 99 percent', () {
|
||||
final notFull = SCRoomRocketStatusRes(
|
||||
currentLevel: 1,
|
||||
currentEnergy: 995,
|
||||
maxEnergy: 1000,
|
||||
displayPercent: 99.5,
|
||||
);
|
||||
final fullEnergy = SCRoomRocketStatusRes(
|
||||
currentLevel: 1,
|
||||
currentEnergy: 1000,
|
||||
maxEnergy: 1000,
|
||||
displayPercent: 99.5,
|
||||
);
|
||||
final fullPercent = SCRoomRocketStatusRes(
|
||||
currentLevel: 1,
|
||||
currentEnergy: 995,
|
||||
maxEnergy: 1000,
|
||||
displayPercent: 100,
|
||||
);
|
||||
final launchStatus = SCRoomRocketStatusRes(
|
||||
currentLevel: 1,
|
||||
currentEnergy: 995,
|
||||
maxEnergy: 1000,
|
||||
displayPercent: 99.5,
|
||||
status: 'LAUNCHING',
|
||||
);
|
||||
|
||||
expect(
|
||||
debugRoomRocketDisplayPercentText(status: notFull, selectedLevel: 1),
|
||||
99,
|
||||
);
|
||||
expect(
|
||||
debugRoomRocketDisplayPercentText(status: fullEnergy, selectedLevel: 1),
|
||||
100,
|
||||
);
|
||||
expect(
|
||||
debugRoomRocketDisplayPercentText(status: fullPercent, selectedLevel: 1),
|
||||
100,
|
||||
);
|
||||
expect(
|
||||
debugRoomRocketDisplayPercentText(status: launchStatus, selectedLevel: 1),
|
||||
100,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@ -339,6 +339,38 @@ void main() {
|
||||
expect(disabledStatus.isEnabled, isFalse);
|
||||
});
|
||||
|
||||
test(
|
||||
'identifies full rocket progress from energy percent or launch status',
|
||||
() {
|
||||
final roundedButNotFull = SCRoomRocketStatusRes.fromJson({
|
||||
'currentEnergy': 995,
|
||||
'maxEnergy': 1000,
|
||||
'displayPercent': 99.5,
|
||||
});
|
||||
final fullEnergy = SCRoomRocketStatusRes.fromJson({
|
||||
'currentEnergy': 1000,
|
||||
'maxEnergy': 1000,
|
||||
'displayPercent': 99.5,
|
||||
});
|
||||
final fullPercent = SCRoomRocketStatusRes.fromJson({
|
||||
'currentEnergy': 995,
|
||||
'maxEnergy': 1000,
|
||||
'displayPercent': 100,
|
||||
});
|
||||
final launchStatus = SCRoomRocketStatusRes.fromJson({
|
||||
'currentEnergy': 995,
|
||||
'maxEnergy': 1000,
|
||||
'displayPercent': 99.5,
|
||||
'status': 'LAUNCHING',
|
||||
});
|
||||
|
||||
expect(roundedButNotFull.shouldDisplayFullProgress, isFalse);
|
||||
expect(fullEnergy.shouldDisplayFullProgress, isTrue);
|
||||
expect(fullPercent.shouldDisplayFullProgress, isTrue);
|
||||
expect(launchStatus.shouldDisplayFullProgress, isTrue);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'uses top-level reward preview for the response level instead of current level',
|
||||
() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user