tickki_chat_flutter 0.1.1 copy "tickki_chat_flutter: ^0.1.1" to clipboard
tickki_chat_flutter: ^0.1.1 copied to clipboard

Tickki Chat SDK for Flutter — embed live agent chat into your app with a drop-in widget or headless primitives.

example/lib/main.dart

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:tickki_chat_flutter/widget.dart';

/// Tickki Chat SDK example. Two screens:
///   1. Drop-in widget — one tap opens the full chat UI.
///   2. Headless demo — REST + realtime primitives, your own bare-bones UI.
///
/// Replace the publishable key below with one minted from your
/// Tickki dashboard at /settings/developer/{slug}. The visitor id
/// is whatever stable string you'd persist for the current user.
void main() {
  runApp(const ExampleApp());
}

const _publishableKey = 'pk_live_PASTE_YOUR_KEY_HERE';
const _visitorId = 'demo-visitor-001';
const _baseUrl = 'https://app.tickki.com';

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Tickki Chat SDK Example',
      theme: ThemeData(
        useMaterial3: true,
        colorSchemeSeed: const Color(0xFF4F46E5),
      ),
      home: const _Home(),
    );
  }
}

class _Home extends StatefulWidget {
  const _Home();
  @override
  State<_Home> createState() => _HomeState();
}

class _HomeState extends State<_Home> {
  late final TickkiChat _client = TickkiChat(
    publishableKey: _publishableKey,
    baseUrl: _baseUrl,
  );

  @override
  void dispose() {
    _client.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Tickki Chat SDK')),
      body: Center(
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 24),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              FilledButton(
                onPressed: _openDropIn,
                style: FilledButton.styleFrom(
                  padding: const EdgeInsets.symmetric(vertical: 14),
                ),
                child: const Text('Open drop-in widget'),
              ),
              const SizedBox(height: 12),
              OutlinedButton(
                onPressed: _openHeadless,
                style: OutlinedButton.styleFrom(
                  padding: const EdgeInsets.symmetric(vertical: 14),
                ),
                child: const Text('Open headless demo'),
              ),
              const SizedBox(height: 24),
              Text(
                'Edit lib/main.dart and paste your publishable key from\n'
                'Tickki → Settings → Developer before running.',
                textAlign: TextAlign.center,
                style: Theme.of(context).textTheme.bodySmall,
              ),
            ],
          ),
        ),
      ),
    );
  }

  void _openDropIn() {
    TickkiChatWidget.show(
      context,
      client: _client,
      visitorId: _visitorId,
    );
  }

  void _openHeadless() {
    Navigator.of(context).push(
      MaterialPageRoute(
        builder: (_) => _HeadlessChatScreen(client: _client),
      ),
    );
  }
}

/// Bare-bones screen showing how to drive the SDK from your own UI:
/// `startSession` → listen to `messages` → call `send`. The widget
/// styling is intentionally minimal — the point is the API shape.
class _HeadlessChatScreen extends StatefulWidget {
  const _HeadlessChatScreen({required this.client});
  final TickkiChat client;
  @override
  State<_HeadlessChatScreen> createState() => _HeadlessChatScreenState();
}

class _HeadlessChatScreenState extends State<_HeadlessChatScreen> {
  ChatSession? _session;
  final List<ChatMessage> _log = [];
  final TextEditingController _input = TextEditingController();
  String? _error;
  StreamSubscription<ChatMessage>? _sub;

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

  Future<void> _start() async {
    try {
      final s = await widget.client.startSession(visitorId: _visitorId);
      _sub = s.messages.listen((m) {
        if (_log.any((existing) => existing.id == m.id)) return;
        setState(() => _log.add(m));
      });
      s.startHeartbeat();
      final page = await s.loadHistory();
      if (!mounted) return;
      setState(() {
        _session = s;
        _log.addAll(page.messages.reversed);
      });
    } on TickkiChatException catch (e) {
      setState(() => _error = '${e.code}: ${e.message}');
    } catch (e) {
      setState(() => _error = e.toString());
    }
  }

  @override
  void dispose() {
    _sub?.cancel();
    _session?.dispose();
    _input.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Headless example')),
      body: Column(
        children: [
          if (_error != null)
            Padding(
              padding: const EdgeInsets.all(12),
              child: Text(_error!, style: const TextStyle(color: Colors.red)),
            ),
          Expanded(
            child: ListView.builder(
              padding: const EdgeInsets.all(12),
              itemCount: _log.length,
              itemBuilder: (_, i) {
                final m = _log[i];
                final mine = m.isFromVisitor;
                return Align(
                  alignment:
                      mine ? Alignment.centerRight : Alignment.centerLeft,
                  child: Container(
                    margin: const EdgeInsets.symmetric(vertical: 4),
                    padding: const EdgeInsets.symmetric(
                      horizontal: 12,
                      vertical: 8,
                    ),
                    decoration: BoxDecoration(
                      color: mine
                          ? const Color(0xFF4F46E5)
                          : Colors.grey.shade200,
                      borderRadius: BorderRadius.circular(12),
                    ),
                    child: Text(
                      m.content,
                      style: TextStyle(
                        color: mine ? Colors.white : Colors.black87,
                      ),
                    ),
                  ),
                );
              },
            ),
          ),
          SafeArea(
            top: false,
            child: Padding(
              padding: const EdgeInsets.all(8),
              child: Row(
                children: [
                  Expanded(
                    child: TextField(
                      controller: _input,
                      decoration: const InputDecoration(
                        border: OutlineInputBorder(),
                        hintText: 'Send a message…',
                      ),
                      onSubmitted: (_) => _send(),
                    ),
                  ),
                  const SizedBox(width: 8),
                  IconButton.filled(
                    onPressed: _session == null ? null : _send,
                    icon: const Icon(Icons.send),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }

  Future<void> _send() async {
    final text = _input.text.trim();
    if (text.isEmpty || _session == null) return;
    _input.clear();
    try {
      final m = await _session!.send(text);
      if (_log.any((existing) => existing.id == m.id)) return;
      setState(() => _log.add(m));
    } on TickkiChatException catch (e) {
      setState(() => _error = '${e.code}: ${e.message}');
    }
  }
}
0
likes
0
points
263
downloads

Documentation

Documentation

Publisher

unverified uploader

Weekly Downloads

Tickki Chat SDK for Flutter — embed live agent chat into your app with a drop-in widget or headless primitives.

Homepage
Repository (GitHub)
View/report issues

Topics

#chat #messaging #live-chat #customer-support #tickki

License

unknown (license)

Dependencies

flutter, http, package_info_plus, pusher_channels_flutter

More

Packages that depend on tickki_chat_flutter