Files
fanuzu/app/lib/core/ui/live_planet.dart
T

105 lines
3.1 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: image,
onOpenHistory: onOpenHistory,
size: size,
glow: glow,
tint: planetColorOf(state?.colorKey),
stage: state == null ? stage : state.stage,
level: state?.level,
isEclipsed: state?.isEclipsed ?? false,
isHibernating: state?.isHibernating ?? false,
isHeroTime: state?.isHeroTime ?? false,
heroEventIds: state?.heroEventIds,
animate: animate,
lowEffects: lowEffects,
),
);
}
/// 배경 광량만 바꿔 콘텐츠의 가독성과 화면 구조는 유지한다.
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,
),
),
),
),
),
),
],
),
),
);
}