livecaller_flutter_sdk 1.1.5
livecaller_flutter_sdk: ^1.1.5 copied to clipboard
Livecaller flutter sdk
example/main.dart
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:livecaller_flutter_sdk/livecaller_flutter_sdk.dart';
/// Your widget id from the Livecaller dashboard.
///
/// Replace with your own value before running.
const String kLivecallerWidgetId = 'YOUR_WIDGET_ID';
/// A JWT issued by *your* backend identifying the current visitor.
///
/// In a real app you would fetch this after the user signs in to your
/// system — do not hard-code production tokens in source.
const String kAuthToken = 'YOUR_VISITOR_JWT';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Start the persistent background listener BEFORE any UI. After the user
// has opened chat once, the SDK reuses the connection config it persisted
// during the last session, so a no-arg call is enough on subsequent cold
// starts. Safe to call when no session exists yet — it just no-ops.
await LivecallerApp.startBackgroundEvents();
// App-wide debug listeners — fire on every event regardless of route.
// These subscriptions live for the process lifetime, so we don't cancel.
LivecallerEvents.instance.on(
LivecallerEventType.conversationWasStarted,
(conversation) => debugPrint('Conversation started: ${conversation['id']}'),
);
LivecallerEvents.instance.on(
LivecallerEventType.conversationMessageReceived,
(message) => debugPrint('Message received: ${message['content']}'),
);
LivecallerEvents.instance.on(
LivecallerEventType.conversationWasClosed,
(conversation) => debugPrint('Conversation closed: ${conversation['id']}'),
);
LivecallerEvents.instance.on(
LivecallerEventType.conversationAuthFailed,
(data) => debugPrint(
'Conversation auth failed: ${data['conversationId']} '
'— host should re-login.',
),
);
runApp(const ProviderScope(child: ExampleApp()));
}
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Livecaller SDK Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
Future<void> _login(BuildContext context) async {
await LivecallerApp.userLogin(context, kAuthToken);
if (!context.mounted) return;
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('Logged in')));
}
Future<void> _logout(BuildContext context) async {
await LivecallerApp.userLogout(context);
await LivecallerApp.stopBackgroundEvents();
if (!context.mounted) return;
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('Logged out')));
}
void _openChat(BuildContext context) {
showModalBottomSheet(
context: context,
isScrollControlled: true,
useSafeArea: true,
backgroundColor: Colors.transparent,
barrierColor: Colors.black54,
builder: (_) => DraggableScrollableSheet(
initialChildSize: 1,
minChildSize: 0.6,
maxChildSize: 1.0,
builder: (_, __) => Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 12),
child: Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: Colors.grey.shade400,
borderRadius: BorderRadius.circular(4),
),
),
),
const Expanded(
child: LivecallerApp(
widgetId: kLivecallerWidgetId,
language: 'en',
),
),
],
),
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Livecaller SDK Example')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton.icon(
onPressed: () => _login(context),
icon: const Icon(Icons.login),
label: const Text('Login'),
),
const SizedBox(height: 12),
ElevatedButton.icon(
onPressed: () => _logout(context),
icon: const Icon(Icons.logout),
label: const Text('Logout'),
),
const SizedBox(height: 24),
ElevatedButton.icon(
onPressed: () => _openChat(context),
icon: const Icon(Icons.chat),
label: const Text('Open Chat'),
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
horizontal: 32,
vertical: 16,
),
),
),
const SizedBox(height: 12),
ElevatedButton.icon(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const NotificationsPage()),
),
icon: const Icon(Icons.notifications),
label: const Text('Notifications'),
),
],
),
),
);
}
}
/// Demonstrates subscribing to Livecaller events from a host screen that is
/// *not* the chat widget itself. The background listener keeps events
/// flowing while the user browses the host app.
class NotificationsPage extends StatefulWidget {
const NotificationsPage({super.key});
@override
State<NotificationsPage> createState() => _NotificationsPageState();
}
class _NotificationsPageState extends State<NotificationsPage> {
final List<StreamSubscription<LivecallerEvent>> _subs = [];
@override
void initState() {
super.initState();
_subs.addAll([
LivecallerEvents.instance.on(
LivecallerEventType.conversationWasStarted,
(_) => _notify('Conversation started', Colors.blue),
),
LivecallerEvents.instance.on(
LivecallerEventType.conversationMessageReceived,
(message) {
final content = message['content']?.toString() ?? '(no body)';
_notify('New message: $content', Colors.green);
},
),
LivecallerEvents.instance.on(
LivecallerEventType.conversationWasClosed,
(_) => _notify('Conversation closed', Colors.orange),
),
LivecallerEvents.instance.on(
LivecallerEventType.conversationAuthFailed,
(_) => _notify('Auth failed — please log in again', Colors.red),
),
]);
}
void _notify(String text, Color color) {
if (!mounted) return;
ScaffoldMessenger.of(context)
..clearSnackBars()
..showSnackBar(
SnackBar(
content: Text(text, style: const TextStyle(color: Colors.white)),
backgroundColor: color,
behavior: SnackBarBehavior.floating,
duration: const Duration(seconds: 3),
),
);
}
@override
void dispose() {
for (final s in _subs) {
s.cancel();
}
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Notifications'),
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
),
body: const Center(
child: Padding(
padding: EdgeInsets.all(24),
child: Text(
'Livecaller notifications appear here as snackbars while you '
'stay on this page — even though the chat widget is closed.',
textAlign: TextAlign.center,
),
),
),
);
}
}