import 'package:flutter/material.dart'; import '../data/planet_visual_state.dart'; import '../theme/tokens.dart'; import 'live_stream.dart'; import 'planet_25d.dart'; /// 첫 서버 스냅샷은 기준점. 과거 캐시와의 차이를 새 진화로 오인하지 않는다. class LivePlanet25D extends StatelessWidget { const LivePlanet25D({ super.key, required this.fandomId, required this.watch, required this.image, required this.size, this.stage, this.onOpenHistory, this.glow = AppColors.neonViolet, this.animate = true, this.lowEffects = false, }); final VoidCallback? onOpenHistory; final String fandomId; final PlanetWatch watch; final String image; final double size; final int? stage; final Color glow; final bool animate; final bool lowEffects; @override Widget build(BuildContext context) => LiveStreamBuilder( key: ValueKey(('planet-state', fandomId)), create: () => watch(fandomId), builder: (context, state) => Planet25D( key: ValueKey((fandomId, state != null)), // 생성 때 고른 형태가 있으면 그 그림, 없으면(성운 · 형태 없는 옛 행성) 화면이 준 그림. image: planetShapeImage(state?.planetType) ?? image, onOpenHistory: onOpenHistory, size: size, glow: glow, tint: planetColorOf(state?.colorKey), stage: state == null ? stage : state.stage, level: state?.level, evolutionImminent: state?.evolutionImminent ?? false, isEclipsed: state?.isEclipsed ?? false, isHibernating: state?.isHibernating ?? false, isHeroTime: state?.isHeroTime ?? false, heroEventIds: state?.heroEventIds, animate: animate, lowEffects: lowEffects, ), ); } /// 정지 그림의 실시간판 — 지켜보는 행성의 형태 · 색, 없으면 [planetFallbackImage]. /// 히어로([LivePlanet25D])와 같은 원천이라 접힌 앱 바의 작은 그림이 히어로와 갈리지 않는다. class LivePlanetArt extends StatelessWidget { const LivePlanetArt({ super.key, required this.fandomId, required this.watch, required this.size, this.nebula = false, }); final String fandomId; final PlanetWatch watch; final double size; final bool nebula; @override Widget build(BuildContext context) => LiveStreamBuilder( key: ValueKey(('planet-art', fandomId)), create: () => watch(fandomId), builder: (context, state) => PlanetArt( fallback: planetFallbackImage(fandomId, nebula: nebula), planetType: nebula ? null : state?.planetType, colorKey: state?.colorKey, width: size, height: size, ), ); } /// 배경 광량만 바꿔 콘텐츠의 가독성과 화면 구조는 유지한다. class LivePlanetLighting extends StatelessWidget { const LivePlanetLighting({ super.key, required this.fandomId, required this.watch, required this.child, }); final String fandomId; final PlanetWatch watch; final Widget child; @override Widget build(BuildContext context) => LiveStreamBuilder( key: ValueKey(('planet-light', fandomId)), create: () => watch(fandomId), builder: (context, state) => AnimatedOpacity( opacity: state?.isHibernating == true ? 0.35 : state?.isEclipsed == true ? 0.45 : 1, duration: MediaQuery.disableAnimationsOf(context) ? Duration.zero : const Duration(seconds: 2), child: Stack( fit: StackFit.passthrough, children: [ child, Positioned.fill( child: IgnorePointer( child: AnimatedOpacity( opacity: state?.isHeroTime == true && state?.isEclipsed != true && state?.isHibernating != true ? 1 : 0, duration: MediaQuery.disableAnimationsOf(context) ? Duration.zero : const Duration(seconds: 2), child: const DecoratedBox( decoration: BoxDecoration( gradient: RadialGradient( colors: [Color(0x26FFD34D), Color(0x00FFD34D)], radius: 0.85, ), ), ), ), ), ), ], ), ), ); }