140 lines
4.5 KiB
Dart
140 lines
4.5 KiB
Dart
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<PlanetVisualState>(
|
|
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,
|
|
eclipseFailed: state?.eclipseFailed ?? false,
|
|
eclipseSuccessId: state?.eclipseSuccessId,
|
|
eclipseWarnAt: state?.eclipseWarnAt,
|
|
eclipseStartAt: state?.eclipseStartAt,
|
|
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<PlanetVisualState>(
|
|
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<PlanetVisualState>(
|
|
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,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|