GIVE [+1] · [+10] 은 서버가 기여를 확정한 묶음 기준으로만 표시
This commit is contained in:
@@ -17,7 +17,7 @@ class ZapController extends ChangeNotifier {
|
||||
ZapResult? result;
|
||||
Timer? _burst;
|
||||
bool _disposed = false;
|
||||
({String fandomId, int count, String key})? _batch;
|
||||
({String fandomId, int count, String key, int streak})? _batch;
|
||||
bool get needsRetry => _batch != null && !sending;
|
||||
|
||||
/// 아직 확정되지 않은 연타 — 보내는 중인 묶음 + 다음 묶음. 표시 잔액은 이만큼 미리 뺀다.
|
||||
@@ -27,6 +27,10 @@ class ZapController extends ChangeNotifier {
|
||||
/// [streakWindow] 안에 다시 누르면 이어지고, 넘기면 1 부터 다시 센다.
|
||||
int streak = 0;
|
||||
Timer? _streakTimer;
|
||||
|
||||
/// 마지막으로 확정된 묶음의 끝 탭이 몇 번째 연속이었나 — 확정 결과 [+1] · [+10] 은 이것으로 정한다.
|
||||
/// 확정 안 된 뒤 연타는 세지 않는다.
|
||||
int confirmedStreak = 0;
|
||||
String? _pendingFandom;
|
||||
static const streakWindow = Duration(milliseconds: 500);
|
||||
|
||||
@@ -85,6 +89,7 @@ class ZapController extends ChangeNotifier {
|
||||
fandomId: fandomId,
|
||||
count: pending,
|
||||
key: 'z${DateTime.now().microsecondsSinceEpoch}',
|
||||
streak: streak,
|
||||
);
|
||||
if (batch.count == 0) return;
|
||||
_burst?.cancel();
|
||||
@@ -102,6 +107,7 @@ class ZapController extends ChangeNotifier {
|
||||
if (_disposed) return;
|
||||
if (receipt.txId.isEmpty) throw StateError('Missing ZAP receipt');
|
||||
if (receipt.balanceAfter >= 0) balance = receipt.balanceAfter;
|
||||
confirmedStreak = batch.streak;
|
||||
result = receipt;
|
||||
_batch = null;
|
||||
} catch (error) {
|
||||
|
||||
@@ -1112,9 +1112,10 @@ class HomeZap extends StatelessWidget {
|
||||
/// 행성 반응 — Figma `2024:20758` 「행성 1회 터치시 흔들림 1번」 · `2033:15818` 행성 리액션 1.
|
||||
///
|
||||
/// - 행성 터치: Light Haptic · 흔들림 1번이 끝나면 [onTap](커뮤니티 이동).
|
||||
/// - GIVE: 누를 때마다 흔들림 1번 · 행성 우하단 [+1] 0.5초(연속 가능). 이어서 10회 이상이면
|
||||
/// 흔들림 x2 · 자전 1.5배([Planet25D.spinBoost]) · [+10]. 숫자는 누른 횟수이고 기여 결과는
|
||||
/// 서버 확정 뒤 [ZapFeedback] 이 따로 띄운다(v1.5 §1.2).
|
||||
/// - GIVE 입력 반응(즉시): 누를 때마다 흔들림 1번, 이어서 10회 이상이면 흔들림 x2 · 자전 1.5배
|
||||
/// ([Planet25D.spinBoost]).
|
||||
/// - GIVE 결과(서버 확정 뒤, v1.5 §1.2 · §3): 행성 우하단 [+1] 0.5초(연속 가능), 10회 이상 이어진
|
||||
/// 연타의 확정이면 [+10].
|
||||
class _PlanetReaction extends StatefulWidget {
|
||||
const _PlanetReaction({
|
||||
required this.builder,
|
||||
@@ -1148,11 +1149,17 @@ class _PlanetReactionState extends State<_PlanetReaction>
|
||||
int? _seenSerial;
|
||||
int _streak = 0;
|
||||
Timer? _countTimer;
|
||||
String? _seenTx;
|
||||
|
||||
/// 확정 결과 표시 — 「+1」 · 「+10」. null 이면 숨김.
|
||||
String? _count;
|
||||
Timer? _resultTimer;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_seenSerial = widget.zap?.touchSerial;
|
||||
_seenTx = widget.zap?.result?.txId;
|
||||
widget.zap?.addListener(_onZap);
|
||||
}
|
||||
|
||||
@@ -1162,6 +1169,7 @@ class _PlanetReactionState extends State<_PlanetReaction>
|
||||
if (old.zap != widget.zap) {
|
||||
old.zap?.removeListener(_onZap);
|
||||
_seenSerial = widget.zap?.touchSerial;
|
||||
_seenTx = widget.zap?.result?.txId;
|
||||
widget.zap?.addListener(_onZap);
|
||||
}
|
||||
}
|
||||
@@ -1170,12 +1178,25 @@ class _PlanetReactionState extends State<_PlanetReaction>
|
||||
void dispose() {
|
||||
widget.zap?.removeListener(_onZap);
|
||||
_countTimer?.cancel();
|
||||
_resultTimer?.cancel();
|
||||
_shake.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onZap() {
|
||||
final zap = widget.zap!;
|
||||
final tx = zap.result?.txId;
|
||||
if (tx != null && tx.isNotEmpty && tx != _seenTx) {
|
||||
_seenTx = tx;
|
||||
if (!zap.questReaction) {
|
||||
setState(() => _count =
|
||||
zap.confirmedStreak >= _PlanetReaction.boostStreak ? '+10' : '+1');
|
||||
_resultTimer?.cancel();
|
||||
_resultTimer = Timer(ZapController.streakWindow, () {
|
||||
if (mounted) setState(() => _count = null);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (zap.touchSerial == _seenSerial) return;
|
||||
_seenSerial = zap.touchSerial;
|
||||
if (zap.questReaction) return;
|
||||
@@ -1233,7 +1254,7 @@ class _PlanetReactionState extends State<_PlanetReaction>
|
||||
),
|
||||
child: widget.builder(boost),
|
||||
),
|
||||
if (_streak > 0)
|
||||
if (_count case final count?)
|
||||
// 행성 우측 하단 — 행성 그림 상자([planetSize]) 안 오른쪽 아래.
|
||||
Positioned.fill(
|
||||
child: IgnorePointer(
|
||||
@@ -1243,7 +1264,7 @@ class _PlanetReactionState extends State<_PlanetReaction>
|
||||
child: Align(
|
||||
alignment: const Alignment(0.85, 0.85),
|
||||
child: Text(
|
||||
boost ? '+10' : '+1',
|
||||
count,
|
||||
key: const ValueKey('planet-give-count'),
|
||||
style: const TextStyle(
|
||||
fontFamily: AppFonts.body,
|
||||
|
||||
Reference in New Issue
Block a user