context_curtain 1.1.5
context_curtain: ^1.1.5 copied to clipboard
A premium UI/UX widget that creates an organic, physics-based canvas flutter animation for high-end features and menu reveals.
example/lib/main.dart
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:context_curtain/curtain_flutter.dart';
void main() {
runApp(const CurtainPackageExampleApp());
}
/// Root app shell for the package demonstration application workspace.
class CurtainPackageExampleApp extends StatelessWidget {
/// Default constructor for root app.
const CurtainPackageExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Context Curtain Stress Engine',
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.redAccent,
brightness: Brightness.dark,
),
),
home: const ExampleShowcaseScreen(),
);
}
}
/// Demo presentation showcase environment screen with heavy performance overlays.
class ExampleShowcaseScreen extends StatefulWidget {
/// Default constructor for screen component.
const ExampleShowcaseScreen({super.key});
@override
State<ExampleShowcaseScreen> createState() => _ExampleShowcaseScreenState();
}
class _ExampleShowcaseScreenState extends State<ExampleShowcaseScreen> {
// Decentralized controllers managing isolated animation layer spaces
final CurtainController _slideOneController = CurtainController();
final CurtainController _slideTwoController = CurtainController();
int _currentSlideIndex = 0;
bool _isStressLoopActive = false;
Ticker? _stressTicker;
@override
void dispose() {
_stressTicker?.dispose();
_slideOneController.dispose();
_slideTwoController.dispose();
super.dispose();
}
/// Toggles an aggressive programmatic animation loop to test pipeline stability
/// under violent, high-frequency layout mutations.
void _toggleStressLoop() {
setState(() {
_isStressLoopActive = !_isStressLoopActive;
});
if (_isStressLoopActive) {
int ticks = 0;
_stressTicker = Ticker((elapsed) {
ticks++;
// Rapidly oscillate state triggers every 45 frames
if (ticks % 45 == 0) {
final nextTarget = (_currentSlideIndex + 1) % 3;
_navigateTo(nextTarget);
}
});
_stressTicker!.start();
} else {
_stressTicker?.stop();
_stressTicker = null;
}
}
/// Centralized state routing processor that resolves index modifications
/// sequentially across nested layouts without frame-skip artifacts.
void _navigateTo(int index) {
if (index == _currentSlideIndex && !_isStressLoopActive) return;
setState(() => _currentSlideIndex = index);
// Cascading logical transitions to safeguard against layout timeline clashes
if (index == 0) {
_slideTwoController.close();
_slideOneController.close();
} else if (index == 1) {
_slideOneController.reveal();
_slideTwoController.close();
} else if (index == 2) {
_slideOneController.reveal();
_slideTwoController.reveal();
}
}
void _next() {
if (_currentSlideIndex < 2) _navigateTo(_currentSlideIndex + 1);
}
void _back() {
if (_currentSlideIndex > 0) _navigateTo(_currentSlideIndex - 1);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Stack(
children: [
/// =================================================================
/// CURTAIN NESTING CASCADE STRESS ENGINE
/// =================================================================
CurtainReveal(
controller: _slideOneController,
side: CurtainSide.right,
curtainColor: const Color(0xFF1E1B4B), // Deep Slate/Indigo
elevation: 40,
revealedBackground: CurtainReveal(
controller: _slideTwoController,
side: CurtainSide.bottom,
curtainColor: const Color(0xFF0F172A), // Deep Charcoal
elevation: 40,
// SLIDE LAYER 03: Vector Field Noise System (Heavy Custom Paint Rendering)
revealedBackground: _buildStressSlide(
"03 / VECTOR FLUID",
"Matrix Particle Core",
Colors.greenAccent,
const ParticleStressBackground(color: Colors.greenAccent),
),
// SLIDE LAYER 02: Math Transform Grid System (Heavy Layout Math Layout)
child: _buildStressSlide(
"02 / RENDER BLOCK",
"Dynamic Matrix Fields",
Colors.cyanAccent,
const RotatingMatrixStressBackground(),
),
),
// SLIDE LAYER 01: Default Home Layout Cover
child: _buildStressSlide(
"01 / SANDBOX CORE",
"Pipeline Stress Shell",
Colors.amberAccent,
const ParticleStressBackground(color: Colors.amberAccent),
),
),
/// =================================================================
/// TOP COMPONENT: ANCHOR POPUP INDEX DROPDOWN SHORTCUTS MENU
/// =================================================================
Positioned(
top: 0,
left: 0,
right: 0,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
const Text(
"CURTAIN STRESS ENGINE",
style: TextStyle(
fontWeight: FontWeight.w900,
letterSpacing: 2.0,
fontSize: 12,
),
),
const SizedBox(width: 8),
_PerformanceTag(isActive: _isStressLoopActive),
],
),
PopupMenuButton<int>(
tooltip: "Jump directly to structural index",
icon: const CircleAvatar(
backgroundColor: Colors.black54,
child: Icon(Icons.apps_rounded, color: Colors.white, size: 20),
),
onSelected: _navigateTo,
itemBuilder: (context) => [
const PopupMenuItem(value: 0, child: Text("Slide 1: Engine Core")),
const PopupMenuItem(value: 1, child: Text("Slide 2: Matrix Grid")),
const PopupMenuItem(value: 2, child: Text("Slide 3: Fluid Fields")),
],
),
],
),
),
),
),
/// =================================================================
/// BOTTOM COMPONENT: PERSISTENT SYNCED FLOATING NAV PANEL
/// =================================================================
Positioned(
bottom: 36,
left: 24,
right: 24,
child: Center(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: Colors.black.withValues(alpha: 0.85),
borderRadius: BorderRadius.circular(24),
border: Border.all(color: Colors.white10),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
onPressed: _currentSlideIndex > 0 ? _back : null,
icon: const Icon(Icons.arrow_back_ios_new, size: 14),
tooltip: "Previous Slide",
),
const SizedBox(width: 12),
Text(
"SLIDE ${_currentSlideIndex + 1} / 3",
style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13, letterSpacing: 1.0),
),
const SizedBox(width: 12),
IconButton(
onPressed: _currentSlideIndex < 2 ? _next : null,
icon: const Icon(Icons.arrow_forward_ios, size: 14),
tooltip: "Next Slide",
),
const SizedBox(width: 8),
const VerticalDivider(color: Colors.white24, width: 1, indent: 8, endIndent: 8),
const SizedBox(width: 8),
// Core Stress-Testing Run Button Trigger
ElevatedButton.icon(
onPressed: _toggleStressLoop,
icon: Icon(
_isStressLoopActive ? Icons.stop_circle_rounded : Icons.bolt_rounded,
size: 16,
color: Colors.white,
),
label: Text(_isStressLoopActive ? "STOP" : "STRESS TEST"),
style: ElevatedButton.styleFrom(
backgroundColor: _isStressLoopActive ? const Color.fromARGB(255, 160, 18, 8) : Colors.redAccent.withValues(alpha: 0.3),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(14)),
),
),
],
),
),
),
),
],
),
);
}
/// Complex blueprint helper that weaves animation heavy testing modules behind layout texts
Widget _buildStressSlide(String title, String subtitle, Color accent, Widget performanceBackground) {
return Stack(
fit: StackFit.expand,
children: [
// Heavy background background calculation engine pass
performanceBackground,
Container(
color: Colors.black.withValues(alpha: 0.4), // Darken layer to protect reading visibility
),
SafeArea(
child: Padding(
padding: const EdgeInsets.all(40),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Spacer(),
Icon(Icons.layers, size: 64, color: accent),
const SizedBox(height: 24),
Text(
title,
style: TextStyle(color: accent, fontWeight: FontWeight.bold, letterSpacing: 3.5, fontSize: 13),
),
const SizedBox(height: 8),
Text(
subtitle,
style: const TextStyle(fontSize: 36, fontWeight: FontWeight.bold, letterSpacing: -1.0, height: 1.1),
),
const SizedBox(height: 12),
const Text(
"Executing real-time graphics pipelines underneath this stack layout sheet. Use multi-touch gestures directly on the cloth borders to verify frame rates.",
style: TextStyle(color: Colors.white60, fontSize: 14, height: 1.4),
),
const Spacer(),
],
),
),
),
],
);
}
}
/// Helper tag indicating execution status state
class _PerformanceTag extends StatelessWidget {
final bool isActive;
const _PerformanceTag({required this.isActive});
@override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: isActive ? Colors.red : Colors.green.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(8),
),
child: Text(
isActive ? "LOOP ACTIVE (THRASHING)" : "STABLE",
style: const TextStyle(fontSize: 9, fontWeight: FontWeight.bold, color: Colors.white),
),
);
}
}
/// =========================================================================
/// STRESS WORKLOAD MODULE 1: CUSTOM PAINTED PARTICLE SYSTEM FIELD
/// Forces high frequency canvas sweeps per paint invocation frame pass
/// =========================================================================
class ParticleStressBackground extends StatefulWidget {
final Color color;
const ParticleStressBackground({super.key, required this.color});
@override
State<ParticleStressBackground> createState() => _ParticleStressBackgroundState();
}
class _ParticleStressBackgroundState extends State<ParticleStressBackground> with SingleTickerProviderStateMixin {
late List<_StressParticle> particles;
late AnimationController _tickerController;
final math.Random random = math.Random();
@override
void initState() {
super.initState();
// Spawns 120 isolated objects running spatial math loops
particles = List.generate(120, (_) => _StressParticle(random));
_tickerController = AnimationController(vsync: this, duration: const Duration(days: 1))..forward();
}
@override
void dispose() {
_tickerController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _tickerController,
builder: (context, _) {
for (var p in particles) {
p.update();
}
return CustomPaint(
painter: _ParticleFieldPainter(particles: particles, baseColor: widget.color),
);
},
);
}
}
class _StressParticle {
late double x, y, vx, vy, size;
final math.Random r;
_StressParticle(this.r) {
reset();
}
void reset() {
x = r.nextDouble() * 400;
y = r.nextDouble() * 800;
vx = (r.nextDouble() - 0.5) * 2.5;
vy = (r.nextDouble() - 0.5) * 2.5;
size = r.nextDouble() * 4 + 2;
}
void update() {
x += vx;
y += vy;
if (x < 0 || x > 500 || y < 0 || y > 900) reset();
}
}
class _ParticleFieldPainter extends CustomPainter {
final List<_StressParticle> particles;
final Color baseColor;
_ParticleFieldPainter({required this.particles, required this.baseColor});
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()..style = PaintingStyle.fill..isAntiAlias = false;
for (var p in particles) {
paint.color = baseColor.withValues(alpha: (p.size / 6).clamp(0.1, 0.6));
canvas.drawCircle(Offset(p.x % size.width, p.y % size.height), p.size, paint);
}
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
/// =========================================================================
/// STRESS WORKLOAD MODULE 2: RECURSIVE MATRIX MATH DISPLAY GRID
/// Forces rendering matrix modifications down the layout layout tree
/// =========================================================================
class RotatingMatrixStressBackground extends StatefulWidget {
const RotatingMatrixStressBackground({super.key});
@override
State<RotatingMatrixStressBackground> createState() => _RotatingMatrixStressBackgroundState();
}
class _RotatingMatrixStressBackgroundState extends State<RotatingMatrixStressBackground> with SingleTickerProviderStateMixin {
late AnimationController _rotationController;
@override
void initState() {
super.initState();
_rotationController = AnimationController(vsync: this, duration: const Duration(seconds: 4))..repeat();
}
@override
void dispose() {
_rotationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _rotationController,
builder: (context, _) {
return GridView.builder(
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 8),
itemCount: 96,
itemBuilder: (context, index) {
final double angle = _rotationController.value * math.pi * 2 + (index * 0.1);
return Transform(
alignment: Alignment.center,
transform: Matrix4.identity()
..setEntry(3, 2, 0.002)
..rotateX(angle)
..rotateY(angle * 0.5),
child: Container(
margin: const EdgeInsets.all(4),
decoration: BoxDecoration(
color: Colors.cyanAccent.withValues(alpha: (math.sin(angle).abs() * 0.15).clamp(0.02, 0.2)),
border: Border.all(color: Colors.cyan.withValues(alpha: 0.2), width: 1),
borderRadius: BorderRadius.circular(4),
),
child: const Center(
child: Icon(Icons.refresh_rounded, size: 12, color: Colors.cyanAccent),
),
),
);
},
);
},
);
}
}
// Extension to map custom color patterns on loop boundaries
extension on Colors {
}