Your commit message here

This commit is contained in:
2025-12-19 22:47:27 -06:00
parent 5d746d694e
commit 464692ce56
21 changed files with 3018 additions and 0 deletions

View File

@@ -4,7 +4,11 @@ import 'dart:math' as math;
import '../theme/app_theme.dart';
import '../models/cycle_entry.dart';
<<<<<<< HEAD
class CycleRing extends StatelessWidget {
=======
class CycleRing extends StatefulWidget {
>>>>>>> 6742220 (Your commit message here)
final int dayOfCycle;
final int totalDays;
final CyclePhase phase;
@@ -17,6 +21,7 @@ class CycleRing extends StatelessWidget {
});
@override
<<<<<<< HEAD
Widget build(BuildContext context) {
final progress = dayOfCycle / totalDays;
final daysUntilNextPeriod = totalDays - dayOfCycle;
@@ -82,12 +87,128 @@ class CycleRing extends StatelessWidget {
style: GoogleFonts.outfit(
fontSize: 12,
color: AppColors.warmGray,
=======
State<CycleRing> createState() => _CycleRingState();
}
class _CycleRingState extends State<CycleRing> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 1500),
);
_animation = CurvedAnimation(
parent: _controller,
curve: Curves.easeOutCubic,
);
_controller.forward();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final targetProgress = widget.dayOfCycle / widget.totalDays;
final daysUntilNextPeriod = widget.totalDays - widget.dayOfCycle;
final isDark = Theme.of(context).brightness == Brightness.dark;
return AnimatedBuilder(
animation: _animation,
builder: (context, child) {
final currentProgress = targetProgress * _animation.value;
return SizedBox(
width: 220,
height: 220,
child: Stack(
alignment: Alignment.center,
children: [
// Background ring
CustomPaint(
size: const Size(220, 220),
painter: _CycleRingPainter(
progress: currentProgress,
phase: widget.phase,
isDark: isDark,
),
),
// Center content with scale and fade animation
Transform.scale(
scale: 0.8 + (0.2 * _animation.value),
child: Opacity(
opacity: _animation.value,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Day ${widget.dayOfCycle}',
style: Theme.of(context).textTheme.displayMedium?.copyWith(
fontSize: 32,
fontWeight: FontWeight.w600,
color: Theme.of(context).colorScheme.onSurface,
),
),
const SizedBox(height: 4),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: _getPhaseColor(widget.phase).withOpacity(isDark ? 0.3 : 0.2),
borderRadius: BorderRadius.circular(20),
border: isDark ? Border.all(color: _getPhaseColor(widget.phase).withOpacity(0.5)) : null,
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
widget.phase.emoji,
style: const TextStyle(fontSize: 14),
),
const SizedBox(width: 6),
Text(
widget.phase.label,
style: GoogleFonts.outfit(
fontSize: 14,
fontWeight: FontWeight.w500,
color: isDark ? Colors.white : _getPhaseColor(widget.phase),
),
),
],
),
),
const SizedBox(height: 8),
Text(
daysUntilNextPeriod > 0
? '$daysUntilNextPeriod days until period'
: 'Period expected',
style: Theme.of(context).textTheme.bodySmall?.copyWith(
fontSize: 12,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
),
>>>>>>> 6742220 (Your commit message here)
),
),
],
),
<<<<<<< HEAD
],
),
=======
);
},
>>>>>>> 6742220 (Your commit message here)
);
}
@@ -108,8 +229,18 @@ class CycleRing extends StatelessWidget {
class _CycleRingPainter extends CustomPainter {
final double progress;
final CyclePhase phase;
<<<<<<< HEAD
_CycleRingPainter({required this.progress, required this.phase});
=======
final bool isDark;
_CycleRingPainter({
required this.progress,
required this.phase,
required this.isDark,
});
>>>>>>> 6742220 (Your commit message here)
@override
void paint(Canvas canvas, Size size) {
@@ -119,7 +250,11 @@ class _CycleRingPainter extends CustomPainter {
// Background arc
final bgPaint = Paint()
<<<<<<< HEAD
..color = AppColors.lightGray.withOpacity(0.2)
=======
..color = (isDark ? Colors.white : AppColors.lightGray).withOpacity(isDark ? 0.05 : 0.1)
>>>>>>> 6742220 (Your commit message here)
..style = PaintingStyle.stroke
..strokeWidth = strokeWidth
..strokeCap = StrokeCap.round;
@@ -152,7 +287,11 @@ class _CycleRingPainter extends CustomPainter {
final dotY = center.dy + radius * math.sin(dotAngle);
final dotPaint = Paint()
<<<<<<< HEAD
..color = Colors.white
=======
..color = isDark ? const Color(0xFF1E1E1E) : Colors.white
>>>>>>> 6742220 (Your commit message here)
..style = PaintingStyle.fill;
final dotBorderPaint = Paint()