pixelflux_codecerebrum 1.1.0 copy "pixelflux_codecerebrum: ^1.1.0" to clipboard
pixelflux_codecerebrum: ^1.1.0 copied to clipboard

Official Flutter package of PixelFlux app. Render your PixelFlux (.pxlflux) files in Flutter with full animation control.

example/main.dart

import 'package:flutter/material.dart';
import 'package:pixelflux_codecerebrum/pixelflux_codecerebrum.dart';

void main() {
  runApp(const PixelFluxDemoApp());
}

class PixelFluxDemoApp extends StatelessWidget {
  const PixelFluxDemoApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'PixelFlux Demo',
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF6750A4),
          brightness: Brightness.dark,
        ),
        cardTheme: CardThemeData(
          elevation: 8,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(16),
          ),
        ),
      ),
      home: const PixelFluxHomePage(),
    );
  }
}

class PixelFluxHomePage extends StatefulWidget {
  const PixelFluxHomePage({super.key});

  @override
  State<PixelFluxHomePage> createState() => _PixelFluxHomePageState();
}

class _PixelFluxHomePageState extends State<PixelFluxHomePage> {
  final controller = PixelFluxController();
  PixelFluxProject? project;
  bool isLoading = true;

  @override
  void initState() {
    super.initState();
    _load();
    // Listen to controller status changes to update UI
    controller.status.addListener(_onStatusChanged);
  }

  void _onStatusChanged() {
    if (mounted) {
      setState(() {});
    }
  }

  Future<void> _load() async {
    try {
      // Swap between image / video for testing
      // project = await PixelFluxLoader.loadFromAsset("assets/sample_image.pxlflux");
      project = await PixelFluxLoader.loadFromAsset("assets/sample_video.pxlflux");
    } catch (e) {
      debugPrint('Error loading project: $e');
    } finally {
      if (mounted) {
        setState(() {
          isLoading = false;
        });
      }
    }
  }

  @override
  void dispose() {
    controller.status.removeListener(_onStatusChanged);
    controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Theme.of(context).colorScheme.surface,
      appBar: AppBar(
        title: const Text(
          "PixelFlux Studio",
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
        centerTitle: true,
        backgroundColor: Colors.transparent,
        elevation: 0,
        flexibleSpace: Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              colors: [
                Theme.of(context).colorScheme.primaryContainer,
                Theme.of(context).colorScheme.secondaryContainer,
              ],
            ),
          ),
        ),
      ),
      body: Container(
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.topCenter,
            end: Alignment.bottomCenter,
            colors: [
              Theme.of(context).colorScheme.surface,
              Theme.of(context).colorScheme.surface.withValues(alpha: 0.8),
            ],
          ),
        ),
        child: Center(
          child: isLoading
              ? _buildLoadingWidget()
              : project == null
                  ? _buildErrorWidget()
                  : _buildContent(),
        ),
      ),
    );
  }

  Widget _buildLoadingWidget() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(32.0),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            const CircularProgressIndicator(),
            const SizedBox(height: 16),
            Text(
              'Loading PixelFlux Project...',
              style: Theme.of(context).textTheme.titleMedium,
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildErrorWidget() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(32.0),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Icon(
              Icons.error_outline,
              size: 48,
              color: Theme.of(context).colorScheme.error,
            ),
            const SizedBox(height: 16),
            Text(
              'Failed to load project',
              style: Theme.of(context).textTheme.titleMedium,
            ),
            const SizedBox(height: 8),
            FilledButton.tonal(
              onPressed: () {
                setState(() {
                  isLoading = true;
                });
                _load();
              },
              child: const Text('Retry'),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildContent() {
    final p = project!;
    return SingleChildScrollView(
      padding: const EdgeInsets.all(16.0),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          // Canvas Card
          Card(
            child: Padding(
              padding: const EdgeInsets.all(24.0),
              child: Column(
                children: [
                  Container(
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(12),
                      boxShadow: [
                        BoxShadow(
                          color: Colors.black.withValues(alpha: 0.3),
                          blurRadius: 8,
                          offset: const Offset(0, 4),
                        ),
                      ],
                    ),
                    child: ClipRRect(
                      borderRadius: BorderRadius.circular(12),
                      child: PixelFluxCanvas(
                        project: p,
                        controller: controller,
                        canvasWidth: 320,
                        canvasHeight: 240,
                        pixelSize: 12.0,
                        showPixelBorders: true,
                        scale: 1.5,
                        rotation: 0.3, // ~17 degrees
                        flipHorizontal: false,
                        flipVertical: true,
                        translateX: 20,
                        translateY: -10,
                      ),
                    ),
                  ),
                  const SizedBox(height: 16),
                  Text(
                    p.isVideo ? 'Video Project' : 'Image Project',
                    style: Theme.of(context).textTheme.labelLarge?.copyWith(
                      color: Theme.of(context).colorScheme.primary,
                      fontWeight: FontWeight.w600,
                    ),
                  ),
                ],
              ),
            ),
          ),
          
          const SizedBox(height: 16),
          
          // Controls Card (only for video)
          if (p.isVideo) _buildControlsCard(),
        ],
      ),
    );
  }

  Widget _buildControlsCard() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(20.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Playback Controls',
              style: Theme.of(context).textTheme.titleMedium?.copyWith(
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 16),
            
            // Playback buttons
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                _buildControlButton(
                  icon: Icons.play_arrow_rounded,
                  onPressed: controller.play,
                  tooltip: 'Play',
                ),
                _buildControlButton(
                  icon: Icons.pause_rounded,
                  onPressed: controller.pause,
                  tooltip: 'Pause',
                ),
                _buildControlButton(
                  icon: Icons.stop_rounded,
                  onPressed: controller.stop,
                  tooltip: 'Stop',
                ),
                _buildControlButton(
                  icon: Icons.swap_horiz_rounded,
                  onPressed: () => controller.reverse(),
                  tooltip: 'Reverse',
                ),
              ],
            ),
            
            const SizedBox(height: 24),
            
            // Loop mode selector
            ValueListenableBuilder(
              valueListenable: controller.status,
              builder: (context, status, _) {
                return Row(
                  children: [
                    Icon(
                      Icons.loop_rounded,
                      size: 20,
                      color: Theme.of(context).colorScheme.primary,
                    ),
                    const SizedBox(width: 8),
                    Text(
                      'Loop Mode:',
                      style: Theme.of(context).textTheme.titleSmall,
                    ),
                    const SizedBox(width: 12),
                    Expanded(
                      child: DropdownButtonFormField<LoopMode>(
                        initialValue: status.loopMode,
                        decoration: InputDecoration(
                          border: OutlineInputBorder(
                            borderRadius: BorderRadius.circular(8),
                          ),
                          contentPadding: const EdgeInsets.symmetric(
                            horizontal: 12,
                            vertical: 8,
                          ),
                          filled: true,
                          fillColor: Theme.of(context).colorScheme.surfaceContainerHighest.withValues(alpha: 0.3),
                        ),
                        onChanged: (m) => controller.setLoopMode(m ?? LoopMode.loop),
                        items: const [
                          DropdownMenuItem(
                            value: LoopMode.once,
                            child: Text("Once"),
                          ),
                          DropdownMenuItem(
                            value: LoopMode.loop,
                            child: Text("Loop"),
                          ),
                          DropdownMenuItem(
                            value: LoopMode.pingPong,
                            child: Text("Ping-Pong"),
                          ),
                        ],
                      ),
                    ),
                  ],
                );
              },
            ),
            
            const SizedBox(height: 20),
            
            // Speed slider
            Row(
              children: [
                Icon(
                  Icons.speed_rounded,
                  size: 20,
                  color: Theme.of(context).colorScheme.primary,
                ),
                const SizedBox(width: 8),
                Text(
                  'Speed:',
                  style: Theme.of(context).textTheme.titleSmall,
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      ValueListenableBuilder(
                        valueListenable: controller.status,
                        builder: (context, status, _) {
                          return Slider(
                            value: status.speed,
                            onChanged: (v) => controller.setSpeed(v),
                            min: 0.1,
                            max: 4.0,
                            divisions: 39,
                            label: "${status.speed.toStringAsFixed(1)}x",
                          );
                        },
                      ),
                      Padding(
                        padding: const EdgeInsets.symmetric(horizontal: 16.0),
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: [
                            Text(
                              '0.1x',
                              style: Theme.of(context).textTheme.bodySmall,
                            ),
                            ValueListenableBuilder(
                              valueListenable: controller.status,
                              builder: (context, status, _) {
                                return Text(
                                  '${status.speed.toStringAsFixed(1)}x',
                                  style: Theme.of(context).textTheme.bodySmall?.copyWith(
                                    fontWeight: FontWeight.bold,
                                    color: Theme.of(context).colorScheme.primary,
                                  ),
                                );
                              },
                            ),
                            Text(
                              '4.0x',
                              style: Theme.of(context).textTheme.bodySmall,
                            ),
                          ],
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildControlButton({
    required IconData icon,
    required VoidCallback onPressed,
    required String tooltip,
  }) {
    return Tooltip(
      message: tooltip,
      child: FilledButton.tonal(
        onPressed: onPressed,
        style: FilledButton.styleFrom(
          shape: const CircleBorder(),
          padding: const EdgeInsets.all(16),
        ),
        child: Icon(icon, size: 24),
      ),
    );
  }
}
1
likes
160
points
13
downloads

Documentation

API reference

Publisher

verified publishercodecerebrum.in

Weekly Downloads

Official Flutter package of PixelFlux app. Render your PixelFlux (.pxlflux) files in Flutter with full animation control.

Homepage

License

MIT (license)

Dependencies

flutter, http

More

Packages that depend on pixelflux_codecerebrum