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

Flutter bindings for NoveraChat — lifecycle-managed providers and controllers over the headless noverachat_dart core.

example/lib/main.dart

// Minimal example wiring the noverachat_flutter bindings into one chat screen.
//
// Configuration is read at compile time so no secret lives in the source. Run:
//
//   flutter run \
//     --dart-define=NOVERACHAT_ENDPOINT=https://chat.example.com \
//     --dart-define=NOVERACHAT_APP_ID=app_9f8k2x \
//     --dart-define=NOVERACHAT_TOKEN=<a per-user JWT from your backend> \
//     --dart-define=NOVERACHAT_ROOM=room_123
//
// In a real app, `tokenProvider` fetches a fresh JWT from YOUR backend; here we
// read one from a --dart-define just to keep the example runnable.

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

const _endpoint =
    String.fromEnvironment('NOVERACHAT_ENDPOINT', defaultValue: 'https://chat.example.com');
const _appId =
    String.fromEnvironment('NOVERACHAT_APP_ID', defaultValue: 'app_9f8k2x');
const _token = String.fromEnvironment('NOVERACHAT_TOKEN', defaultValue: '');
const _roomId =
    String.fromEnvironment('NOVERACHAT_ROOM', defaultValue: 'room_123');

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'noverachat_flutter example',
      // Provide a connected NoveraChat to the whole app.
      home: NoveraChatScope(
        options: ClientOptions(
          appId: _appId,
          endpoint: _endpoint,
          tokenProvider: () async => _token,
        ),
        child: const ChatScreen(roomId: _roomId),
      ),
    );
  }
}

class ChatScreen extends StatefulWidget {
  const ChatScreen({super.key, required this.roomId});

  final String roomId;

  @override
  State<ChatScreen> createState() => _ChatScreenState();
}

class _ChatScreenState extends State<ChatScreen> {
  RoomController? _messages;
  TypingController? _typing;
  final _input = TextEditingController();

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    // Build the controllers once, now that NoveraChatScope is above us.
    if (_messages == null) {
      final chat = NoveraChatScope.of(context);
      final room = chat.room(widget.roomId);
      _messages = RoomController(room)..loadHistory();
      _typing = TypingController(room);
    }
  }

  @override
  void dispose() {
    _messages?.dispose();
    _typing?.dispose();
    _input.dispose();
    super.dispose();
  }

  void _send() {
    final text = _input.text.trim();
    if (text.isEmpty) return;
    _messages!.send(text);
    _input.clear();
  }

  @override
  Widget build(BuildContext context) {
    final messages = _messages!;
    return Scaffold(
      appBar: AppBar(title: Text('Room ${widget.roomId}')),
      body: Column(
        children: [
          Expanded(
            child: MessagesBuilder(
              controller: messages,
              builder: (context, list) => ListView.builder(
                itemCount: list.length,
                itemBuilder: (context, i) {
                  final m = list[i];
                  return ListTile(
                    dense: true,
                    title: Text(m.isDeleted ? '(deleted)' : (m.content ?? '')),
                    subtitle: Text('${m.senderId ?? "me"} · ${m.status.name}'),
                  );
                },
              ),
            ),
          ),
          // "… is typing" indicator.
          ListenableBuilder(
            listenable: _typing!,
            builder: (context, _) => _typing!.isAnyoneTyping
                ? const Align(
                    alignment: Alignment.centerLeft,
                    child: Padding(
                      padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4),
                      child: Text('typing…', style: TextStyle(fontStyle: FontStyle.italic)),
                    ),
                  )
                : const SizedBox.shrink(),
          ),
          SafeArea(
            child: Padding(
              padding: const EdgeInsets.all(8),
              child: Row(
                children: [
                  Expanded(
                    child: TextField(
                      controller: _input,
                      onChanged: (_) =>
                          NoveraChatScope.of(context).room(widget.roomId).setTyping(true),
                      onSubmitted: (_) => _send(),
                      decoration: const InputDecoration(hintText: 'Message'),
                    ),
                  ),
                  IconButton(icon: const Icon(Icons.send), onPressed: _send),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}
0
likes
0
points
496
downloads

Publisher

unverified uploader

Weekly Downloads

Flutter bindings for NoveraChat — lifecycle-managed providers and controllers over the headless noverachat_dart core.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, noverachat_dart

More

Packages that depend on noverachat_flutter