Skip to main content

gravix_effects 1.1.2 copy "gravix_effects: ^1.1.2" to clipboard
gravix_effects: ^1.1.2 copied to clipboard

PlatformAndroid

Gravix Effects — real-time beauty filter, reshape, makeup and looks for Flutter livestreaming. Outputs: gravix_effects_webrtc, gravix_effects_agora.

example/lib/main.dart

// Gravix Effects — the smallest complete integration: the camera with effects, a row of looks and the ready-made
// beauty panel. No streaming here — to send the picture to viewers, see gravix_effects_webrtc/example (LiveKit /
// flutter_webrtc) or gravix_effects_agora/example (Agora).
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:gravix_effects/beauty_ui.dart';
import 'package:gravix_effects/gravix_effects.dart';

void main() => runApp(const MaterialApp(debugShowCheckedModeBanner: false, home: CameraScreen()));

class CameraScreen extends StatefulWidget {
  const CameraScreen({super.key});
  @override
  State<CameraScreen> createState() => _CameraScreenState();
}

class _CameraScreenState extends State<CameraScreen> {
  final _beauty = GravixBeautyController.shared; // remembers the chosen look + sliders across camera restarts
  GravixCamera? _cam;
  List<GravixLook> _looks = const [];
  String? _error;

  @override
  void initState() {
    super.initState();
    _start();
  }

  Future<void> _start() async {
    if (!GravixCamera.isSupported) return setState(() => _error = 'Gravix Effects runs on Android only.');
    try {
      unawaited(GravixCamera.preload()); // loads the face model while the permission dialog is open
      if (!await GravixCamera.requestPermission()) return setState(() => _error = 'Camera permission is needed.');
      final cam = await GravixCamera.start(lens: GravixLens.front, fps: 30);
      await _beauty.attach(cam);
      final looks = [for (final name in await cam.builtinLooks()) await GravixLooks.builtin(name)];
      if (!mounted) {
        await cam.stop();
        return;
      }
      setState(() {
        _cam = cam;
        _looks = looks;
      });
    } on GravixException catch (e) {
      setState(() => _error = 'Camera error ${e.code}: ${e.message ?? ''}');
    }
  }

  @override
  void dispose() {
    final cam = _cam;
    if (cam != null) {
      _beauty.detach(cam);
      cam.stop();
    }
    super.dispose();
  }

  void _openBeautyPanel() => showModalBottomSheet(
        context: context,
        backgroundColor: Colors.transparent,
        barrierColor: Colors.transparent,
        builder: (_) => GravixBeautyPanel(controller: _beauty),
      );

  @override
  Widget build(BuildContext context) {
    final cam = _cam;
    return Scaffold(
      backgroundColor: Colors.black,
      body: Stack(fit: StackFit.expand, children: [
        if (cam != null)
          GravixPreview(cam) // mirrored for the front camera, fills the screen
        else
          Center(
            child: _error == null
                ? const CircularProgressIndicator()
                : Text(_error!, style: const TextStyle(color: Colors.white), textAlign: TextAlign.center),
          ),
        if (cam != null)
          Align(
            alignment: Alignment.bottomCenter,
            child: SafeArea(
              child: Column(mainAxisSize: MainAxisSize.min, children: [
                LooksRow(looks: _looks, controller: _beauty),
                Padding(
                  padding: const EdgeInsets.all(16),
                  child: Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
                    FilledButton.tonalIcon(
                        onPressed: _openBeautyPanel, icon: const Icon(Icons.face_retouching_natural), label: const Text('Beauty')),
                    FilledButton.tonalIcon(onPressed: cam.switchCamera, icon: const Icon(Icons.cameraswitch), label: const Text('Flip')),
                  ]),
                ),
              ]),
            ),
          ),
      ]),
    );
  }
}

/// The built-in looks as tappable thumbnails; the chosen one is outlined.
class LooksRow extends StatelessWidget {
  const LooksRow({super.key, required this.looks, required this.controller});
  final List<GravixLook> looks;
  final GravixBeautyController controller;

  @override
  Widget build(BuildContext context) => ListenableBuilder(
        listenable: controller,
        builder: (context, _) => SizedBox(
          height: 92,
          child: ListView(scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 12), children: [
            for (final look in looks)
              GestureDetector(
                onTap: () => controller.selectLookFile(look),
                child: Container(
                  width: 68,
                  margin: const EdgeInsets.symmetric(horizontal: 4),
                  child: Column(children: [
                    Container(
                      width: 60,
                      height: 60,
                      decoration: BoxDecoration(
                        borderRadius: BorderRadius.circular(12),
                        border: Border.all(color: controller.isLook(look) ? Colors.white : Colors.transparent, width: 2),
                        image: look.thumbnail == null ? null : DecorationImage(image: MemoryImage(look.thumbnail!), fit: BoxFit.cover),
                        color: Colors.white24,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(look.name, style: const TextStyle(color: Colors.white, fontSize: 11), overflow: TextOverflow.ellipsis),
                  ]),
                ),
              ),
          ]),
        ),
      );
}
1
likes
140
points
36
downloads

Documentation

API reference

Publisher

verified publishergravixcloud.com

Weekly Downloads

Gravix Effects — real-time beauty filter, reshape, makeup and looks for Flutter livestreaming. Outputs: gravix_effects_webrtc, gravix_effects_agora.

Homepage

License

unknown (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on gravix_effects

Packages that implement gravix_effects