connect_x_flutter_livechat_sdk 1.2.2
connect_x_flutter_livechat_sdk: ^1.2.2 copied to clipboard
Live Chat SDK for Flutter
example/lib/main.dart
import 'package:connect_x_flutter_livechat_sdk/connect_x_flutter_livechat_sdk.dart';
import 'package:flutter/material.dart';
// --- Connection config (kept here so the setup screen can re-use it) ---
// Pass with: flutter run --dart-define=CX_TOKEN=<token>
const String _token = String.fromEnvironment('CX_TOKEN');
const String _orgId = "0000OrgRAndDConnectX";
const String _channelId = "9318254639";
const String _externalValue = "Chubby"; // This links the user to your CRM
// Sample customer images for testers to choose from.
// The selected URL is sent as `cx_customerImage` in initialize().
const List<String> _sampleCustomerImages = [
'https://bucket.connect-x.tech/connectx/api/storage/files/84c5a330-43dc-4506-b88d-4f31005b8cd9',
'https://i.pravatar.cc/300?img=12',
'https://i.pravatar.cc/300?img=47',
];
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: SetupPage());
}
}
/// Setup screen: tester picks one of the sample customer images, then we
/// initialize the chat connector with that image as `cx_customerImage`.
class SetupPage extends StatefulWidget {
const SetupPage({super.key});
@override
State<SetupPage> createState() => _SetupPageState();
}
class _SetupPageState extends State<SetupPage> {
int _selectedIndex = 0;
bool _isConnecting = false;
Future<void> _connectAndContinue() async {
setState(() => _isConnecting = true);
try {
await ChatController.instance.initialize(
token: _token,
orgId: _orgId,
channelId: _channelId,
externalValue: _externalValue,
chatInfo: {
'cx_customerImage': _sampleCustomerImages[_selectedIndex],
},
);
if (!mounted) return;
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => const MyHomePage()),
);
} catch (e) {
if (!mounted) return;
setState(() => _isConnecting = false);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text("Connect failed: $e")),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("เลือกรูปลูกค้าเพื่อทดสอบ")),
body: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
"เลือกรูปภาพที่จะส่งเป็น cx_customerImage แล้วกดเชื่อมต่อ",
style: TextStyle(fontSize: 16),
),
const SizedBox(height: 24),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List.generate(_sampleCustomerImages.length, (index) {
final isSelected = index == _selectedIndex;
return GestureDetector(
onTap: _isConnecting
? null
: () => setState(() => _selectedIndex = index),
child: Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: isSelected
? Colors.blueAccent
: Colors.grey.shade300,
width: isSelected ? 4 : 2,
),
),
child: CircleAvatar(
radius: 44,
backgroundColor: Colors.grey.shade200,
backgroundImage:
NetworkImage(_sampleCustomerImages[index]),
),
),
);
}),
),
const Spacer(),
ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
backgroundColor: Colors.blueAccent,
),
onPressed: _isConnecting ? null : _connectAndContinue,
child: _isConnecting
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.white,
),
)
: const Text(
"เชื่อมต่อ & เปิดแอป",
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
],
),
),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
void _openChatScreen() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChatScreen(
onClose: () => Navigator.pop(context),
isHideCloseButton: true,
),
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("User App"),
actions: [
ValueListenableBuilder<bool>(
valueListenable: ChatController.instance.hasUnreadMessagesNotifier,
builder: (context, hasUnread, child) {
return Stack(
children: [
IconButton(
icon: const Icon(Icons.notifications),
onPressed: () {
// Clear the red dot and open the chat screen
ChatController.instance.markAsRead();
_openChatScreen();
},
),
if (hasUnread)
Positioned(
right: 12,
top: 12,
child: Container(
padding: const EdgeInsets.all(2),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(6),
),
constraints: const BoxConstraints(
minWidth: 12,
minHeight: 12,
),
),
),
],
);
},
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 2. SEND MESSAGE MANUALLY (FROM FORM)
ElevatedButton(
style: ElevatedButton.styleFrom(
padding:
const EdgeInsets.symmetric(horizontal: 30, vertical: 15),
backgroundColor: Colors.blueAccent,
),
onPressed: () =>
_showManualSendModal(context), // Open the small modal
child: const Text(
"Quick Support Message",
style: TextStyle(color: Colors.white, fontSize: 16),
),
),
const SizedBox(height: 20),
// 3. START CHAT UI
ElevatedButton(
onPressed: _openChatScreen,
child: const Text("Open Chat UI"),
),
],
),
),
);
}
}
void _showManualSendModal(BuildContext context) {
final TextEditingController modalController = TextEditingController();
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text("Quick Message"),
content: TextField(
controller: modalController,
autofocus: true,
decoration: const InputDecoration(
hintText: "Enter your message here...",
border: OutlineInputBorder(),
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text("Cancel"),
),
ElevatedButton(
onPressed: () {
final text = modalController.text.trim();
if (text.isNotEmpty) {
// Call your library
ChatController.instance.sendMessage(text: text);
Navigator.pop(context); // Close modal
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text("Message sent successfully!")),
);
}
},
child: const Text("Send"),
),
],
);
},
);
}