roomful_flutter 0.1.0-alpha.4 copy "roomful_flutter: ^0.1.0-alpha.4" to clipboard
roomful_flutter: ^0.1.0-alpha.4 copied to clipboard

Flutter widgets and controllers for Roomful — presence, live cursors, comments, locks, and shared state over a self-hostable relay, built on the pure-Dart roomful core.

example/roomful_flutter_example.dart

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

/// A small end-to-end example wiring the whole `roomful_flutter` surface together: a
/// [RoomfulProvider] hosting [PresenceAvatars], a [LiveCursorsOverlay] canvas, and a shared
/// counter via [RoomfulSharedStateBuilder].
///
/// Defaults to the same relay and room as the React `examples/cross-platform-interop` client, so
/// the two collaborate across platforms out of the box:
///
/// ```sh
/// flutter run -t example/roomful_flutter_example.dart
/// ```
///
/// Override the relay for a local one with
/// `--dart-define=ROOMFUL_RELAY_URL=ws://<your-host>:8787`.
void main() {
  runApp(const RoomfulExampleApp());
}

// Shared with the React interop client so both join the same room. Defaults to the public Roomful
// relay; point at a local one with --dart-define=ROOMFUL_RELAY_URL=ws://<host>:8787.
const String _roomId =
    String.fromEnvironment('ROOMFUL_ROOM', defaultValue: 'roomful-interop-demo');
const String _relayUrl = String.fromEnvironment(
  'ROOMFUL_RELAY_URL',
  defaultValue: 'wss://relay.roomful.dev',
);

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Roomful × Flutter',
      theme: ThemeData.dark(),
      home: const _ExampleHome(name: 'Flutter User', color: '#5cc7ab'),
    );
  }
}

class _ExampleHome extends StatelessWidget {
  const _ExampleHome({required this.name, required this.color});

  final String name;
  final String color;

  @override
  Widget build(BuildContext context) {
    return RoomfulProvider(
      roomId: _roomId,
      peerId: 'flutter-${identityHashCode(this)}',
      relayUrl: _relayUrl,
      child: _RoomScreen(name: name, color: color),
    );
  }
}

class _RoomScreen extends StatefulWidget {
  const _RoomScreen({required this.name, required this.color});

  final String name;
  final String color;

  @override
  State<_RoomScreen> createState() => _RoomScreenState();
}

class _RoomScreenState extends State<_RoomScreen> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (!mounted) {
        return;
      }
      RoomfulProvider.of(context).setPresence(<String, dynamic>{
        'name': widget.name,
        'color': widget.color,
      });
    });
  }

  void _publishCursor(RoomController room, Offset local, BoxConstraints box) {
    if (box.maxWidth == 0 || box.maxHeight == 0) {
      return;
    }
    // setPosition fills the relay-required cursor fields; a bare {x, y} map would be dropped.
    room.cursors.setPosition(
      local.dx / box.maxWidth,
      local.dy / box.maxHeight,
      name: widget.name,
      color: widget.color,
      xAbsolute: local.dx,
      yAbsolute: local.dy,
    );
  }

  @override
  Widget build(BuildContext context) {
    final room = RoomfulProvider.of(context);
    return Scaffold(
      appBar: AppBar(
        title: const Text('Roomful × Flutter'),
        actions: const <Widget>[
          Padding(
            padding: EdgeInsets.only(right: 12),
            child: Center(child: PresenceAvatars()),
          ),
        ],
      ),
      body: Column(
        children: <Widget>[
          Padding(
            padding: const EdgeInsets.all(12),
            child: RoomfulBuilder(
              builder: (context, room) => Text(
                '${room.peers.length} other peer(s) • ${room.state.name}',
              ),
            ),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 12),
            child: RoomfulSharedStateBuilder<int>(
              builder: (context, value, set) {
                final count = value ?? 0;
                return Row(
                  children: <Widget>[
                    Text('Shared counter: $count'),
                    const SizedBox(width: 12),
                    ElevatedButton(
                      onPressed: () => set(count + 1),
                      child: const Text('+1'),
                    ),
                  ],
                );
              },
            ),
          ),
          Expanded(
            child: LayoutBuilder(
              builder: (context, constraints) {
                return Listener(
                  onPointerHover: (event) =>
                      _publishCursor(room, event.localPosition, constraints),
                  onPointerMove: (event) =>
                      _publishCursor(room, event.localPosition, constraints),
                  child: LiveCursorsOverlay(
                    normalized: true,
                    child: Container(
                      color: const Color(0xFF0A0F0E),
                      alignment: Alignment.center,
                      child: const Text('Move your cursor here'),
                    ),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}
0
likes
160
points
5
downloads

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

Flutter widgets and controllers for Roomful — presence, live cursors, comments, locks, and shared state over a self-hostable relay, built on the pure-Dart roomful core.

Homepage
Repository (GitHub)
View/report issues
Contributing

Topics

#collaboration #realtime #flutter #presence #widget

License

MIT (license)

Dependencies

flutter, roomful

More

Packages that depend on roomful_flutter