adaptive_chat 1.0.29
adaptive_chat: ^1.0.29 copied to clipboard
Flutter plugin for the Adaptive SDK Chat module. Launches an AI-powered in-app chat experience with survey flows, flashcards, quizzes, and step-by-step explanations for the Adaptive e-learning platform.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:adaptive_chat/adaptive_chat.dart';
void main() => runApp(const AdaptiveChatExampleApp());
class AdaptiveChatExampleApp extends StatelessWidget {
const AdaptiveChatExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Adaptive Chat Example',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xFF0F766E),
),
useMaterial3: true,
),
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final _subjectController = TextEditingController(text: 'Math');
final _topicController = TextEditingController(text: 'Fractions');
String? _error;
@override
void dispose() {
_subjectController.dispose();
_topicController.dispose();
super.dispose();
}
Future<void> _launchChat() async {
setState(() => _error = null);
try {
await AdaptiveChat.showConversation(
config: AdaptiveChatConfig(
subject: _subjectController.text.trim(),
topic: _topicController.text.trim(),
),
);
} on AdaptiveChatException catch (e) {
setState(() => _error = '${e.code}: ${e.message}');
}
}
@override
Widget build(BuildContext context) {
final teal = const Color(0xFF0F766E);
return Scaffold(
backgroundColor: const Color(0xFFF8FAFC),
appBar: AppBar(
title: const Text('Adaptive Chat Example'),
backgroundColor: teal,
foregroundColor: Colors.white,
elevation: 0,
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// ── Logo ──
Center(
child: Container(
width: 72,
height: 72,
decoration: BoxDecoration(
color: teal,
borderRadius: BorderRadius.circular(20),
),
alignment: Alignment.center,
child: const Text(
'AI',
style: TextStyle(
color: Colors.white,
fontSize: 26,
fontWeight: FontWeight.bold,
),
),
),
),
const SizedBox(height: 16),
Text(
'AI Coach Chat',
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
color: teal,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 8),
const Text(
'Configure the subject and topic, then launch the chat to test survey flows, quizzes, flashcards, and step-by-step explanations.',
textAlign: TextAlign.center,
style: TextStyle(color: Color(0xFF6B7280), height: 1.5),
),
const SizedBox(height: 32),
// ── Config fields ──
const _SectionLabel('Configuration'),
const SizedBox(height: 8),
_InputField(
label: 'Subject',
controller: _subjectController,
hint: 'e.g. Math',
),
const SizedBox(height: 12),
_InputField(
label: 'Topic',
controller: _topicController,
hint: 'e.g. Fractions',
),
const SizedBox(height: 24),
// ── Quick presets ──
const _SectionLabel('Quick Presets'),
const SizedBox(height: 8),
Row(
children: [
_PresetChip(
label: '🧮 Math',
onTap: () {
_subjectController.text = 'Math';
_topicController.text = 'Fractions';
},
),
const SizedBox(width: 8),
_PresetChip(
label: '🌱 Science',
onTap: () {
_subjectController.text = 'Science';
_topicController.text = 'Photosynthesis';
},
),
const SizedBox(width: 8),
_PresetChip(
label: '📝 English',
onTap: () {
_subjectController.text = 'English';
_topicController.text = 'Grammar';
},
),
],
),
const SizedBox(height: 32),
if (_error != null) ...[
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: const Color(0xFFFEE2E2),
borderRadius: BorderRadius.circular(10),
),
child: Text(
_error!,
style: const TextStyle(color: Color(0xFFDC2626)),
),
),
const SizedBox(height: 16),
],
// ── Launch button ──
SizedBox(
height: 56,
child: ElevatedButton(
onPressed: _launchChat,
style: ElevatedButton.styleFrom(
backgroundColor: teal,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(14),
),
textStyle: const TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
),
),
child: const Text('Launch AI Coach Chat →'),
),
),
const SizedBox(height: 32),
// ── Info card ──
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFFF1F5F9),
borderRadius: BorderRadius.circular(12),
),
child: const Text(
'Features being tested:\n'
'• Survey flow (MCQ + picture cards)\n'
'• True / False quiz\n'
'• Flashcard deck with progress\n'
'• Step-by-step explanation\n'
'• Typing indicator animation\n'
'• Chat history drawer with search',
style: TextStyle(
color: Color(0xFF64748B),
height: 1.7,
fontSize: 13,
),
),
),
],
),
),
);
}
}
// ── Small reusable widgets ────────────────────────────────────────────────────
class _SectionLabel extends StatelessWidget {
final String text;
const _SectionLabel(this.text);
@override
Widget build(BuildContext context) {
return Text(
text.toUpperCase(),
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF9CA3AF),
letterSpacing: 0.8,
),
);
}
}
class _InputField extends StatelessWidget {
final String label;
final String hint;
final TextEditingController controller;
const _InputField({
required this.label,
required this.hint,
required this.controller,
});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
label,
style: const TextStyle(
fontWeight: FontWeight.w500,
color: Color(0xFF374151),
),
),
const SizedBox(height: 6),
TextField(
controller: controller,
decoration: InputDecoration(
hintText: hint,
filled: true,
fillColor: Colors.white,
contentPadding:
const EdgeInsets.symmetric(horizontal: 14, vertical: 14),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Color(0xFFD1D5DB)),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: const BorderSide(color: Color(0xFFD1D5DB)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide:
const BorderSide(color: Color(0xFF0F766E), width: 1.5),
),
),
),
],
);
}
}
class _PresetChip extends StatelessWidget {
final String label;
final VoidCallback onTap;
const _PresetChip({required this.label, required this.onTap});
@override
Widget build(BuildContext context) {
return Expanded(
child: GestureDetector(
onTap: onTap,
child: Container(
height: 40,
decoration: BoxDecoration(
color: const Color(0xFFE0F2F1),
borderRadius: BorderRadius.circular(10),
),
alignment: Alignment.center,
child: Text(
label,
style: const TextStyle(
color: Color(0xFF0F766E),
fontWeight: FontWeight.w500,
fontSize: 13,
),
),
),
),
);
}
}