라이브 티커 · 갤럭시 검색 색인 · 주간 랭킹 스냅샷 · 연속 ZAP 상한 · 가입 행성 Zap · 성운 목표 · 랭킹 갱신 안내 · 행성 터치 반응
This commit is contained in:
@@ -523,6 +523,26 @@ class _HomeBody extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
),
|
||||
// Figma `2024:20758` — 행성 터치는 흔들림 1번 뒤 커뮤니티(팬덤 라운지)로.
|
||||
onTapPlanet:
|
||||
planetRepository == null ||
|
||||
data.fandomId.isEmpty
|
||||
? null
|
||||
: () => Navigator.of(
|
||||
context,
|
||||
rootNavigator: true,
|
||||
).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => PlanetDetailScreen(
|
||||
repository: planetRepository!(
|
||||
data.fandomId,
|
||||
),
|
||||
watchPlanet: watchPlanet,
|
||||
eclipse: eclipse,
|
||||
initialTab: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
onOpenHistory: planetRepository == null
|
||||
? null
|
||||
: () => Navigator.of(context).push(
|
||||
|
||||
@@ -8,6 +8,7 @@ import '../../../core/ui/hero_time_status.dart';
|
||||
import 'growth_conditions.dart';
|
||||
|
||||
import 'dart:math' as math;
|
||||
import 'package:flutter/services.dart' show HapticFeedback;
|
||||
import 'dart:ui' show ImageFilter;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -38,6 +39,7 @@ class HomeHero extends StatefulWidget {
|
||||
this.onHeroParticipate,
|
||||
this.onOpenHistory,
|
||||
this.onOpenPlanet,
|
||||
this.onTapPlanet,
|
||||
this.zap,
|
||||
this.zapData,
|
||||
this.ticker,
|
||||
@@ -61,6 +63,9 @@ class HomeHero extends StatefulWidget {
|
||||
|
||||
/// 성장 카드의 「BTS ›」 — 사본 흐름대로 행성 상세(F3)로 간다.
|
||||
final VoidCallback? onOpenPlanet;
|
||||
|
||||
/// 행성 본체 터치 — Figma `2024:20758` 「행성 1회 터치시 흔들림 1번, 커뮤니티 이동」.
|
||||
final VoidCallback? onTapPlanet;
|
||||
final String fandomId;
|
||||
final PlanetWatch watchPlanet;
|
||||
final VoidCallback? onHeroParticipate;
|
||||
@@ -207,7 +212,9 @@ class _HomeHeroState extends State<HomeHero> {
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: LivePlanet25D(
|
||||
child: _TapShake(
|
||||
onTap: widget.onTapPlanet,
|
||||
child: LivePlanet25D(
|
||||
onOpenHistory: widget.onOpenHistory,
|
||||
key: _planetKey,
|
||||
fandomId: fandomId,
|
||||
@@ -221,6 +228,7 @@ class _HomeHeroState extends State<HomeHero> {
|
||||
),
|
||||
glow: AppColors.neonViolet,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -265,6 +273,7 @@ class _HomeHeroState extends State<HomeHero> {
|
||||
Positioned.fill(
|
||||
child: IgnorePointer(
|
||||
child: ZapFeedback(
|
||||
fandomName: widget.growth.fandomName,
|
||||
touchSerial: zap.touchSerial,
|
||||
pending: zap.pending > 0 || zap.sending,
|
||||
result: zap.result,
|
||||
@@ -1022,3 +1031,49 @@ class HomeZap extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// 행성 터치 반응 — Figma `2024:20758` 「행성 1회 터치시 흔들림 1번」 · UX·FX v1.5 §3 Light Haptic.
|
||||
/// 흔들림이 끝나면 [onTap](커뮤니티 이동)을 부른다. [onTap] 이 없으면 아무 반응도 하지 않는다.
|
||||
class _TapShake extends StatefulWidget {
|
||||
const _TapShake({required this.child, this.onTap});
|
||||
|
||||
final Widget child;
|
||||
final VoidCallback? onTap;
|
||||
|
||||
@override
|
||||
State<_TapShake> createState() => _TapShakeState();
|
||||
}
|
||||
|
||||
class _TapShakeState extends State<_TapShake> with SingleTickerProviderStateMixin {
|
||||
late final _shake = AnimationController(vsync: this, duration: const Duration(milliseconds: 320));
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_shake.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Future<void> _tap() async {
|
||||
final onTap = widget.onTap;
|
||||
if (onTap == null || _shake.isAnimating) return;
|
||||
HapticFeedback.lightImpact();
|
||||
if (!MediaQuery.disableAnimationsOf(context)) await _shake.forward(from: 0);
|
||||
if (mounted) onTap();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: widget.onTap == null ? null : _tap,
|
||||
child: AnimatedBuilder(
|
||||
animation: _shake,
|
||||
// 한 번 좌우로 흔들리고 제자리 — 진폭 6 · 감쇠.
|
||||
builder: (context, child) => Transform.translate(
|
||||
offset: Offset(math.sin(_shake.value * math.pi * 4) * 6 * (1 - _shake.value), 0),
|
||||
child: child,
|
||||
),
|
||||
child: widget.child,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user