Flutter
تضيف حزمة kavchat_flutter إلى تطبيقكم على Flutter دردشة دعم تعمل وفق سيناريو: أزرار، والتعرّف على النص الحر، ونموذج يفتح تذكرة دعم، ونسخة من البوت تعمل دون اتصال بالإنترنت، وعرض من اليمين إلى اليسار بالعبرية والعربية.
التثبيت
dependencies:
kavchat_flutter: ^0.0.11تأتي الحزمة مع http وshared_preferences (لتخزين الإصدار مؤقتًا وحفظ المحادثة) وurl_launcher (للروابط في السيناريوهات). لفتح روابط tel: على Android 11 والإصدارات الأحدث، أضيفوا إلى AndroidManifest.xml إدخال <queries> للمخطط tel، وإدخالًا آخر للمخطط https لروابط المواقع (راجعوا README الخاص بـ url_launcher). على iOS، تحتاجون إلى LSApplicationQueriesSchemes فقط إذا كنتم تستدعون canLaunchUrl بأنفسكم.
الاستخدام
final kavchat = KavchatController(
publicKey: 'pk_live_...',
// apiBase: 'https://api.kavchat.com', // default
// locale: 'he', // default: device language if translated, else the bot language
onScreen: (screen, targetId) => navigatorKey.currentState?.pushNamed('/$screen', arguments: targetId),
);
Scaffold(
floatingActionButton: KavchatLauncher(controller: kavchat), // hidden while the bot is off
);
// or open it yourself
showKavchat(context, kavchat);
// or embed the screen in your own route
KavchatChat(controller: kavchat, onClose: () => Navigator.pop(context));أنشئوا وحدة التحكم مرة واحدة (مثلًا داخل State أو provider)، واستدعوا dispose() عند التخلص من الكائن الذي يحتفظ بها.
KavchatLauncher هو FloatingActionButton، ويمكنكم تحديد موضعه باستخدام Scaffold.floatingActionButtonLocation. يوضح الإعداد kavchat.settings?.position (start أو end) الجانب الذي تم اختياره في لوحة التحكم.
عند إعداد رسالة بجانب زر الدردشة في لوحة الإدارة (فقاعة كلام، أو نص مقوّس فوق الزر، أو الزر نفسه يتمدد إلى شكل كبسولة ويتحدث، أو خط يرتفع من الزر ويعرض خيارات البوت الأولى)، يعرضها KavchatLauncher بعد مدة التأخير المحددة، مرة واحدة يوميًا كحد أقصى. يؤدي الضغط على خيار في الخط إلى فتح الدردشة بهذا الخيار، كما لو تم اختياره داخل الدردشة. يؤدي إغلاق الرسالة أو فتح الدردشة إلى إخفاء الرسالة حتى الغد. لا تظهر الرسالة أثناء فتح الدردشة. إذا كان تقليل الحركة مفعّلًا على الجهاز، تظهر الرسالة دون حركة. عند تفعيل خيار "عدم العرض على الهواتف"، تظهر الرسالة على الأجهزة اللوحية فقط (عندما يكون أقصر ضلع للشاشة 600 نقطة أو أكثر). على الهاتف، يعرض الخط خيارين كحد أقصى. يعطّل KavchatLauncher(controller: kavchat, attention: false) عرض الرسالة.
عندما تكون أيقونة الزر في السمة وجهًا، فإنه يرمش من حين لآخر عندما يكون الزر ساكنًا. لا يرمش الوجه أثناء فتح الدردشة، أو عندما يكون التطبيق في الخلفية، أو عند تفعيل تقليل الحركة.
لا يظهر البوت (لا يظهر الزر العائم، ويعرض KavchatChat عبارة "غير متاح") عندما يكون الإصدار enabled: false: إذا كان البوت متوقفًا، أو متاحًا لمستخدمي الاختبار فقط والمستخدم ليس منهم، أو إذا نفدت الحصة (reason: 'quota').
رمز الهوية
للمستخدمين الذين سجّلوا الدخول، وقّعوا رمز JWT قصيرًا على خادمكم باستخدام المفتاح السري (وليس داخل التطبيق أبدًا، راجعوا التعرّف على المستخدمين) ثم مرّروه:
KavchatController(publicKey: 'pk_live_...', userToken: jwt, userName: 'Dana');
await kavchat.setUser(token: newJwt, name: 'Dana'); // after login
await kavchat.setUser(token: null); // after logoutيُرسل الرمز في الترويسة Authorization: Bearer <token> مع كل استدعاء. عند وجود الرمز، لا يتطلب نموذج التواصل بريدًا إلكترونيًا أو رقم هاتف، ويمكن التعرّف على المستخدم ضمن مجموعة مستخدمي الاختبار. يعيد setUser تحميل الإصدار، ويبدأ المستخدم الآخر محادثة جديدة، لذلك لا تنتقل المحادثة المحفوظة على الجهاز إلى حساب آخر أبدًا.
الروابط والشاشات ونموذج التواصل
- تُفتح الأزرار من النوع
linkباستخدامurl_launcher، لعناوينhttps:وtel:فقط. أما الروابط داخل رسائل البوت فتقتصر علىhttps:. - تستدعي الأزرار من النوع
screenالدالةonScreen(screen, targetId). من دون هذه الدالة، لا تفعل شيئًا. - يفتح زر "التواصل مع الفريق" النموذج المدمج (الاسم، والبريد الإلكتروني، والهاتف، والموضوع، والرسالة، مع إرفاق المحادثة)، ويعرض رقم التذكرة بعد الإرسال.
قائمة الشاشات في المحرر
عرّفوا الشاشات التي يمكن للتطبيق فتحها مرة واحدة في KavchatController(screens: ...). ترسل حزمة التطوير القائمة إلى Kavchat تلقائيًا، ويعرض محرر السيناريوهات هذه الشاشات بأسمائها في قائمة منسدلة بدلًا من حقل نص حر. يطلب المحرر أيضًا معرّف العنصر عندما تحتاجه الشاشة، ويحذّر من أي زر يؤدي إلى شاشة لم يتم تعريفها. لا حاجة إلى كتابة قائمة الشاشات يدويًا في لوحة التحكم.
final kavchat = KavchatController(
publicKey: 'pk_live_...',
screens: const [
KavchatScreen(id: 'orders', label: 'My orders'),
KavchatScreen(id: 'product', label: 'Product page', needsTarget: true), // the button carries a targetId
],
onScreen: (screen, targetId) => navigatorKey.currentState?.pushNamed('/$screen', arguments: targetId),
);
// later, to replace the list: await kavchat.registerScreens([...]);idهو القيمة التي تصل إلىonScreen: أحرف لاتينية، وأرقام، و_، و.، و-، بحد أقصى 40 محرفًا. أماlabelفهو الاسم الذي يراه المسؤول، بحد أقصى 60 محرفًا. الحد الأقصى هو 100 شاشة. تُستبعد الإدخالات غير الصالحة والمعرّفات المكررة.needsTarget: يحمل الزر أيضًا معرّف عنصر (مثل معرّف منتج)، ويصل إلىonScreenباسمtargetId.- تُرسل القائمة في الخلفية بعد تحميل الإصدار، فقط عند تغيّرها أو مرة أسبوعيًا. إذا فشل الإرسال، لا يظهر أي تنبيه، وتُعاد المحاولة عند التشغيل التالي. لا يرى المستخدم شيئًا.
- تظهر الشاشات المسجّلة في لوحة التحكم ضمن البوت، ثم الإعدادات، ثم "شاشات التطبيق"، مع المنصات التي أبلغت عن كل شاشة. يمكنكم حذف أي شاشة أزلتموها من التطبيق من هناك.
RTL
تضبط الدردشة Directionality الخاص بها بحسب لغة الواجهة: he وar من اليمين إلى اليسار، وبقية اللغات من اليسار إلى اليمين. ولا تغيّر اتجاه تطبيقكم. تختار كل فقاعة اتجاهها أيضًا بحسب أول حرف ذي اتجاه قوي، ليُقرأ المحتوى المختلط بشكل صحيح. لغة الواجهة منفصلة عن لغة السيناريو: يمكن لبوت باللغة الإنجليزية عرض أزرار بالعربية، مثل "رجوع"، عند استخدام locale: 'ar'.
الألوان والهوية البصرية
تأتي الألوان من إعداد البوت primaryColor. يكون النص فوقه أسود أو أبيض بحسب تباين WCAG، ويُستبدل اللون الفاتح جدًا بلون داكن في المواضع التي يُستخدم فيها للنص. لتغيير الألوان:
KavchatLauncher(controller: kavchat, theme: KavchatThemeData.fromColor(const Color(0xFF0F766E)));
KavchatChat(controller: kavchat, theme: KavchatThemeData.fromHex('#0f766e').copyWith(background: Colors.white));تظهر شارة "يعمل بواسطة Kavchat by maxsave" في جميع الباقات، مع رابط إلى kavchat.com. في باقة بريميوم، يمكنكم إخفاؤها من إعدادات البوت.
الدردشة مع موظف دعم
لا حاجة إلى إعدادات للبدء. عند تفعيل الدردشة مع موظفي الدعم في لوحة الإدارة، يظهر الخيار في دردشة التطبيق تمامًا كما يظهر في أداة الدردشة على الموقع.
- الخيار: يظهر "التحدث مع موظف دعم" قبل "التواصل مع الفريق"، وفقط بعد أن يؤكد الخادم وجود موظف متاح. يُعاد التحقق من التوفّر عند الضغط على الزر. خارج ساعات العمل، أو عندما يكون جميع الموظفين مشغولين، يظهر نموذج التواصل فقط مع توضيح قصير وموعد عودة الفريق، إن كان معروفًا. عند نفاد الحصة الشهرية، يظهر النموذج دون توضيح.
- الطلب: يترك الزوّار بريدًا إلكترونيًا أو رقم هاتف تحسّبًا لعدم توفّر موظف في الوقت المحدد. ويمكنهم أيضًا إضافة اسم ورسالة أولى. عندما يكون أكثر من قسم مفتوحًا، يختارون قسمًا. لا يحتاج المستخدمون المعروفون (
userToken) إلى إدخال بيانات التواصل. إذا لم يتمكن أي موظف من استقبال المحادثة، يُفتح نموذج التواصل بالبيانات التي أُدخلت بالفعل. - الانتظار: تظهر عبارة "بانتظار موظف دعم" مع عدّ تنازلي حتى نهاية مدة الانتظار التي حددتموها، وإلى جانبها زرا "ترك رسالة بدلًا من الانتظار" و"إنهاء المحادثة". يمكن للمستخدم الكتابة أثناء الانتظار. عند انتهاء الوقت، تتحول المحادثة تلقائيًا إلى تذكرة. يظهر رقم التذكرة وتوضيح بأن أي موظف لم يتفرغ في الوقت المحدد.
- المحادثة: اسم الموظف، والرسائل، ومؤشر الكتابة، والتحويل إلى موظف آخر، وإنهاء المحادثة. يُعرض كل ما يصل من الخادم كنص عادي دون روابط.
- في الوقت الفعلي: اتصال بأحداث يرسلها الخادم (Server-Sent Events) عبر استجابة
httpمتدفقة. إذا انقطع الاتصال، تعيد الدردشة الاتصال بفواصل زمنية متزايدة وتسترجع كل ما فاتها. بهذه الطريقة، لا تضيع أي رسالة ولا تظهر مرتين. على الشبكات التي تحجب هذا الاتصال، وفي Flutter Web، تعمل الدردشة بالاستطلاع الطويل المتكرر (long-poll). لكل رسالة معرّف، لذلك لا تؤدي إعادة المحاولة إلى تكرارها. تُعلَّم الرسالة التي لم تُرسل، ويمكن إعادة إرسالها بضغطة. - الانتقال إلى الخلفية وإعادة التشغيل: عندما ينتقل التطبيق إلى الخلفية (
paused،hidden)، يُغلق الاتصال. وعند عودته (resumed)، تسترجع الدردشة ما فاتها. يظل تصريح الوصول إلى المحادثة صالحًا لمدة تصل إلى 12 ساعة أو حتى انتهاء المحادثة، ويُحفظ في مساحة التخزين التي تختارونها. وهكذا تعود المحادثة المفتوحة إلى الشاشة بعد إعادة تشغيل التطبيق. لا يُحفظ التصريح في العنوان ولا يُكتب في السجل. - لا توجد إشعارات فورية في هذا الإصدار: تصل رسائل الموظف فقط عندما يكون التطبيق مفتوحًا.
يُنصح بحفظ تصريح الوصول في تخزين آمن (Keychain على iOS وKeystore على Android)، مثلًا باستخدام flutter_secure_storage. إذا لم تضبطوا secureStorage، يُحفظ التصريح في مساحة التخزين نفسها المستخدمة للمحادثة. يفتح زرّكم المخصص للتحدث مع موظف دعم نموذج الطلب عندما يكون هناك موظف متاح. وإذا لم يتوفر موظف، يُفتح نموذج التواصل مع التوضيح:
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class SecureKavchatStorage implements KavchatStorage {
final _s = const FlutterSecureStorage();
@override
Future<String?> read(String key) => _s.read(key: key);
@override
Future<void> write(String key, String value) => _s.write(key: key, value: value);
@override
Future<void> remove(String key) => _s.delete(key: key);
}
final kavchat = KavchatController(
publicKey: 'pk_live_...',
secureStorage: SecureKavchatStorage(),
livePage: 'checkout',
onLivePhase: (phase) => debugPrint('live chat: $phase'),
);
// your own button
FilledButton(onPressed: kavchat.openLive, child: const Text('Chat with us'));يتوفر المنطق نفسه، من دون Flutter، في kavchat_engine (KavchatClient، وLiveSession، وآلة الحالات المشتركة liveApplyEvent، وliveLines وliveStatus، التي تجتاز متجهات الاختبار نفسها الخاصة بأداة الدردشة على الموقع).
الأسئلة والشروط والعملاء المحتملون
لا حاجة إلى إعدادات في التطبيق. يمكن للسيناريو طلب بيانات (اسم، أو هاتف، أو بريد إلكتروني، أو رقم، أو نص)، واختيار كيفية المتابعة وفق شروط (بريميوم)، وإرسال بيانات عميل محتمل. يعمل كل ذلك على الجهاز.
- لوحة مفاتيح مناسبة: عندما ينتظر البوت إجابة، يعرض حقل النص لوحة مفاتيح للهاتف أو البريد الإلكتروني أو الأرقام، مع الإكمال التلقائي. إذا كانت الإجابة غير صالحة، يوضح البوت ما ينقصها ويُميّز الحقل. يظهر زر "تخطي" في الأسئلة التي يمكن تجاوزها.
- العميل المحتمل: عند وجود نص للموافقة، يظهر زرا "إرسال" و"لا، شكرًا". إذا لم يتوفر اتصال بالإنترنت، تُحفظ بيانات العميل المحتمل على الجهاز وتُرسل عند عودة الاتصال، دون تكرار.
- الملء المسبق: تُستخدم الإجابات التي قدّمها المستخدم لملء نموذج التواصل ونموذج طلب التحدث مع موظف دعم، وتُرفق بالتذكرة وبالمحادثة مع الموظف. يُعدّ الاسم والبريد الإلكتروني ورقم الهاتف الواردة في رمز الهوية إجابات معروفة، ولا يسأل عنها البوت مجددًا.
- الشاشة الحالية: يحدد
livePageأيضًا الشاشة التي تتحقق منها الشروط والتي تُرسل مع بيانات العملاء المحتملين. عندما ينتقل المستخدم إلى شاشة أخرى، استدعواsetPage('checkout').
إجابات الذكاء الاصطناعي (بريميوم)
لا حاجة إلى إعداد أي شيء في التطبيق. عند تفعيل إجابات الذكاء الاصطناعي في لوحة الإدارة (باستخدام مفتاحكم الخاص لدى مزوّد الذكاء الاصطناعي)، يُرسل إلى Kavchat السؤال الذي لا يجيب عنه أي سيناريو. وأثناء الانتظار، لمدة تصل إلى 20 ثانية، تعرض الدردشة مؤشرًا بأن البوت يكتب. تظهر الإجابة كنص عادي مع تسمية صغيرة "إجابة الذكاء الاصطناعي" بلغة الواجهة، وتحتها زر لموضوع ذي صلة، إن وجد، وزر "التواصل مع الفريق".
إذا لم تتوفر إجابة، أو فشل الطلب، أو استغرق وقتًا أطول من المسموح، أو تجاوز الحد (10 إجابات لكل محادثة خلال كل 15 دقيقة)، تعرض الدردشة رسالة "لم أجد إجابة" المعتادة. يظل السؤال ظاهرًا في تقرير الأسئلة التي لم تُعثر لها على إجابة، وتُحفظ إجابات الذكاء الاصطناعي في المحادثة المحفوظة مثل أي رسالة أخرى.
العمل دون اتصال والتخزين المؤقت
يُحفظ الإصدار في الذاكرة المؤقتة مع ETag الخاص به (If-None-Match، 304). عند غياب الاتصال أو حدوث خطأ في الخادم، تُستخدم النسخة المحفوظة وتظهر رسالة توضح ذلك. تُحفظ المحادثة لكل بوت وتُستعاد لمدة 24 ساعة، ما دام الإصدار لم يتغير. يُرسل مسار المحادثة إلى الخادم بعد 2 ثانية من آخر إجراء، وكذلك عندما ينتقل التطبيق إلى الخلفية.