Initial commit: SubManager Flutter App
주요 구현 완료 기능: - 구독 관리 (추가/편집/삭제/카테고리 분류) - 이벤트 할인 시스템 (기본값 자동 설정) - SMS 자동 스캔 및 구독 정보 추출 - 알림 시스템 (타임존 처리 안정화) - 환율 변환 지원 (KRW/USD) - 반응형 UI 및 애니메이션 - 다국어 지원 (한국어/영어) 버그 수정: - NotificationService tz.local 초기화 오류 해결 - MainScreenSummaryCard 레이아웃 오버플로우 수정 - 구독 추가 시 LateInitializationError 완전 해결 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
124
lib/widgets/animated_wave_background.dart
Normal file
124
lib/widgets/animated_wave_background.dart
Normal file
@@ -0,0 +1,124 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
/// 웨이브 애니메이션 배경 효과를 제공하는 위젯
|
||||
///
|
||||
/// [controller]와 [pulseController]를 통해 애니메이션을 제어합니다.
|
||||
class AnimatedWaveBackground extends StatelessWidget {
|
||||
final AnimationController controller;
|
||||
final AnimationController pulseController;
|
||||
|
||||
const AnimatedWaveBackground({
|
||||
Key? key,
|
||||
required this.controller,
|
||||
required this.pulseController,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
// 웨이브 애니메이션 배경 요소 - 사인/코사인 함수 대신 더 부드러운 곡선 사용
|
||||
AnimatedBuilder(
|
||||
animation: controller,
|
||||
builder: (context, child) {
|
||||
// 0~1 사이의 값을 0~2π 사이의 값으로 변환하여 부드러운 주기 생성
|
||||
final angle = controller.value * 2 * math.pi;
|
||||
// 사인 함수를 사용하여 부드러운 움직임 생성
|
||||
final xOffset = 20 * math.sin(angle);
|
||||
final yOffset = 10 * math.cos(angle);
|
||||
|
||||
return Positioned(
|
||||
right: -40 + xOffset,
|
||||
top: -60 + yOffset,
|
||||
child: Transform.rotate(
|
||||
// 회전도 선형적으로 변화하도록 수정
|
||||
angle: 0.2 * math.sin(angle * 0.5),
|
||||
child: Container(
|
||||
width: 200,
|
||||
height: 200,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
AnimatedBuilder(
|
||||
animation: controller,
|
||||
builder: (context, child) {
|
||||
// 첫 번째 원과 약간 다른 위상을 가지도록 설정
|
||||
final angle = (controller.value * 2 * math.pi) + (math.pi / 3);
|
||||
final xOffset = 20 * math.cos(angle);
|
||||
final yOffset = 10 * math.sin(angle);
|
||||
|
||||
return Positioned(
|
||||
left: -80 + xOffset,
|
||||
bottom: -70 + yOffset,
|
||||
child: Transform.rotate(
|
||||
// 반대 방향으로 회전하도록 설정
|
||||
angle: -0.3 * math.sin(angle * 0.5),
|
||||
child: Container(
|
||||
width: 220,
|
||||
height: 220,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.05),
|
||||
borderRadius: BorderRadius.circular(110),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
// 배경에 추가적인 작은 원 추가하여 깊이감 증가
|
||||
AnimatedBuilder(
|
||||
animation: controller,
|
||||
builder: (context, child) {
|
||||
// 세 번째 원은 다른 위상으로 움직이도록 설정
|
||||
final angle = (controller.value * 2 * math.pi) + (math.pi * 2 / 3);
|
||||
final xOffset = 15 * math.sin(angle * 0.7);
|
||||
final yOffset = 8 * math.cos(angle * 0.7);
|
||||
|
||||
return Positioned(
|
||||
right: 40 + xOffset,
|
||||
bottom: -40 + yOffset,
|
||||
child: Transform.rotate(
|
||||
angle: 0.4 * math.cos(angle * 0.5),
|
||||
child: Container(
|
||||
width: 120,
|
||||
height: 120,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.08),
|
||||
borderRadius: BorderRadius.circular(60),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
// 숨쉬는 효과가 있는 작은 원
|
||||
AnimatedBuilder(
|
||||
animation: pulseController,
|
||||
builder: (context, child) {
|
||||
return Positioned(
|
||||
top: 10,
|
||||
left: 200,
|
||||
child: Container(
|
||||
width: 30,
|
||||
height: 30,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(
|
||||
0.1 + 0.1 * pulseController.value,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user