HOME 을 Figma 「홈」 구성으로 — TODAY'S QUEST · 미니맵·확장 맵(프로토타입 v6.2) · 행성 정보 박스 · 인큐베이터 · 아티스트 소식 · HOT ARCHIVE · 인기 K-INSIDE
This commit is contained in:
@@ -47,8 +47,12 @@ class HomeHero extends StatefulWidget {
|
||||
this.unjoined = false,
|
||||
this.onItem,
|
||||
this.miniMap,
|
||||
this.zapButtonKey,
|
||||
});
|
||||
|
||||
/// 화면 하단에 떠 있는 ZAP 버튼([HomeZap])의 키 — 기여 연출이 이 자리에서 행성으로 날아간다.
|
||||
final GlobalKey? zapButtonKey;
|
||||
|
||||
final VoidCallback? onOpenHistory;
|
||||
|
||||
/// 성장 카드의 「BTS ›」 — 사본 흐름대로 행성 상세(F3)로 간다.
|
||||
@@ -96,8 +100,9 @@ class HomeHero extends StatefulWidget {
|
||||
/// 사본 기준 배경 높이(상태 표시줄 48 포함).
|
||||
static const double designHeight = 680;
|
||||
|
||||
/// 배경 아래로 ZAP 원이 걸쳐 내려오는 몫. 다음 구획의 위 여백(24)과 같다.
|
||||
static const double zapOverhang = 24;
|
||||
/// 히어로 아래 여백 — 사본 `Frame 4241` 위 패딩 24 에서 첫 구획 머리의 터치 여유 12 를 뺀 값.
|
||||
/// (ZAP 은 화면 하단에 떠 있어 더는 히어로에 걸치지 않는다.)
|
||||
static const double bottomGap = 12;
|
||||
|
||||
@override
|
||||
State<HomeHero> createState() => _HomeHeroState();
|
||||
@@ -106,17 +111,18 @@ class HomeHero extends StatefulWidget {
|
||||
class _HomeHeroState extends State<HomeHero> {
|
||||
final _fxKey = GlobalKey();
|
||||
final _planetKey = GlobalKey();
|
||||
final _buttonKey = GlobalKey();
|
||||
PlanetGrowth get growth => widget.growth;
|
||||
String get fandomId => widget.fandomId;
|
||||
PlanetWatch get watchPlanet => widget.watchPlanet;
|
||||
VoidCallback? get onHeroParticipate => widget.onHeroParticipate;
|
||||
|
||||
Offset _center(GlobalKey key) {
|
||||
final box = key.currentContext?.findRenderObject();
|
||||
/// [key] 의 가운데를 히어로 좌표로. ZAP 버튼은 히어로 밖(화면 하단 고정)이라 전역 좌표로 잰다.
|
||||
Offset _center(GlobalKey? key) {
|
||||
final box = key?.currentContext?.findRenderObject();
|
||||
final root = _fxKey.currentContext?.findRenderObject();
|
||||
return box is RenderBox && box.hasSize && root is RenderBox
|
||||
? box.localToGlobal(box.size.center(Offset.zero), ancestor: root)
|
||||
return box is RenderBox && box.hasSize && root is RenderBox && root.hasSize
|
||||
? box.localToGlobal(box.size.center(Offset.zero)) -
|
||||
root.localToGlobal(Offset.zero)
|
||||
: Offset.zero;
|
||||
}
|
||||
|
||||
@@ -133,7 +139,7 @@ class _HomeHeroState extends State<HomeHero> {
|
||||
|
||||
return PlanetFxScope(
|
||||
child: SizedBox(
|
||||
height: background + HomeHero.zapOverhang,
|
||||
height: background + HomeHero.bottomGap,
|
||||
child: Stack(
|
||||
key: _fxKey,
|
||||
children: [
|
||||
@@ -202,7 +208,6 @@ class _HomeHeroState extends State<HomeHero> {
|
||||
glow: AppColors.neonViolet,
|
||||
),
|
||||
),
|
||||
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -218,7 +223,6 @@ class _HomeHeroState extends State<HomeHero> {
|
||||
_GrowthOverlayCard(
|
||||
growth: growth,
|
||||
onOpen: widget.onOpenPlanet,
|
||||
zapClearance: hasZap,
|
||||
),
|
||||
],
|
||||
],
|
||||
@@ -226,67 +230,11 @@ class _HomeHeroState extends State<HomeHero> {
|
||||
),
|
||||
|
||||
if (widget.miniMap case final mini?)
|
||||
Positioned(
|
||||
top: top + HomeHero.miniMapTop,
|
||||
right: 0,
|
||||
child: mini,
|
||||
),
|
||||
Positioned(top: top + HomeHero.miniMapTop, right: 0, child: mini),
|
||||
|
||||
if (widget.ticker case final ticker?)
|
||||
Positioned(top: top + 102, left: 0, right: 0, child: ticker),
|
||||
|
||||
// 3. 원형 ZAP — 사본 `Frame 1984081111`. 중심이 카드 아래 변에 걸친다.
|
||||
if (widget.zapData case final data?)
|
||||
if (widget.zap case final zap?)
|
||||
if (data.joined && data.mine?.id == fandomId)
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: LiveStreamBuilder<PlanetVisualState>(
|
||||
key: ValueKey(('home-zap', fandomId)),
|
||||
create: () => watchPlanet(fandomId),
|
||||
builder: (context, state) {
|
||||
final hero =
|
||||
state?.isHeroTime == true &&
|
||||
state?.heroEndsAt?.isAfter(DateTime.now()) ==
|
||||
true &&
|
||||
onHeroParticipate != null &&
|
||||
zap.pending == 0 &&
|
||||
!zap.sending &&
|
||||
!zap.needsRetry;
|
||||
return Column(
|
||||
key: _buttonKey,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (zap.needsRetry)
|
||||
TextButton(
|
||||
onPressed: zap.retry,
|
||||
child: Text(context.l10n.zapRetrySame),
|
||||
),
|
||||
ZapButton(
|
||||
round: true,
|
||||
showLabel: !growth.isNebula,
|
||||
onItem: widget.onItem,
|
||||
zapPop: data.zapPop,
|
||||
myPop:
|
||||
(zap.balance ?? data.myPop) -
|
||||
zap.pending * data.zapPop,
|
||||
isHeroTime: hero,
|
||||
blockedReason: zap.sending
|
||||
? context.l10n.zapApplying
|
||||
: zap.needsRetry
|
||||
? context.l10n.zapNeedsCheck
|
||||
: null,
|
||||
onZap: () => hero
|
||||
? onHeroParticipate!()
|
||||
: zap.tap(fandomId),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (widget.zap case final zap?)
|
||||
Positioned.fill(
|
||||
child: IgnorePointer(
|
||||
@@ -294,7 +242,7 @@ class _HomeHeroState extends State<HomeHero> {
|
||||
touchSerial: zap.touchSerial,
|
||||
pending: zap.pending > 0 || zap.sending,
|
||||
result: zap.result,
|
||||
source: _center(_buttonKey),
|
||||
source: _center(widget.zapButtonKey),
|
||||
target: _center(_planetKey),
|
||||
radius:
|
||||
(_planetKey.currentContext?.findRenderObject()
|
||||
@@ -344,7 +292,8 @@ class _Contribution extends StatelessWidget {
|
||||
alignment: Alignment.center,
|
||||
decoration: const BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: AppColors.cosmicSurfaceRaised,
|
||||
// 사본 `Ellipse 3` #9BF8A8(프로필 사진이 없을 때의 바탕).
|
||||
color: Color(0xFF9BF8A8),
|
||||
boxShadow: [BoxShadow(color: Color(0xB3000000), blurRadius: 4)],
|
||||
),
|
||||
child: Text(
|
||||
@@ -353,7 +302,7 @@ class _Contribution extends StatelessWidget {
|
||||
fontFamily: AppFonts.body,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.onCosmic,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -391,7 +340,9 @@ class _Contribution extends StatelessWidget {
|
||||
: growth.isNebula
|
||||
? context.l10n.heroNebulaPrompt
|
||||
: growth.hasRecentContribution
|
||||
? context.l10n.heroRecentContribution(formatPop(growth.contributedPop))
|
||||
? context.l10n.heroRecentContribution(
|
||||
formatPop(growth.contributedPop),
|
||||
)
|
||||
: context.l10n.heroGrowingTogether,
|
||||
style: const TextStyle(
|
||||
fontFamily: AppFonts.body,
|
||||
@@ -406,26 +357,19 @@ class _Contribution extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
/// 성장 카드 — 사본 기본 상태의 「BTS › / 행성 성장률 67% / 진행 바 / 6,270 / 10,000」
|
||||
/// (`Frame 1984081073` 343 폭 · `#040304` 40% · r12 · 패딩 12/16 · 간격 12 · 유리 흐림 4).
|
||||
/// 성장 카드 — Figma 「홈」 `Frame 1984081073`(343×151 · `#040304` 40% · r12 · 패딩 12/16 ·
|
||||
/// 간격 12 · 유리 흐림 4): 「BTS ›」(ABeeZee 32 · chevron 24 #777777) / 「행성 성장률 67%」
|
||||
/// (14/500 · 행간 24) / 진행 바 10 / 「6,270 / 10,000」(14/500). 말풍선(`Group 563` 168×40)
|
||||
/// 은 바 채움 끝 위에 뜬다.
|
||||
///
|
||||
/// 둘째 줄 「POP 진행률」과 바 아래 두 조건 줄은 정책값이다 — growthPercent 는 POP 진행률
|
||||
/// 이고(전체 충족률 아님) 승급은 POP·sFPI 동시 충족이다(정책 설계서 §P-08 · UX·FX v1.5
|
||||
/// §2.1). 말풍선 꼬리는 바 채움 끝을 가리킨다(사본 `Group 563` 가운데 = 채움 끝 x238).
|
||||
/// 성장률 · 수치는 두 조건 중 병목 축([PlanetGrowth.bottleneck])이다. 말풍선을 누르면 두
|
||||
/// 조건 상세([GrowthConditions])를 연다.
|
||||
class _GrowthOverlayCard extends StatelessWidget {
|
||||
const _GrowthOverlayCard({
|
||||
required this.growth,
|
||||
this.onOpen,
|
||||
this.zapClearance = false,
|
||||
});
|
||||
const _GrowthOverlayCard({required this.growth, this.onOpen});
|
||||
|
||||
final PlanetGrowth growth;
|
||||
final VoidCallback? onOpen;
|
||||
|
||||
/// 원형 ZAP(52)이 카드 아래 변에 걸친다. 둘째 조건 줄이 가려지지 않게 아래 여백을
|
||||
/// ZAP 윗변(아래 변 − 28) 위로 올린다. ZAP 좌표는 사본 그대로 둔다.
|
||||
final bool zapClearance;
|
||||
|
||||
static const _white14 = TextStyle(
|
||||
fontFamily: AppFonts.body,
|
||||
fontSize: 14,
|
||||
@@ -434,26 +378,58 @@ class _GrowthOverlayCard extends StatelessWidget {
|
||||
color: AppColors.onCosmic,
|
||||
);
|
||||
|
||||
/// 말풍선 가운데의 최소 x — 「행성 성장률 100%」 줄(약 103)과 겹치지 않게 한다.
|
||||
static const _bubbleMinCenter = 196.0;
|
||||
|
||||
String _value(num v) =>
|
||||
v == v.roundToDouble() ? formatPop(v.toInt()) : v.toStringAsFixed(1);
|
||||
|
||||
void _details(BuildContext context) => showModalBottomSheet<void>(
|
||||
context: context,
|
||||
useRootNavigator: true,
|
||||
backgroundColor: AppColors.cosmicSheet,
|
||||
builder: (context) => SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(
|
||||
AppSpace.s4,
|
||||
AppSpace.s5,
|
||||
AppSpace.s4,
|
||||
AppSpace.s5,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
context.l10n.growthConditionsTitle,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: AppSpace.s3),
|
||||
GrowthConditions(growth: growth, style: _white14),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ratio = growth.popRatio;
|
||||
|
||||
final low = growth.bottleneck;
|
||||
final ratio = low?.ratio;
|
||||
final percent = ratio == null ? '—' : '${(ratio * 100).round()}';
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 2, sigmaY: 2),
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.fromLTRB(
|
||||
AppSpace.s4,
|
||||
AppSpace.s3,
|
||||
AppSpace.s4,
|
||||
zapClearance ? 32 : AppSpace.s3,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppSpace.s4,
|
||||
vertical: AppSpace.s3,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0x66040304),
|
||||
borderRadius: BorderRadius.circular(AppRadius.md),
|
||||
border: Border.all(color: AppFx.glassStroke),
|
||||
),
|
||||
child: LayoutBuilder(
|
||||
builder: (context, box) => Stack(
|
||||
@@ -485,44 +461,57 @@ class _GrowthOverlayCard extends StatelessWidget {
|
||||
const ImageIcon(
|
||||
AppIcons.chevronRight,
|
||||
size: 24,
|
||||
color: AppColors.onCosmicVariant,
|
||||
color: Color(0xFF777777),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Text(context.l10n.heroPopProgress, style: _white14),
|
||||
const SizedBox(width: 4),
|
||||
Text(
|
||||
growth.growthPercent == null
|
||||
? '—'
|
||||
: '${growth.growthPercent}%',
|
||||
style: _white14,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: AppSpace.s3),
|
||||
_Bar(ratio: ratio ?? 0),
|
||||
const SizedBox(height: AppSpace.s3),
|
||||
GrowthConditions(
|
||||
growth: growth,
|
||||
style: _white14.copyWith(height: 16 / 14),
|
||||
// 성장률 · 바 · 수치를 누르면 두 조건 상세 — 말풍선이 없는 성운 카드의 입구.
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () => _details(context),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
growth.isNebula
|
||||
? context.l10n.heroNebulaGrowthRate(percent)
|
||||
: context.l10n.heroGrowthRate(percent),
|
||||
style: _white14,
|
||||
),
|
||||
const SizedBox(height: AppSpace.s3),
|
||||
_Bar(ratio: ratio ?? 0),
|
||||
const SizedBox(height: AppSpace.s3),
|
||||
Text(
|
||||
low == null
|
||||
? '— / —'
|
||||
: '${_value(low.current)} / ${_value(low.required)}',
|
||||
style: _white14,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
// 말풍선 — 꼬리 끝이 바 위 9.5 에 닿는다(사본 581.5+40 → 바 631).
|
||||
// 말풍선 — 사본 y566.5(카드 안 31.5) · 꼬리 끝이 바 위에 닿는다. 가운데는 채움 끝
|
||||
// (사본 x238 = 채움 206)을 따르되 왼쪽 성장률 글자와 겹치지 않게 민다.
|
||||
// 성운 카드(`344:213809`)에는 말풍선이 없다.
|
||||
if (!growth.isNebula)
|
||||
Positioned(
|
||||
top: 45 + 24 + AppSpace.s3 - 49.5,
|
||||
left: (box.maxWidth * (ratio ?? 0.5)).clamp(
|
||||
84.0,
|
||||
top: 31.5,
|
||||
left: (box.maxWidth * (ratio ?? 0)).clamp(
|
||||
math.min(_bubbleMinCenter, box.maxWidth - 84),
|
||||
box.maxWidth - 84,
|
||||
),
|
||||
child: FractionalTranslation(
|
||||
translation: const Offset(-0.5, 0),
|
||||
child: _SpeechBubble(text: growth.growthStatus),
|
||||
child: Semantics(
|
||||
button: true,
|
||||
child: GestureDetector(
|
||||
onTap: () => _details(context),
|
||||
child: _SpeechBubble(text: growth.growthBubble),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -820,7 +809,9 @@ class _StartSheet extends StatelessWidget {
|
||||
onTap: () => Navigator.of(context).pop(),
|
||||
child: SizedBox(
|
||||
height: 47,
|
||||
child: Center(child: Text(context.l10n.commonCancel, style: _item)),
|
||||
child: Center(
|
||||
child: Text(context.l10n.commonCancel, style: _item),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -828,3 +819,180 @@ class _StartSheet extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// 「GALAXY 맵 확장」 히어로 — Figma 「홈_초기사용자」 `343:211127`.
|
||||
///
|
||||
/// 히어로 680(상태 표시줄 48 포함)은 그대로 두고, 그 안 y124~680 을 갤럭시 맵(프로토타입 v6.2
|
||||
/// 장면 — `GalaxyWebView` 확장 모드)이 채운다. 프레임 순서대로 라이브 띠(y48 · 22)가 헤더(y70)
|
||||
/// 위에 오고, 히어로 아래에 375×54 「GALAXY」 바(ABeeZee 20 · 오른쪽 돋보기 42)가 붙는다.
|
||||
/// 돋보기 = 갤럭시 검색(`2008:14560` 「돋보기 - 검색페이지 이동」).
|
||||
///
|
||||
/// 닫기 컨트롤은 프레임에 없다. 「GALAXY」 글자 탭과 시스템 뒤로가기로 기본 히어로에 돌아간다.
|
||||
class HomeGalaxyHero extends StatelessWidget {
|
||||
const HomeGalaxyHero({
|
||||
super.key,
|
||||
required this.map,
|
||||
required this.onClose,
|
||||
required this.onSearch,
|
||||
this.ticker,
|
||||
});
|
||||
|
||||
/// 갤럭시 맵 — HOME 이 미니맵과 같은 `GalaxyWebView` 를 넘긴다(확장 모드).
|
||||
final Widget map;
|
||||
final VoidCallback onClose;
|
||||
final VoidCallback onSearch;
|
||||
final Widget? ticker;
|
||||
|
||||
/// 사본 「GALAXY」 바 높이.
|
||||
static const barHeight = 54.0;
|
||||
|
||||
/// 헤더가 라이브 띠 아래로 내려가는 몫(띠 22).
|
||||
static const headerShift = 22.0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final top = MediaQuery.paddingOf(context).top - 48;
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: top + HomeHero.designHeight,
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: Image.asset(
|
||||
'assets/figma/bg-space-home.png',
|
||||
fit: BoxFit.cover,
|
||||
alignment: Alignment.topCenter,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: top + 124,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: map,
|
||||
),
|
||||
if (ticker case final t?)
|
||||
Positioned(top: top + 48, left: 0, right: 0, child: t),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
height: barHeight,
|
||||
color: const Color(0xFF141414),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppSpace.s4,
|
||||
vertical: 6,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
key: const ValueKey('galaxy-bar-close'),
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: onClose,
|
||||
child: const Text(
|
||||
'GALAXY',
|
||||
style: TextStyle(
|
||||
fontFamily: AppFonts.display,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w400,
|
||||
height: 1.4,
|
||||
color: AppColors.onCosmic,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
width: 42,
|
||||
height: 42,
|
||||
),
|
||||
padding: EdgeInsets.zero,
|
||||
tooltip: context.l10n.commonSearch,
|
||||
onPressed: onSearch,
|
||||
icon: const Icon(
|
||||
Icons.search,
|
||||
size: 20,
|
||||
color: AppColors.onCosmic,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// HOME 의 ZAP — Figma 「홈」 `Frame 1984081111`(52×53 원 · `#4BC2AE → #4F98C8 → #5669DC` ·
|
||||
/// `#547BD4` 빛 6 · 번개 하나). 프레임 루트 직속이라 스크롤과 무관하게 하단 탭 위
|
||||
/// 가운데에 떠 있다(사본 x162 · 하단 탭 위 16). 명세 「Zap 버튼」 규칙 *화면 하단 위치 고정 ·*
|
||||
/// *행성/성운 가입 또는 생성한 유저에게만 노출* — 소속 팬덤이 지도 데이터의 내 행성일 때만.
|
||||
class HomeZap extends StatelessWidget {
|
||||
const HomeZap({
|
||||
super.key,
|
||||
required this.buttonKey,
|
||||
required this.zap,
|
||||
required this.data,
|
||||
required this.fandomId,
|
||||
required this.watchPlanet,
|
||||
this.onHeroParticipate,
|
||||
this.onItem,
|
||||
});
|
||||
|
||||
final GlobalKey buttonKey;
|
||||
final ZapController zap;
|
||||
final GalaxySnapshot data;
|
||||
final String fandomId;
|
||||
final PlanetWatch watchPlanet;
|
||||
final VoidCallback? onHeroParticipate;
|
||||
final VoidCallback? onItem;
|
||||
|
||||
/// 사본 하단 탭 윗변(y2806)과 버튼 아랫변(y2790) 사이.
|
||||
static const bottomGap = 16.0;
|
||||
|
||||
static bool visible(GalaxySnapshot? data, String fandomId) =>
|
||||
data != null && data.joined && data.mine?.id == fandomId;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => LiveStreamBuilder<PlanetVisualState>(
|
||||
key: ValueKey(('home-zap', fandomId)),
|
||||
create: () => watchPlanet(fandomId),
|
||||
builder: (context, state) {
|
||||
final hero =
|
||||
state?.isHeroTime == true &&
|
||||
state?.heroEndsAt?.isAfter(DateTime.now()) == true &&
|
||||
onHeroParticipate != null &&
|
||||
zap.pending == 0 &&
|
||||
!zap.sending &&
|
||||
!zap.needsRetry;
|
||||
return Column(
|
||||
key: buttonKey,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (zap.needsRetry)
|
||||
TextButton(
|
||||
onPressed: zap.retry,
|
||||
child: Text(context.l10n.zapRetrySame),
|
||||
),
|
||||
ZapButton(
|
||||
round: true,
|
||||
// 사본 `2097:16428` 의 떠 있는 ZAP 은 번개만 있다(라벨 없음).
|
||||
showLabel: false,
|
||||
onItem: onItem,
|
||||
zapPop: data.zapPop,
|
||||
myPop: (zap.balance ?? data.myPop) - zap.pending * data.zapPop,
|
||||
isHeroTime: hero,
|
||||
blockedReason: zap.sending
|
||||
? context.l10n.zapApplying
|
||||
: zap.needsRetry
|
||||
? context.l10n.zapNeedsCheck
|
||||
: null,
|
||||
onZap: () => hero ? onHeroParticipate!() : zap.tap(fandomId),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user