qriib_meet 0.1.0 copy "qriib_meet: ^0.1.0" to clipboard
qriib_meet: ^0.1.0 copied to clipboard

Flutter APIs for creating Qriib rooms and embedding secure, customizable audio and video meeting experiences.

example/lib/main.dart

import 'dart:convert';

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

const _apiKey = String.fromEnvironment('QRIIB_API_KEY');
const _secretKey = String.fromEnvironment('QRIIB_SECRET_KEY');
const _projectId = String.fromEnvironment('QRIIB_PROJECT_ID');

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

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

  @override
  Widget build(BuildContext context) => MaterialApp(
        title: 'Qriib Meet examples',
        theme: ThemeData(
            colorScheme:
                ColorScheme.fromSeed(seedColor: const Color(0xFF6750A4)),
            useMaterial3: true),
        home: const RoomExamplesPage(),
      );
}

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

class _RoomExamplesPageState extends State<RoomExamplesPage> {
  late final QriibMeetClient _client = QriibMeetClient.withProjectCredentials(
      apiKey: _apiKey, secretKey: _secretKey, enableNetworkLogging: false);
  final _project = TextEditingController(text: _projectId);
  final _room = TextEditingController();
  final _moderator = TextEditingController();
  final _name = TextEditingController(text: 'Guest');
  final _startAt = TextEditingController(text: '2026-12-31T18:30');
  var _busy = false;
  bool get _configured => _apiKey.isNotEmpty && _secretKey.isNotEmpty;
  String get _projectIdValue => _project.text.trim();
  String get _roomId => _room.text.trim();

  @override
  void dispose() {
    _client.close();
    for (final controller in [_project, _room, _moderator, _name, _startAt]) {
      controller.dispose();
    }
    super.dispose();
  }

  Future<void> _run(Future<Map<String, dynamic>> Function() request) async {
    if (!_configured || _busy) return;
    setState(() => _busy = true);
    try {
      final response = await request();
      if (mounted) await _showResponse(response);
    } on QriibApiException catch (error) {
      _message(error.message);
    } on QriibMeetException catch (error) {
      _message(error.message);
    } catch (_) {
      _message('Request failed. Verify credentials, IDs, and room state.');
    } finally {
      if (mounted) setState(() => _busy = false);
    }
  }

  void _message(String message) {
    if (mounted) {
      ScaffoldMessenger.of(context)
          .showSnackBar(SnackBar(content: Text(message)));
    }
  }

  void _needProject() {
    if (_projectIdValue.isEmpty) {
      throw const QriibMeetException('Project ID is required.');
    }
  }

  void _needRoom() {
    if (_roomId.isEmpty) {
      throw const QriibMeetException('Room ID is required.');
    }
  }

  Future<void> _showResponse(Map<String, dynamic> response) => showDialog<void>(
        context: context,
        builder: (context) => AlertDialog(
          title: const Text('API response'),
          content: SingleChildScrollView(
              child: SelectableText(
                  const JsonEncoder.withIndent('  ').convert(response))),
          actions: [
            TextButton(
                onPressed: () => Navigator.pop(context),
                child: const Text('Close'))
          ],
        ),
      );

  Future<void> _open(Map<String, dynamic> response, bool audioOnly) async {
    await openMeetingFromResponse(
      context: context,
      qriib: _client,
      response: response,
      userName: _name.text.trim(),
      audioOnly: audioOnly,
    );
  }

  Future<void> _quick(bool audioOnly) => _run(() async {
        _needProject();
        final metadata = QriibRoomMetadata(
            roomTitle: audioOnly ? 'Quick audio room' : 'Quick video room',
            welcomeMessage: 'Welcome to Qriib Meet');
        final response = audioOnly
            ? await _client.rooms.createQuickAudioRoom(
                projectId: _projectIdValue,
                clientRoomId: newClientRoomId(),
                name: _name.text.trim(),
                moderatorId: _moderator.text.trim(),
                maxParticipants: 20,
                emptyTimeout: 78,
                metadata: metadata)
            : await _client.rooms.createQuickVideoRoom(
                projectId: _projectIdValue,
                clientRoomId: newClientRoomId(),
                name: _name.text.trim(),
                moderatorId: _moderator.text.trim(),
                maxParticipants: 20,
                emptyTimeout: 78,
                metadata: metadata);
        await _open(response, audioOnly);
        return response;
      });

  Future<void> _scheduled(bool audioOnly) => _run(() async {
        _needProject();
        return audioOnly
            ? _client.rooms.createScheduledAudioRoom(
                projectId: _projectIdValue,
                clientRoomId: newClientRoomId(),
                startAt: _startAt.text.trim(),
                maxParticipants: 20,
                emptyTimeout: 78,
                metadata:
                    const QriibRoomMetadata(roomTitle: 'Scheduled audio room'))
            : _client.rooms.createScheduledVideoRoom(
                projectId: _projectIdValue,
                clientRoomId: newClientRoomId(),
                startAt: _startAt.text.trim(),
                maxParticipants: 20,
                emptyTimeout: 78,
                metadata:
                    const QriibRoomMetadata(roomTitle: 'Scheduled video room'));
      });

  Future<void> _join() => _run(() async {
        _needRoom();
        final response = await _client.rooms.joinRoom(
            roomId: _roomId,
            userInfo: QriibUserInfo(
                name: _name.text.trim(),
                role: 'attendee',
                isAdmin: false,
                isHidden: false));
        await _open(response, false);
        return response;
      });

  Future<void> _start(bool audioOnly) => _run(() async {
        _needRoom();
        final response = await _client.rooms
            .startScheduledRoom(_roomId, name: _name.text.trim());
        await _open(response, audioOnly);
        return response;
      });

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('Qriib Meet examples')),
        body: ListView(padding: const EdgeInsets.all(16), children: [
          Text('Rooms API playground',
              style: Theme.of(context).textTheme.headlineSmall),
          const SizedBox(height: 8),
          Text(_configured
              ? 'Ready to make authenticated requests.'
              : 'Run with QRIIB_API_KEY and QRIIB_SECRET_KEY. No secrets are stored in this app.'),
          const SizedBox(height: 16),
          _field(_project, 'Project ID'),
          _field(_moderator, 'Moderator ID (quick rooms)'),
          _field(_name, 'Participant name'),
          _field(_room, 'Room ID'),
          _field(_startAt, 'Start at (ISO-8601)'),
          _section('Create rooms', [
            _action('Create quick video room', Icons.videocam_outlined,
                () => _quick(false)),
            _action('Create quick audio room', Icons.headphones_outlined,
                () => _quick(true)),
            _action('Create scheduled video room', Icons.event_outlined,
                () => _scheduled(false)),
            _action('Create scheduled audio room',
                Icons.event_available_outlined, () => _scheduled(true)),
          ]),
          _section('Join and start', [
            _action('Join an existing room', Icons.login_outlined, _join),
            _action('Start scheduled video room', Icons.play_circle_outline,
                () => _start(false)),
            _action('Start scheduled audio room', Icons.play_circle_outline,
                () => _start(true)),
          ]),
          _section('Room management', [
            _action(
                'Create invitation link',
                Icons.link_outlined,
                () => _run(() {
                      _needRoom();
                      return _client.rooms.createInvitationLink(
                          roomId: _roomId, role: QriibInvitationRole.attendee);
                    })),
            _action(
                'Get room status',
                Icons.info_outline,
                () => _run(() {
                      _needRoom();
                      return _client.rooms.getRoomStatus(_roomId);
                    })),
            _action(
                'Get active room info',
                Icons.meeting_room_outlined,
                () => _run(() {
                      _needRoom();
                      return _client.rooms.getActiveRoomInfo(_roomId);
                    })),
            _action('Get active rooms info', Icons.groups_outlined,
                () => _run(_client.rooms.getActiveRoomsInfo)),
            _action(
                'Fetch past rooms',
                Icons.history_outlined,
                () => _run(() {
                      _needProject();
                      return _client.rooms.fetchPastRooms(
                          projectId: _projectIdValue,
                          from: 0,
                          limit: 10,
                          orderBy: QriibPastRoomsOrder.desc);
                    })),
            _action(
                'End room',
                Icons.stop_circle_outlined,
                () => _run(() {
                      _needRoom();
                      return _client.rooms.endRoom(_roomId);
                    }),
                destructive: true),
          ]),
        ]),
      );

  Widget _field(TextEditingController controller, String label) => Padding(
      padding: const EdgeInsets.only(bottom: 12),
      child: TextField(
          controller: controller,
          decoration: InputDecoration(
              labelText: label, border: const OutlineInputBorder())));
  Widget _section(String title, List<Widget> actions) =>
      Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
        const Divider(height: 32),
        Text(title, style: Theme.of(context).textTheme.titleLarge),
        const SizedBox(height: 8),
        ...actions
      ]);
  Widget _action(String label, IconData icon, Future<void> Function() action,
          {bool destructive = false}) =>
      Padding(
          padding: const EdgeInsets.only(bottom: 8),
          child: SizedBox(
              width: double.infinity,
              child: FilledButton.tonalIcon(
                  onPressed: _configured && !_busy ? action : null,
                  icon: _busy
                      ? const SizedBox.square(
                          dimension: 18,
                          child: CircularProgressIndicator(strokeWidth: 2))
                      : Icon(icon),
                  style: destructive
                      ? FilledButton.styleFrom(
                          foregroundColor: Theme.of(context).colorScheme.error)
                      : null,
                  label: Text(label))));
}
1
likes
0
points
168
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter APIs for creating Qriib rooms and embedding secure, customizable audio and video meeting experiences.

Homepage

License

unknown (license)

Dependencies

async, collection, connectivity_plus, crypto, dart_jsonwebtoken, dart_webrtc, device_info_plus, dio, fixnum, flutter, flutter_webrtc, http, json_annotation, logging, meta, mime_type, path, permission_handler, pretty_dio_logger, protobuf, sdp_transform, synchronized, uuid, web

More

Packages that depend on qriib_meet

Packages that implement qriib_meet