uchara_sdk 1.0.2 copy "uchara_sdk: ^1.0.2" to clipboard
uchara_sdk: ^1.0.2 copied to clipboard

Official Flutter SDK for the Uchara Chat Platform. Headless customer/visitor SDK for embedding realtime chat into Flutter apps: session init, conversations, messages, file uploads, transcript download [...]

example/lib/main.dart

import 'dart:async';

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

/// Runnable example for the Uchara Flutter SDK.
///
/// Demonstrates the full headless lifecycle:
///   init -> conversation -> messages -> realtime -> dispose
///
/// No real credentials are hardcoded. Enter your API URL and public widget
/// token in the UI (or set the `UCHARA_API_URL` / `UCHARA_WIDGET_TOKEN`
/// environment variables) before tapping "Run demo".
void main() {
  runApp(const UcharaExampleApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Uchara SDK Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
        useMaterial3: true,
      ),
      home: const DemoPage(),
    );
  }
}

class DemoPage extends StatefulWidget {
  const DemoPage({super.key});

  @override
  State<DemoPage> createState() => _DemoPageState();
}

class _DemoPageState extends State<DemoPage> {
  final _apiUrlController = TextEditingController(
    text: const String.fromEnvironment('UCHARA_API_URL',
        defaultValue: 'https://api.uchara.com'),
  );
  final _widgetTokenController = TextEditingController(
    text: const String.fromEnvironment('UCHARA_WIDGET_TOKEN',
        defaultValue: 'YOUR_PUBLIC_WIDGET_TOKEN'),
  );

  final _log = <String>[];
  final _scrollController = ScrollController();

  VisitorSDK? _sdk;
  StreamSubscription<WSEvent>? _eventsSub;
  bool _running = false;

  @override
  void dispose() {
    _eventsSub?.cancel();
    _sdk?.dispose();
    _apiUrlController.dispose();
    _widgetTokenController.dispose();
    _scrollController.dispose();
    super.dispose();
  }

  void _logLine(String line) {
    setState(() => _log.add(line));
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (_scrollController.hasClients) {
        _scrollController.jumpTo(_scrollController.position.maxScrollExtent);
      }
    });
  }

  Future<void> _runDemo() async {
    if (_running) return;
    setState(() => _running = true);
    _log.clear();

    final apiUrl = _apiUrlController.text.trim();
    final widgetToken = _widgetTokenController.text.trim();
    if (widgetToken.isEmpty || widgetToken == 'YOUR_PUBLIC_WIDGET_TOKEN') {
      _logLine('⚠️  Enter a real public widget token to run the demo.');
      setState(() => _running = false);
      return;
    }

    // Clean up any previous run.
    _eventsSub?.cancel();
    _sdk?.dispose();

    final sdk = VisitorSDK(VisitorConfig(
      apiUrl: apiUrl,
      widgetToken: widgetToken,
      identity: const VisitorIdentity(
        externalId: 'example-user',
        name: 'Example Visitor',
        email: 'visitor@example.com',
      ),
      autoConnect: true,
    ));
    _sdk = sdk;

    try {
      _logLine('1. init() — exchanging widget token for a visitor session…');
      final session = await sdk.init();
      _logLine('   visitor token: ${_mask(session.visitorToken)}');
      _logLine('   contact id:    ${session.contactId}');

      _logLine('2. Subscribing to realtime events…');
      _eventsSub = sdk.events?.listen((event) {
        _logLine('   [realtime] ${event.type}');
      });

      _logLine('3. getActiveConversation()…');
      var conversation = await sdk.getActiveConversation();
      if (conversation == null) {
        _logLine('   No active conversation — starting a new one.');
        conversation =
            await sdk.startConversation(message: 'Hello from Flutter!');
      }
      _logLine('   conversation id: ${conversation.id}');

      _logLine('4. sendMessage()…');
      final sent = await sdk.sendMessage(
        conversation.id,
        content: 'Is anyone there?',
      );
      _logLine('   sent message id: ${sent.id}');

      _logLine('5. getMessages() (paginated)…');
      final page = await sdk.getMessages(conversation.id, limit: 50);
      _logLine('   ${page.messages.length} message(s) returned');

      _logLine('6. sendTyping() over the realtime connection…');
      sdk.sendTyping(conversation.id);
      _logLine('   typing indicator sent');

      _logLine('7. dispose() — releasing the SDK…');
      await _eventsSub?.cancel();
      _eventsSub = null;
      sdk.dispose();
      _sdk = null;
      _logLine('   done. ✅');
    } on ServerEnvelopeException catch (e) {
      _logLine(
          '❌ ServerEnvelopeException(${e.statusCode}, ${e.code}): ${e.message}');
    } on ApiException catch (e) {
      _logLine('❌ ApiException(${e.statusCode}): ${e.message}');
    } on NetworkException catch (e) {
      _logLine('❌ NetworkException: ${e.message}');
    } on UcharaException catch (e) {
      _logLine('❌ UcharaException: ${e.message}');
    } finally {
      setState(() => _running = false);
    }
  }

  String _mask(String token) {
    if (token.length <= 8) return '***';
    return '${token.substring(0, 4)}…${token.substring(token.length - 4)}';
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Uchara SDK Example')),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(16),
            child: Column(
              children: [
                TextField(
                  controller: _apiUrlController,
                  decoration: const InputDecoration(
                    labelText: 'API URL',
                    border: OutlineInputBorder(),
                  ),
                ),
                const SizedBox(height: 12),
                TextField(
                  controller: _widgetTokenController,
                  decoration: const InputDecoration(
                    labelText: 'Public widget token',
                    border: OutlineInputBorder(),
                  ),
                ),
                const SizedBox(height: 16),
                SizedBox(
                  width: double.infinity,
                  child: FilledButton(
                    onPressed: _running ? null : _runDemo,
                    child: Text(_running ? 'Running…' : 'Run demo'),
                  ),
                ),
              ],
            ),
          ),
          const Divider(height: 1),
          Expanded(
            child: ListView.builder(
              controller: _scrollController,
              padding: const EdgeInsets.all(12),
              itemCount: _log.length,
              itemBuilder: (context, index) {
                return Padding(
                  padding: const EdgeInsets.symmetric(vertical: 2),
                  child: Text(
                    _log[index],
                    style:
                        const TextStyle(fontFamily: 'monospace', fontSize: 13),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}
0
likes
140
points
102
downloads

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

Official Flutter SDK for the Uchara Chat Platform. Headless customer/visitor SDK for embedding realtime chat into Flutter apps: session init, conversations, messages, file uploads, transcript download, and a resilient WebSocket client.

Repository (GitHub)
View/report issues

Topics

#chat #messaging #customer-support #realtime #websocket

License

MIT (license)

Dependencies

flutter, http, http_parser, web_socket_channel

More

Packages that depend on uchara_sdk