Preserve Flutter mirror-os codebase

This commit is contained in:
Chris
2026-07-11 21:51:34 -05:00
commit 27631ed108
142 changed files with 11896 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
import 'package:flutter/material.dart';
class MirrorAnimations {
MirrorAnimations._();
static const screenTransitionDuration = Duration(milliseconds: 800);
static const quickTransitionDuration = Duration(milliseconds: 300);
static const overlayFadeDuration = Duration(milliseconds: 500);
static Widget screenTransitionBuilder(
Widget child,
Animation<double> animation,
) {
return FadeTransition(
opacity: animation,
child: ScaleTransition(
scale: Tween(begin: 0.95, end: 1.0).animate(
CurvedAnimation(parent: animation, curve: Curves.easeOutCubic),
),
child: child,
),
);
}
static Widget slideUpTransitionBuilder(
Widget child,
Animation<double> animation,
) {
return FadeTransition(
opacity: animation,
child: SlideTransition(
position: Tween(
begin: const Offset(0, 0.05),
end: Offset.zero,
).animate(CurvedAnimation(parent: animation, curve: Curves.easeOutCubic)),
child: child,
),
);
}
}
+6
View File
@@ -0,0 +1,6 @@
library mirror_ui;
export 'theme.dart';
export 'animations.dart';
export 'widgets/progress_ring.dart';
export 'widgets/timer_display.dart';
+110
View File
@@ -0,0 +1,110 @@
import 'package:flutter/material.dart';
class MirrorTheme {
MirrorTheme._();
static const _zinc50 = Color(0xFFFAFAFA);
static const _zinc100 = Color(0xFFF4F4F5);
static const _zinc200 = Color(0xFFE4E4E7);
static const _zinc400 = Color(0xFFA1A1AA);
static const _zinc500 = Color(0xFF71717A);
static const _zinc700 = Color(0xFF3F3F46);
static const _zinc800 = Color(0xFF27272A);
static const _zinc900 = Color(0xFF18181B);
static const _zinc950 = Color(0xFF09090B);
static const _accent = Color(0xFF60A5FA); // blue-400
static const _accentDim = Color(0xFF1E3A5F);
static const _success = Color(0xFF4ADE80); // green-400
static const _danger = Color(0xFFF87171); // red-400
static const _warning = Color(0xFFFBBF24); // amber-400
static const fontFamily = 'Inter';
static const fontMono = 'JetBrains Mono';
static ThemeData get dark => ThemeData(
brightness: Brightness.dark,
fontFamily: fontFamily,
scaffoldBackgroundColor: _zinc950,
colorScheme: const ColorScheme.dark(
surface: _zinc900,
primary: _accent,
secondary: _zinc700,
error: _danger,
onSurface: _zinc100,
onPrimary: _zinc950,
),
cardTheme: const CardThemeData(
color: _zinc900,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(16)),
),
),
textTheme: const TextTheme(
displayLarge: TextStyle(
fontSize: 96,
fontWeight: FontWeight.w200,
fontFamily: fontMono,
color: _zinc50,
letterSpacing: -2,
),
displayMedium: TextStyle(
fontSize: 60,
fontWeight: FontWeight.w200,
fontFamily: fontMono,
color: _zinc50,
),
displaySmall: TextStyle(
fontSize: 36,
fontWeight: FontWeight.w300,
color: _zinc50,
),
headlineLarge: TextStyle(
fontSize: 28,
fontWeight: FontWeight.w600,
color: _zinc50,
),
headlineMedium: TextStyle(
fontSize: 22,
fontWeight: FontWeight.w500,
color: _zinc50,
),
bodyLarge: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w400,
color: _zinc200,
),
bodyMedium: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w400,
color: _zinc400,
),
bodySmall: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: _zinc500,
),
labelLarge: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w600,
color: _zinc50,
letterSpacing: 1.5,
),
),
iconTheme: const IconThemeData(color: _zinc400, size: 24),
dividerColor: _zinc800,
);
static const Color accent = _accent;
static const Color accentDim = _accentDim;
static const Color success = _success;
static const Color danger = _danger;
static const Color warning = _warning;
static const Color surface = _zinc900;
static const Color surfaceLight = _zinc800;
static const Color background = _zinc950;
static const Color textPrimary = _zinc50;
static const Color textSecondary = _zinc400;
static const Color textMuted = _zinc500;
}
@@ -0,0 +1,86 @@
import 'dart:math' as math;
import 'package:flutter/material.dart';
import '../theme.dart';
class ProgressRing extends StatelessWidget {
final double percent;
final double size;
final double strokeWidth;
final Color? color;
final Color? backgroundColor;
const ProgressRing({
super.key,
required this.percent,
this.size = 36,
this.strokeWidth = 3,
this.color,
this.backgroundColor,
});
@override
Widget build(BuildContext context) {
final effectiveColor = percent >= 95
? MirrorTheme.success
: (color ?? MirrorTheme.accent);
return SizedBox(
width: size,
height: size,
child: CustomPaint(
painter: _ProgressRingPainter(
percent: percent.clamp(0, 100),
strokeWidth: strokeWidth,
color: effectiveColor,
backgroundColor: backgroundColor ?? MirrorTheme.surfaceLight,
),
),
);
}
}
class _ProgressRingPainter extends CustomPainter {
final double percent;
final double strokeWidth;
final Color color;
final Color backgroundColor;
_ProgressRingPainter({
required this.percent,
required this.strokeWidth,
required this.color,
required this.backgroundColor,
});
@override
void paint(Canvas canvas, Size size) {
final center = Offset(size.width / 2, size.height / 2);
final radius = (size.width - strokeWidth) / 2;
final bgPaint = Paint()
..color = backgroundColor
..style = PaintingStyle.stroke
..strokeWidth = strokeWidth;
final fgPaint = Paint()
..color = color
..style = PaintingStyle.stroke
..strokeWidth = strokeWidth
..strokeCap = StrokeCap.round;
canvas.drawCircle(center, radius, bgPaint);
final sweepAngle = (percent / 100) * 2 * math.pi;
canvas.drawArc(
Rect.fromCircle(center: center, radius: radius),
-math.pi / 2,
sweepAngle,
false,
fgPaint,
);
}
@override
bool shouldRepaint(_ProgressRingPainter oldDelegate) =>
oldDelegate.percent != percent || oldDelegate.color != color;
}
@@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import '../theme.dart';
class TimerDisplay extends StatelessWidget {
final int seconds;
final String? label;
final TextStyle? style;
const TimerDisplay({
super.key,
required this.seconds,
this.label,
this.style,
});
@override
Widget build(BuildContext context) {
final minutes = seconds ~/ 60;
final secs = seconds % 60;
final timeText = minutes > 0
? '$minutes:${secs.toString().padLeft(2, '0')}'
: '$secs';
return Column(
mainAxisSize: MainAxisSize.min,
children: [
if (label != null)
Text(
label!,
style: Theme.of(context).textTheme.labelLarge?.copyWith(
color: MirrorTheme.accent,
letterSpacing: 8,
),
),
if (label != null) const SizedBox(height: 40),
Text(
timeText,
style: style ?? Theme.of(context).textTheme.displayLarge?.copyWith(
color: MirrorTheme.accent,
),
),
],
);
}
}
+17
View File
@@ -0,0 +1,17 @@
name: mirror_ui
description: Shared theme, animations, and common widgets for Mirror OS
version: 0.1.0
publish_to: none
resolution: workspace
environment:
sdk: ^3.5.0
flutter: ^3.24.0
dependencies:
flutter:
sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter