gyanmeet_flutter_sdk 1.2.1 copy "gyanmeet_flutter_sdk: ^1.2.1" to clipboard
gyanmeet_flutter_sdk: ^1.2.1 copied to clipboard

unlisted

Gyanmeet meeting SDK for Flutter — a self-contained video meeting widget with host controls, chat, polls, and optional on-device AI proctoring.

example/lib/main.dart

import 'dart:io';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:gyanmeet_flutter_sdk/gyanmeet_flutter_sdk.dart';

import 'dev_join.dart';

void main() => runApp(const ExampleApp());

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Gyanmeet Flutter SDK Example',
      debugShowCheckedModeBanner: false,
      home: JoinScreen(),
    );
  }
}

// Dev harness: enter API base + API key + room code, mint a token via the
// dev join flow, then embed GyanmeetMeeting with that token. In production the
// consumer's backend mints the token; the app never holds an API key.
class JoinScreen extends StatefulWidget {
  const JoinScreen({super.key});

  @override
  State<JoinScreen> createState() => _JoinScreenState();
}

class _JoinScreenState extends State<JoinScreen> {
  final _backend = TextEditingController(text: 'https://api.gyanmeet.com/api');
  // Dev-only prefill for quick local testing — do NOT commit a real API key.
  final _apiKey = TextEditingController(
      text: 'bbc64569648d2ed797c95f6cb7d192d3345759d1d81924a0027ec74e9c8aa173');
  final _roomCode = TextEditingController(text: 'N49-YT2-PFW');
  final _name = TextEditingController(text: 'Flutter Tester');
  final _email = TextEditingController(text: 'flutter@example.com');

  String? _token;
  bool _minting = false;
  String? _error;

  String? _compareResult;
  bool _comparing = false;

  Future<void> _compareFaces(
      String assetA, String assetB, String label) async {
    setState(() {
      _comparing = true;
      _compareResult = null;
    });
    try {
      final a = await _assetToFile(assetA, assetA.split('/').last);
      final b = await _assetToFile(assetB, assetB.split('/').last);

      const cfg = GyanmeetConfig();
      final ok = await FaceComparator.instance.init(cfg.faceModelAssetPath!);
      if (!ok) {
        setState(() => _compareResult = 'model load failed');
        return;
      }

      final baseEmb = await FaceComparator.instance.embedFromFile(a);
      if (baseEmb == null) {
        setState(() => _compareResult = 'no face in image A');
        return;
      }
      final sim =
          await FaceComparator.instance.similarityToBaseFromFile(baseEmb, b);
      if (sim == null) {
        setState(() => _compareResult = 'no face in image B');
        return;
      }
      final same = sim >= cfg.faceMatchThreshold;
      final msg =
          '$label: similarity=${sim.toStringAsFixed(4)}  threshold=${cfg.faceMatchThreshold}  '
          '=> ${same ? "SAME person" : "DIFFERENT person"}';
      debugPrint('[FACE COMPARE] $msg');
      setState(() => _compareResult = msg);
    } catch (e) {
      setState(() => _compareResult = 'error: $e');
    } finally {
      if (mounted) setState(() => _comparing = false);
    }
  }

  Future<File> _assetToFile(String asset, String name) async {
    final data = await rootBundle.load(asset);
    final f = File('${Directory.systemTemp.path}/$name');
    await f.writeAsBytes(data.buffer.asUint8List(), flush: true);
    return f;
  }

  // Reference image for the identity gate / manual-enroll. Loaded from assets
  // for testing; in production the consumer fetches it (backend photo, etc.).
  Uint8List? _referenceImage;

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

  Future<void> _loadReference() async {
    try {
      final data = await rootBundle.load('assets/reference/person_a.png');
      if (mounted) {
        setState(() => _referenceImage = data.buffer.asUint8List());
      }
    } catch (e) {
      debugPrint('reference load failed: $e');
    }
  }

  @override
  void dispose() {
    _backend.dispose();
    _apiKey.dispose();
    _roomCode.dispose();
    _name.dispose();
    _email.dispose();
    super.dispose();
  }

  Future<void> _mintAndJoin() async {
    setState(() {
      _minting = true;
      _error = null;
    });
    try {
      final token = await devMintToken(
        apiBase: _backend.text.trim(),
        apiKey: _apiKey.text.trim(),
        roomCode: _roomCode.text.trim(),
        name: _name.text.trim(),
        email: _email.text.trim(),
      );
      if (!mounted) return;
      setState(() {
        _token = token;
        _minting = false;
      });
    } catch (e) {
      if (!mounted) return;
      setState(() {
        _error = '$e';
        _minting = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    if (_token != null) {
      return ScaffoldMessenger(
        child: Builder(builder: (context) {
          return GyanmeetMeeting(
            backendUrl: _backend.text.trim(),
            token: _token!,
            config: const GyanmeetConfig(
              showPreJoin: true,
              enableIdentityVerificationGate: true,
            ),
            identityReferenceImage: _referenceImage,
            primaryColor: '#366D5A',
            onJoined: (id, role) => debugPrint('joined $id as $role'),
            onLeave: () => setState(() => _token = null),
            onEnded: () => setState(() => _token = null),
            onError: (e) => debugPrint('error: $e'),
            onFacePresenceChanged: (isPresent) =>
                debugPrint('Face present: $isPresent'),
            onGazeViolation: (reason) =>
                debugPrint('Gaze violation: $reason'),
            onIdentityMismatch: (similarity) =>
                debugPrint('Identity mismatch! similarity=$similarity'),
            onProctoringViolation: (v) => debugPrint(
                'PROCTORING VIOLATION: ${v.type} reason=${v.reason} sim=${v.similarity}'),
          );
        }),
      );
    }

    return Scaffold(
      appBar: AppBar(title: const Text('Gyanmeet SDK Example')),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(20),
        child: Column(
          children: [
            _field(_backend, 'Backend URL'),
            _field(_apiKey, 'API key (dev only)'),
            _field(_roomCode, 'Room code'),
            _field(_name, 'Display name'),
            _field(_email, 'Email'),
            const SizedBox(height: 20),
            if (_error != null)
              Padding(
                padding: const EdgeInsets.only(bottom: 12),
                child: Text(_error!,
                    style: const TextStyle(color: Color(0xFFDC2626))),
              ),
            SizedBox(
              width: double.infinity,
              child: ElevatedButton(
                onPressed: _minting ? null : _mintAndJoin,
                child: _minting
                    ? const SizedBox(
                        width: 18,
                        height: 18,
                        child: CircularProgressIndicator(strokeWidth: 2))
                    : const Text('Join meeting'),
              ),
            ),
            const SizedBox(height: 12),
            SizedBox(
              width: double.infinity,
              child: OutlinedButton(
                onPressed: _comparing
                    ? null
                    : () => _compareFaces('assets/reference/messi.jpg',
                        'assets/reference/neymar.jpg', 'messi vs neymar'),
                child: const Text('Compare messi vs neymar (diff)'),
              ),
            ),
            const SizedBox(height: 8),
            SizedBox(
              width: double.infinity,
              child: OutlinedButton(
                onPressed: _comparing
                    ? null
                    : () => _compareFaces('assets/reference/neymar.jpg',
                        'assets/reference/neymar2.jpg', 'neymar vs neymar2'),
                child: _comparing
                    ? const SizedBox(
                        width: 18,
                        height: 18,
                        child: CircularProgressIndicator(strokeWidth: 2))
                    : const Text('Compare neymar vs neymar2 (same)'),
              ),
            ),
            if (_compareResult != null)
              Padding(
                padding: const EdgeInsets.only(top: 12),
                child: Text(_compareResult!,
                    style: const TextStyle(fontWeight: FontWeight.w600)),
              ),
          ],
        ),
      ),
    );
  }

  Widget _field(TextEditingController c, String label) => Padding(
        padding: const EdgeInsets.only(bottom: 12),
        child: TextField(
          controller: c,
          decoration: InputDecoration(labelText: label),
        ),
      );
}
1
likes
0
points
178
downloads

Publisher

unverified uploader

Weekly Downloads

Gyanmeet meeting SDK for Flutter — a self-contained video meeting widget with host controls, chat, polls, and optional on-device AI proctoring.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

dio, flutter, google_mlkit_face_detection, image, livekit_client, livekit_components, path_provider, provider, tflite_flutter

More

Packages that depend on gyanmeet_flutter_sdk