diff --git a/README.md b/README.md index 270a615..5a251ac 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Integrate Chatwoot flutter client into your flutter app and talk to your visitor chatwoot screenshot -## 1. Add the package to your project +## 1. Installation Run the command below in your terminal @@ -18,11 +18,163 @@ Add `chatwoot_sdk:<>` to your project's [pubspec.yml](https://flutter.dev/docs/development/tools/pubspec) file. You can check [here](https://pub.dev/packages/chatwoot_sdk) for the latest version. -## 2. How to use +## 2. Getting Started -### a. Using ChatwootWidget +| Options | Use case | Inbox Type | Example | Known Platform Support Issues | +|----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------|-------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ChatwootClient | Bare client api for building custom chat widgets. | API | [Chatwoot Client example](#a-using-chatwoot-client) | - | +| ChatwootDialog | Flutter Widget implementation built on the ChatwootClient | API | [Chatwoot Dialog example](#b-using-chatwootChatDialog) | - | +| ChatwootChat | Also a widget implementation of ChatwootClient but presents only the Chat interface. Can be embedded in a a custom page unlike the dialog which is always presented in a dialog | API | [Chatwoot Chat Widget example](#c-embedding-chatwootChat) | - | +| ChatwootWidget | The chatwoot website channel widget embedded in a flutter webview | Website | [Chatwoot Webview Widget example](#d-using-chatwootWidgetwebview) | Flutter webview currently supports only android & ios. Adding file attachment not supported on ios. Some known issues with previewing and downloading attached files on both Android and ios. | -* Create a website channel in chatwoot server by following the steps described here https://www.chatwoot.com/docs/channels/website +## 3. How to use + +### a. Using Chatwoot Client +* Create an Api inbox in Chatwoot. Refer to [Create API Channel](https://www.chatwoot.com/docs/product/channels/api/create-channel) document. +* Create your own customized chat ui and use `ChatwootClient` to load and sendMessages. Messaging events like `onMessageSent` and `onMessageReceived` will be triggered on `ChatwootCallback` argument passed when creating the client instance. + + +NB: This chatwoot client uses [Hive](https://pub.dev/packages/hive) for local storage. + +```dart +final chatwootCallbacks = ChatwootCallbacks( + onWelcome: (){ + print("on welcome"); + }, + onPing: (){ + print("on ping"); + }, + onConfirmedSubscription: (){ + print("on confirmed subscription"); + }, + onConversationStartedTyping: (){ + print("on conversation started typing"); + }, + onConversationStoppedTyping: (){ + print("on conversation stopped typing"); + }, + onPersistedMessagesRetrieved: (persistedMessages){ + print("persisted messages retrieved"); + }, + onMessagesRetrieved: (messages){ + print("messages retrieved"); + }, + onMessageReceived: (chatwootMessage){ + print("message received"); + }, + onMessageDelivered: (chatwootMessage, echoId){ + print("message delivered"); + }, + onMessageSent: (chatwootMessage, echoId){ + print("message sent"); + }, + onError: (error){ + print("Ooops! Something went wrong. Error Cause: ${error.cause}"); + }, + ); + + ChatwootClient.create( + baseUrl: widget.baseUrl, + inboxIdentifier: widget.inboxIdentifier, + user: widget.user, + enablePersistence: widget.enablePersistence, + callbacks: chatwootCallbacks + ).then((client) { + client.loadMessages(); + }).onError((error, stackTrace) { + print("chatwoot client error $error: $stackTrace"); + }); +``` + +#### Available Parameters + +| Name | Default | Type | Description | +|-------------------|---------|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| baseUrl | - | String | Installation url for chatwoot | +| inboxIdentifier | - | String | Identifier for target chatwoot inbox | +| enablePersistance | true | bool | Enables persistence of chatwoot client instance's contact, conversation and messages to disk
for convenience.
true - persists chatwoot client instance's data(contact, conversation and messages) to disk. To clear persisted
data call ChatwootClient.clearData or ChatwootClient.clearAllData
false - holds chatwoot client instance's data in memory and is cleared as
soon as chatwoot client instance is disposed
Setting | +| user | null | ChatwootUser | Custom user details to be attached to chatwoot contact | +| callbacks | null | ChatwootCallbacks | Callbacks for handling chatwoot events | + + +### b. Using ChatwootChatDialog +* Create an Api inbox in Chatwoot. Refer to [Create API Channel](https://www.chatwoot.com/docs/product/channels/api/create-channel) document. +* Call `ChatwootChatDialog.show` with Api inbox configuration + +```dart +ChatwootChatDialog.show( + context, + title: "Customer Support", + inboxIdentifier: "your-api-inbox-identifier", + userIdentityValidationKey: "your hmac user validation key", + baseUrl: "https://app.chatwoot.com", + user: ChatwootUser( + identifier: "test@test.com", + name: "Tester test", + email: "test@test.com", + ), + primaryColor: const Color(0xff258596), + onAttachmentPressed: _handleAttachmentPressed, + openFile: _handleOpenFile, +); +``` + +#### Available Parameters + +| Name | Default | Type | Description | +|-------------------------------|---------|-----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| baseUrl | - | String | Installation url for chatwoot | +| inboxIdentifier | - | String | Identifier for target chatwoot inbox | +| enablePersistance | true | bool | Enables persistence of chatwoot client instance's contact, conversation and messages to disk
for convenience.
true - persists chatwoot client instance's data(contact, conversation and messages) to disk. To clear persisted
data call ChatwootClient.clearData or ChatwootClient.clearAllData
false - holds chatwoot client instance's data in memory and is cleared as
soon as chatwoot client instance is disposed
Setting | +| user | null | ChatwootUser | Custom user details to be attached to chatwoot contact | +| primaryColor | blue | Widget color | Widget theme color | +| All chatwoot callback methods | null | ChatwootCallbacks | Callbacks for handling chatwoot events | +| onAttachmentPressed | null | Future Function() | Callback for handling attach file button onPressed | +| openFile | null | void Function(String filePath) | Callbacks for handling event where user taps to open an attachment | + + +### c. Embedding ChatwootChat +* Create an Api inbox in Chatwoot. Refer to [Create API Channel](https://www.chatwoot.com/docs/product/channels/api/create-channel) document. +* Initialize `ChatwootChat` with Api inbox configuration + +```dart + + ChatwootChat( + inboxIdentifier: "your-api-inbox-identifier", + userIdentityValidationKey: "your hmac user validation key", + baseUrl: "https://app.chatwoot.com", + user: ChatwootUser( + identifier: "test@test.com", + name: "Tester test", + email: "test@test.com", + ), + enablePersistence: true, + theme: ChatwootChatTheme(primaryColor: Colors.blue,), + onConversationIsOffline: () {}, + onConversationIsOnline: () {}, + onConversationStoppedTyping: () {}, + onConversationStartedTyping: () {}, + onAttachmentPressed: () async{return FileAttachment();}, + openFile: (filePath){}, + ); +``` + +#### Available Parameters + +| Name | Default | Type | Description | +|-------------------------------|---------|------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| baseUrl | - | String | Installation url for chatwoot | +| inboxIdentifier | - | String | Identifier for target chatwoot inbox | +| enablePersistance | true | bool | Enables persistence of chatwoot client instance's contact, conversation and messages to disk
for convenience.
true - persists chatwoot client instance's data(contact, conversation and messages) to disk. To clear persisted
data call ChatwootClient.clearData or ChatwootClient.clearAllData
false - holds chatwoot client instance's data in memory and is cleared as
soon as chatwoot client instance is disposed
Setting | +| user | null | ChatwootUser | Custom user details to be attached to chatwoot contact | +| All chatwoot callback methods | null | ChatwootCallbacks | Callbacks for handling chatwoot events | +| onAttachmentPressed | null | Future Function() | Callback for handling attach file button onPressed | +| openFile | null | void Function(String filePath) | Callbacks for handling event where user taps to open an attachment | + + +### d. Using ChatwootWidget(webview) + +* Create a **website channel** in chatwoot server by following the steps described here https://www.chatwoot.com/docs/channels/website * Replace websiteToken prop and baseUrl ```dart @@ -147,70 +299,3 @@ Horray! You're done. | onLoadStarted | - | void Function() | Widget load start event | | onLoadProgress | - | void Function(int) | Widget Load progress event | | onLoadCompleted | - | void Function() | Widget Load completed event | - -### b. Using Chatwoot Client -* Create an Api inbox in Chatwoot. Refer to [Create API Channel](https://www.chatwoot.com/docs/product/channels/api/create-channel) document. -* Create your own customized chat ui and use `ChatwootClient` to load and sendMessages. Messaging events like `onMessageSent` and `onMessageReceived` will be triggered on `ChatwootCallback` argument passed when creating the client instance. - - -NB: This chatwoot client uses [Hive](https://pub.dev/packages/hive) for local storage. - -```dart -final chatwootCallbacks = ChatwootCallbacks( - onWelcome: (){ - print("on welcome"); - }, - onPing: (){ - print("on ping"); - }, - onConfirmedSubscription: (){ - print("on confirmed subscription"); - }, - onConversationStartedTyping: (){ - print("on conversation started typing"); - }, - onConversationStoppedTyping: (){ - print("on conversation stopped typing"); - }, - onPersistedMessagesRetrieved: (persistedMessages){ - print("persisted messages retrieved"); - }, - onMessagesRetrieved: (messages){ - print("messages retrieved"); - }, - onMessageReceived: (chatwootMessage){ - print("message received"); - }, - onMessageDelivered: (chatwootMessage, echoId){ - print("message delivered"); - }, - onMessageSent: (chatwootMessage, echoId){ - print("message sent"); - }, - onError: (error){ - print("Ooops! Something went wrong. Error Cause: ${error.cause}"); - }, - ); - - ChatwootClient.create( - baseUrl: widget.baseUrl, - inboxIdentifier: widget.inboxIdentifier, - user: widget.user, - enablePersistence: widget.enablePersistence, - callbacks: chatwootCallbacks - ).then((client) { - client.loadMessages(); - }).onError((error, stackTrace) { - print("chatwoot client creation failed with error $error: $stackTrace"); - }); -``` - -#### Available Parameters - -| Name | Default | Type | Description | -|-------------------|---------|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| baseUrl | - | String | Installation url for chatwoot | -| inboxIdentifier | - | String | Identifier for target chatwoot inbox | -| enablePersistance | true | bool | Enables persistence of chatwoot client instance's contact, conversation and messages to disk
for convenience.
true - persists chatwoot client instance's data(contact, conversation and messages) to disk. To clear persisted
data call ChatwootClient.clearData or ChatwootClient.clearAllData
false - holds chatwoot client instance's data in memory and is cleared as
soon as chatwoot client instance is disposed
Setting | -| user | null | ChatwootUser | Custom user details to be attached to chatwoot contact | -| callbacks | null | ChatwootCallbacks | Callbacks for handling chatwoot events | diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 2e60d0e..36d2368 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -26,8 +26,15 @@ apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" android { - compileSdkVersion 33 - + namespace "com.example.example" + compileSdkVersion 34 + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = '17' + } sourceSets { main.java.srcDirs += 'src/main/kotlin' } @@ -35,8 +42,8 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). applicationId "com.chatwoot.example" - minSdkVersion 19 - targetSdkVersion 33 + minSdkVersion flutter.minSdkVersion + targetSdkVersion 34 versionCode flutterVersionCode.toInteger() versionName flutterVersionName } diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index c208884..f880684 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml index f0de856..b42f3ce 100644 --- a/example/android/app/src/main/AndroidManifest.xml +++ b/example/android/app/src/main/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml index c208884..f880684 100644 --- a/example/android/app/src/profile/AndroidManifest.xml +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,4 @@ - + diff --git a/example/android/build.gradle b/example/android/build.gradle index 0b0a838..01e5f23 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -1,12 +1,12 @@ buildscript { - ext.kotlin_version = '1.7.20' + ext.kotlin_version = '2.0.20' repositories { google() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:7.4.1' + classpath 'com.android.tools.build:gradle:8.7.0' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -26,6 +26,6 @@ subprojects { project.evaluationDependsOn(':app') } -task clean(type: Delete) { +tasks.register("clean", Delete) { delete rootProject.buildDir } diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties index 02e5f58..2aaed3a 100644 --- a/example/android/gradle/wrapper/gradle-wrapper.properties +++ b/example/android/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-all.zip diff --git a/example/lib/main.dart b/example/lib/main.dart index b885caa..cb0ff98 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -26,7 +26,7 @@ class MyApp extends StatelessWidget { } class MyHomePage extends StatefulWidget { - MyHomePage({Key key, this.title}) : super(key: key); + MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @@ -88,7 +88,7 @@ class _MyHomePageState extends State { final imageData = await photo.readAsBytes(); final decodedImage = image.decodeImage(imageData); - final scaledImage = image.copyResize(decodedImage, width: 500); + final scaledImage = image.copyResize(decodedImage!, width: 500); final jpg = image.encodeJpg(scaledImage, quality: 90); final filePath = (await getTemporaryDirectory()).uri.resolve( diff --git a/example/lib/main_client.dart b/example/lib/main_client.dart new file mode 100644 index 0000000..0c67cae --- /dev/null +++ b/example/lib/main_client.dart @@ -0,0 +1,112 @@ + +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:chatwoot_sdk/chatwoot_sdk.dart'; +import 'package:chatwoot_sdk/ui/chatwoot_chat_theme.dart'; +import 'package:flutter/material.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:open_filex/open_filex.dart'; + +void main() { + runApp(MyApp()); +} + +class MyApp extends StatelessWidget { + // This widget is the root of your application. + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Flutter Demo', + theme: ThemeData( + primarySwatch: Colors.blue, + ), + home: MyHomePage(title: 'Flutter Demo Home Page'), + ); + } +} + +class MyHomePage extends StatefulWidget { + MyHomePage({Key? key, required this.title}) : super(key: key); + + final String title; + + @override + _MyHomePageState createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + @override + void initState() { + super.initState(); + } + + _showDialog(){ + ChatwootChatDialog.show( + context, + title: "Customer Support", + inboxIdentifier: "your-api-inbox-identifier", + userIdentityValidationKey: "your-hmac-user-validation-key", + baseUrl: "https://app.chatwoot.com", + user: ChatwootUser( + identifier: "test@test.com", + name: "Tester test", + email: "test@test.com", + ), + primaryColor: const Color(0xff258596), + onAttachmentPressed: _handleAttachmentPressed, + openFile: _handleOpenFile, + ); + } + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text("Chatwoot Example"), + actions: [ + IconButton(onPressed: _showDialog, icon: Icon(Icons.copy)) + ], + ), + body: ChatwootChat( + inboxIdentifier: "your-api-inbox-identifier", + userIdentityValidationKey: "your-hmac-user-validation-key", + baseUrl: "https://app.chatwoot.com", + user: ChatwootUser( + identifier: "test@test.com", + name: "Tester test", + email: "test@test.com", + ), + theme: ChatwootChatTheme( + primaryColor: const Color(0xff258596) + ), + onAttachmentPressed: _handleAttachmentPressed, + openFile: _handleOpenFile, + ), + ); + } + + Future _handleOpenFile(String filePath) async{ + await OpenFilex.open(filePath); + } + + Future _handleAttachmentPressed() async{ + return await _handleFileSelection(); + } + + + Future _handleFileSelection() async { + final result = await FilePicker.platform.pickFiles( + type: FileType.any, + ); + + if (result?.files.isNotEmpty ?? false) { + final bytes = await File(result!.files.first.path!).readAsBytes(); + final name = result.files.first.name; + final path = result.files.first.path ?? ''; + return FileAttachment(bytes: Uint8List.fromList(bytes), name: name, path: path); + } + + return null; + } + +} diff --git a/example/pubspec.lock b/example/pubspec.lock index 2913c99..3b17edf 100644 --- a/example/pubspec.lock +++ b/example/pubspec.lock @@ -5,18 +5,26 @@ packages: dependency: transitive description: name: archive - sha256: d6347d54a2d8028e0437e3c099f66fdb8ae02c4720c1e7534c9f24c10351f85d + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d url: "https://pub.dev" source: hosted - version: "3.3.6" + version: "3.6.1" + args: + dependency: transitive + description: + name: args + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 + url: "https://pub.dev" + source: hosted + version: "2.6.0" async: dependency: transitive description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" boolean_selector: dependency: transitive description: @@ -25,14 +33,38 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + cached_network_image: + dependency: transitive + description: + name: cached_network_image + sha256: "4a5d8d2c728b0f3d0245f69f921d7be90cae4c2fd5288f773088672c0893f819" + url: "https://pub.dev" + source: hosted + version: "3.4.0" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" + url: "https://pub.dev" + source: hosted + version: "4.1.1" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "6322dde7a5ad92202e64df659241104a43db20ed594c41ca18de1014598d7996" + url: "https://pub.dev" + source: hosted + version: "1.3.0" characters: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" chatwoot_sdk: dependency: "direct main" description: @@ -52,74 +84,90 @@ packages: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.0" - convert: - dependency: transitive - description: - name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" - url: "https://pub.dev" - source: hosted - version: "3.1.1" + version: "1.18.0" cross_file: dependency: transitive description: name: cross_file - sha256: "0b0036e8cccbfbe0555fd83c1d31a6f30b77a96b598b35a5d36dd41f718695e9" + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" url: "https://pub.dev" source: hosted - version: "0.3.3+4" + version: "0.3.4+2" crypto: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.6" csslib: dependency: transitive description: name: csslib - sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" url: "https://pub.dev" source: hosted - version: "0.17.2" + version: "1.0.2" cupertino_icons: dependency: "direct main" description: name: cupertino_icons - sha256: e35129dc44c9118cee2a5603506d823bab99c68393879edb440e0090d07586be + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.8" + dbus: + dependency: transitive + description: + name: dbus + sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" + url: "https://pub.dev" + source: hosted + version: "0.7.10" diffutil_dart: dependency: transitive description: name: diffutil_dart - sha256: "21bcad3fcc89389da5c72c59b9da31eabb301a6548f715c17b0dfdd27d2ac6d5" + sha256: "5e74883aedf87f3b703cb85e815bdc1ed9208b33501556e4a8a5572af9845c81" url: "https://pub.dev" source: hosted - version: "2.0.0+1" + version: "4.0.1" dio: dependency: transitive description: name: dio - sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8" + sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260" + url: "https://pub.dev" + source: hosted + version: "5.7.0" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8" url: "https://pub.dev" source: hosted - version: "4.0.6" + version: "2.0.0" + easy_image_viewer: + dependency: transitive + description: + name: easy_image_viewer + sha256: fb6cb123c3605552cc91150dcdb50ca977001dcddfb71d20caa0c5edc9a80947 + url: "https://pub.dev" + source: hosted + version: "1.5.1" equatable: dependency: transitive description: name: equatable - sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.7" fake_async: dependency: transitive description: @@ -132,111 +180,183 @@ packages: dependency: transitive description: name: ffi - sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.1.3" file: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.1" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: "825aec673606875c33cd8d3c4083f1a3c3999015a84178b317b7ef396b7384f3" + url: "https://pub.dev" + source: hosted + version: "8.0.7" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: b2b91daf8a68ecfa4a01b778a6f52edef9b14ecd506e771488ea0f2e0784198b + url: "https://pub.dev" + source: hosted + version: "0.9.3+1" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "271ab9986df0c135d45c3cdb6bd0faa5db6f4976d3e4b437cf7d0f258d941bfc" + url: "https://pub.dev" + source: hosted + version: "0.9.4+2" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "8f5d2f6590d51ecd9179ba39c64f722edc15226cc93dcc8698466ad36a4a85a4" + url: "https://pub.dev" + source: hosted + version: "0.9.3+3" + fixnum: + dependency: transitive + description: + name: fixnum + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be + url: "https://pub.dev" + source: hosted + version: "1.1.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.dev" + source: hosted + version: "3.4.1" flutter_chat_types: dependency: transitive description: name: flutter_chat_types - sha256: cb9e72c6dee5f32e4b379b6b953dff95253c54242ee4e21ad81652b11902d5a8 + sha256: e285b588f6d19d907feb1f6d912deaf22e223656769c34093b64e1c59b094fb9 url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "3.6.2" flutter_chat_ui: dependency: transitive description: name: flutter_chat_ui - sha256: "9c19396e59de978da092a935a04542ecf9746e3d75b9b7a038638e2a1982a5a1" + sha256: "168a4231464ad00a17ea5f0813f1b58393bdd4035683ea4dc37bbe26be62891e" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.6.15" flutter_link_previewer: dependency: transitive description: name: flutter_link_previewer - sha256: "0adc16359ce8385d623ee4b2985e702d7766d52e351bf0fd6a12366f8e49a63f" + sha256: "007069e60f42419fb59872beb7a3cc3ea21e9f1bdff5d40239f376fa62ca9f20" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "3.2.2" flutter_linkify: dependency: transitive description: name: flutter_linkify - sha256: c89fe74de985ec22f23d3538d2249add085a4f37ac1c29fd79e1a207efb81d63 + sha256: "74669e06a8f358fee4512b4320c0b80e51cffc496607931de68d28f099254073" url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "6.0.0" + flutter_markdown: + dependency: transitive + description: + name: flutter_markdown + sha256: "999a4e3cb3e1532a971c86d6c73a480264f6a687959d4887cb4e2990821827e4" + url: "https://pub.dev" + source: hosted + version: "0.7.4+2" + flutter_parsed_text: + dependency: transitive + description: + name: flutter_parsed_text + sha256: "529cf5793b7acdf16ee0f97b158d0d4ba0bf06e7121ef180abe1a5b59e32c1e2" + url: "https://pub.dev" + source: hosted + version: "2.2.1" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: c224ac897bed083dabf11f238dd11a239809b446740be0c2044608c50029ffdf + sha256: "9b78450b89f059e96c9ebb355fa6b3df1d6b330436e0b885fb49594c41721398" url: "https://pub.dev" source: hosted - version: "2.0.9" + version: "2.0.23" flutter_secure_storage: dependency: transitive description: name: flutter_secure_storage - sha256: "98352186ee7ad3639ccc77ad7924b773ff6883076ab952437d20f18a61f0a7c5" + sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0" url: "https://pub.dev" source: hosted - version: "8.0.0" + version: "9.2.2" flutter_secure_storage_linux: dependency: transitive description: name: flutter_secure_storage_linux - sha256: "0912ae29a572230ad52d8a4697e5518d7f0f429052fd51df7e5a7952c7efe2a3" + sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b" url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "1.2.1" flutter_secure_storage_macos: dependency: transitive description: name: flutter_secure_storage_macos - sha256: "083add01847fc1c80a07a08e1ed6927e9acd9618a35e330239d4422cd2a58c50" + sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.1.2" flutter_secure_storage_platform_interface: dependency: transitive description: name: flutter_secure_storage_platform_interface - sha256: b3773190e385a3c8a382007893d678ae95462b3c2279e987b55d140d3b0cb81b + sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8 url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.2" flutter_secure_storage_web: dependency: transitive description: name: flutter_secure_storage_web - sha256: "42938e70d4b872e856e678c423cc0e9065d7d294f45bc41fc1981a4eb4beaffe" + sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9 url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.1" flutter_secure_storage_windows: dependency: transitive description: name: flutter_secure_storage_windows - sha256: fc2910ec9b28d60598216c29ea763b3a96c401f0ce1d13cdf69ccb0e5c93c3ee + sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709 url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "3.1.2" flutter_test: dependency: "direct dev" description: flutter @@ -247,14 +367,6 @@ packages: description: flutter source: sdk version: "0.0.0" - freezed_annotation: - dependency: transitive - description: - name: freezed_annotation - sha256: "70776c4541e5cacfe45bcaf00fe79137b8c61aa34fb5765a05ce6c57fd72c6e9" - url: "https://pub.dev" - source: hosted - version: "0.14.3" hive: dependency: transitive description: @@ -275,18 +387,18 @@ packages: dependency: transitive description: name: html - sha256: d9793e10dbe0e6c364f4c59bf3e01fb33a9b2a674bc7a1081693dba0614b6269 + sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" url: "https://pub.dev" source: hosted - version: "0.15.1" + version: "0.15.5" http: dependency: transitive description: name: http - sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "1.2.2" http_parser: dependency: transitive description: @@ -299,218 +411,442 @@ packages: dependency: "direct main" description: name: image - sha256: "483a389d6ccb292b570c31b3a193779b1b0178e7eb571986d9a49904b6861227" + sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d url: "https://pub.dev" source: hosted - version: "4.0.15" + version: "4.3.0" image_picker: dependency: "direct main" description: name: image_picker - sha256: "64b21d9f0e065f9ab0e4dde458076226c97382cc0c6949144cb874c62bf8e9f8" + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" url: "https://pub.dev" source: hosted - version: "0.8.7" + version: "1.1.2" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "420ed22d2c9ce767ed96df723aaebfeb20ce92dfda8665cd2ba72d72a51ae669" + sha256: "8faba09ba361d4b246dc0a17cb4289b3324c2b9f6db7b3d457ee69106a86bd32" url: "https://pub.dev" source: hosted - version: "0.8.6+1" + version: "0.8.12+17" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "98f50d6b9f294c8ba35e25cc0d13b04bfddd25dbc8d32fa9d566a6572f2c081c" + sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" url: "https://pub.dev" source: hosted - version: "2.1.12" + version: "3.0.6" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: "50e882fe0a06bf0c8f7f5bce78d30975f279213293afc9471dc35f05617c50ff" + sha256: "4f0568120c6fcc0aaa04511cb9f9f4d29fc3d0139884b1d06be88dcec7641d6b" url: "https://pub.dev" source: hosted - version: "0.8.7+1" + version: "0.8.12+1" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" image_picker_platform_interface: dependency: transitive description: name: image_picker_platform_interface - sha256: "1991219d9dbc42a99aff77e663af8ca51ced592cd6685c9485e3458302d3d4f8" + sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80" url: "https://pub.dev" source: hosted - version: "2.6.3" + version: "2.10.0" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" intl: dependency: transitive description: name: intl - sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + sha256: "99f282cb0e02edcbbf8c6b3bbc7c90b65635156c412e58f3975a7e55284ce685" url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "0.20.0" js: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" json_annotation: dependency: transitive description: name: json_annotation - sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" + url: "https://pub.dev" + source: hosted + version: "4.9.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + url: "https://pub.dev" + source: hosted + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" url: "https://pub.dev" source: hosted - version: "4.8.0" + version: "3.0.1" linkify: dependency: transitive description: name: linkify - sha256: bdfbdafec6cdc9cd0ebb333a868cafc046714ad508e48be8095208c54691d959 + sha256: "4139ea77f4651ab9c315b577da2dd108d9aa0bd84b5d03d33323f1970c645832" url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "5.0.0" + markdown: + dependency: transitive + description: + name: markdown + sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 + url: "https://pub.dev" + source: hosted + version: "7.2.2" matcher: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + media_kit: + dependency: transitive + description: + name: media_kit + sha256: "1f1deee148533d75129a6f38251ff8388e33ee05fc2d20a6a80e57d6051b7b62" + url: "https://pub.dev" + source: hosted + version: "1.1.11" + media_kit_libs_android_video: + dependency: transitive + description: + name: media_kit_libs_android_video + sha256: "9dd8012572e4aff47516e55f2597998f0a378e3d588d0fad0ca1f11a53ae090c" + url: "https://pub.dev" + source: hosted + version: "1.3.6" + media_kit_libs_ios_video: + dependency: transitive + description: + name: media_kit_libs_ios_video + sha256: b5382994eb37a4564c368386c154ad70ba0cc78dacdd3fb0cd9f30db6d837991 + url: "https://pub.dev" + source: hosted + version: "1.1.4" + media_kit_libs_linux: + dependency: transitive + description: + name: media_kit_libs_linux + sha256: e186891c31daa6bedab4d74dcdb4e8adfccc7d786bfed6ad81fe24a3b3010310 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + media_kit_libs_macos_video: + dependency: transitive + description: + name: media_kit_libs_macos_video + sha256: f26aa1452b665df288e360393758f84b911f70ffb3878032e1aabba23aa1032d + url: "https://pub.dev" + source: hosted + version: "1.1.4" + media_kit_libs_video: + dependency: transitive + description: + name: media_kit_libs_video + sha256: "20bb4aefa8fece282b59580e1cd8528117297083a6640c98c2e98cfc96b93288" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + media_kit_libs_windows_video: + dependency: transitive + description: + name: media_kit_libs_windows_video + sha256: "32654572167825c42c55466f5d08eee23ea11061c84aa91b09d0e0f69bdd0887" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "1.0.10" + media_kit_native_event_loop: + dependency: transitive + description: + name: media_kit_native_event_loop + sha256: "7d82e3b3e9ded5c35c3146c5ba1da3118d1dd8ac3435bac7f29f458181471b40" + url: "https://pub.dev" + source: hosted + version: "1.0.9" + media_kit_video: + dependency: transitive + description: + name: media_kit_video + sha256: "2cc3b966679963ba25a4ce5b771e532a521ebde7c6aa20e9802bec95d9916c8f" + url: "https://pub.dev" + source: hosted + version: "1.2.5" meta: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.15.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" + open_filex: + dependency: "direct main" + description: + name: open_filex + sha256: ba425ea49affd0a98a234aa9344b9ea5d4c4f7625a1377961eae9fe194c3d523 + url: "https://pub.dev" + source: hosted + version: "4.5.0" + package_info_plus: + dependency: transitive + description: + name: package_info_plus + sha256: da8d9ac8c4b1df253d1a328b7bf01ae77ef132833479ab40763334db13b91cce + url: "https://pub.dev" + source: hosted + version: "8.1.1" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66 + url: "https://pub.dev" + source: hosted + version: "3.0.1" path: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.9.0" path_provider: dependency: "direct main" description: name: path_provider - sha256: "04890b994ee89bfa80bf3080bfec40d5a92c5c7a785ebb02c13084a099d2b6f9" + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.0.13" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: a776c088d671b27f6e3aa8881d64b87b3e80201c64e8869b811325de7a76c15e + sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a url: "https://pub.dev" source: hosted - version: "2.0.22" + version: "2.2.12" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "026b97a6c29da75181a37aae2eba9227f5fe13cb2838c6b975ce209328b8ab4e" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.4.0" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: ab0987bf95bc591da42dffb38c77398fc43309f0b9b894dcc5d6f40c4b26c379 + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dev" source: hosted - version: "2.1.7" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: f0abc8ebd7253741f05488b4813d936b4d07c6bae3e86148a09e342ee4b08e76 + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.1.2" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: bcabbe399d4042b8ee687e17548d5d3f527255253b4a639f5f8d2094a9c2b45c + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.3.0" petitparser: dependency: transitive description: name: petitparser - sha256: "49392a45ced973e8d94a85fdb21293fbb40ba805fc49f2965101ae748a3683b4" + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "6.0.2" photo_view: dependency: transitive description: name: photo_view - sha256: aedb4371e5bf67546ecd92aed341df714f9de5db7c417ce7538a91c2b43d931a + sha256: "1fc3d970a91295fbd1364296575f854c9863f225505c28c46e0a03e48960c75e" url: "https://pub.dev" source: hosted - version: "0.12.0" + version: "0.15.0" platform: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: dbf0f707c78beedc9200146ad3cb0ab4d5da13c246336987be6940f026500d3a + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.3" - pointycastle: + version: "2.1.8" + riverpod: dependency: transitive description: - name: pointycastle - sha256: db7306cf0249f838d1a24af52b5a5887c5bf7f31d8bb4e827d071dc0939ad346 + name: riverpod + sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959" url: "https://pub.dev" source: hosted - version: "3.6.2" - process: + version: "2.6.1" + rxdart: dependency: transitive description: - name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" url: "https://pub.dev" source: hosted - version: "4.2.4" - riverpod: + version: "0.28.0" + safe_local_storage: dependency: transitive description: - name: riverpod - sha256: "13cbe0e17b659f38027986df967b3eaf7f42c519786352167fc3db1be44eae07" + name: safe_local_storage + sha256: ede4eb6cb7d88a116b3d3bf1df70790b9e2038bc37cb19112e381217c74d9440 + url: "https://pub.dev" + source: hosted + version: "1.0.2" + screen_brightness: + dependency: transitive + description: + name: screen_brightness + sha256: ed8da4a4511e79422fc1aa88138e920e4008cd312b72cdaa15ccb426c0faaedd + url: "https://pub.dev" + source: hosted + version: "0.2.2+1" + screen_brightness_android: + dependency: transitive + description: + name: screen_brightness_android + sha256: "3df10961e3a9e968a5e076fe27e7f4741fa8a1d3950bdeb48cf121ed529d0caf" + url: "https://pub.dev" + source: hosted + version: "0.1.0+2" + screen_brightness_ios: + dependency: transitive + description: + name: screen_brightness_ios + sha256: "99adc3ca5490b8294284aad5fcc87f061ad685050e03cf45d3d018fe398fd9a2" + url: "https://pub.dev" + source: hosted + version: "0.1.0" + screen_brightness_macos: + dependency: transitive + description: + name: screen_brightness_macos + sha256: "64b34e7e3f4900d7687c8e8fb514246845a73ecec05ab53483ed025bd4a899fd" + url: "https://pub.dev" + source: hosted + version: "0.1.0+1" + screen_brightness_platform_interface: + dependency: transitive + description: + name: screen_brightness_platform_interface + sha256: b211d07f0c96637a15fb06f6168617e18030d5d74ad03795dd8547a52717c171 + url: "https://pub.dev" + source: hosted + version: "0.1.0" + screen_brightness_windows: + dependency: transitive + description: + name: screen_brightness_windows + sha256: "9261bf33d0fc2707d8cf16339ce25768100a65e70af0fcabaf032fc12408ba86" url: "https://pub.dev" source: hosted - version: "0.14.0+3" + version: "0.1.3" + scroll_to_index: + dependency: transitive + description: + name: scroll_to_index + sha256: b707546e7500d9f070d63e5acf74fd437ec7eeeb68d3412ef7b0afada0b4f176 + url: "https://pub.dev" + source: hosted + version: "3.0.1" sky_engine: dependency: transitive description: flutter @@ -520,34 +856,82 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709" + url: "https://pub.dev" + source: hosted + version: "2.5.4+6" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "96a698e2bc82bd770a4d6aab00b42396a7c63d9e33513a56945cbccb594c2474" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" + url: "https://pub.dev" + source: hosted + version: "2.4.0" stack_trace: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" state_notifier: dependency: transitive description: name: state_notifier - sha256: "8fe42610f179b843b12371e40db58c9444f8757f8b69d181c97e50787caed289" + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb url: "https://pub.dev" source: hosted - version: "0.7.2+1" + version: "1.0.0" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" string_scanner: dependency: transitive description: @@ -560,10 +944,10 @@ packages: dependency: transitive description: name: synchronized - sha256: "33b31b6beb98100bf9add464a36a8dd03eb10c7a8cf15aeec535e9b054aaf04b" + sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.3.0+3" term_glyph: dependency: transitive description: @@ -576,90 +960,106 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.7.2" typed_data: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" + universal_platform: + dependency: transitive + description: + name: universal_platform + sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + uri_parser: + dependency: transitive + description: + name: uri_parser + sha256: "6543c9fd86d2862fac55d800a43e67c0dcd1a41677cb69c2f8edfe73bbcf1835" + url: "https://pub.dev" + source: hosted + version: "2.0.2" url_launcher: dependency: transitive description: name: url_launcher - sha256: "75f2846facd11168d007529d6cd8fcb2b750186bea046af9711f10b907e1587e" + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" url: "https://pub.dev" source: hosted - version: "6.1.10" + version: "6.3.1" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "3e2f6dfd2c7d9cd123296cab8ef66cfc2c1a13f5845f42c7a0f365690a8a7dd1" + sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193" url: "https://pub.dev" source: hosted - version: "6.0.23" + version: "6.3.14" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: bb328b24d3bccc20bdf1024a0990ac4f869d57663660de9c936fb8c043edefe3 + sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e url: "https://pub.dev" source: hosted - version: "6.0.18" + version: "6.3.1" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "318c42cba924e18180c029be69caf0a1a710191b9ec49bb42b5998fdcccee3cc" + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.2.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "41988b55570df53b3dd2a7fc90c76756a963de6a8c5f8e113330cb35992e2094" + sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.2.1" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: "4eae912628763eb48fc214522e58e942fd16ce195407dbf45638239523c759a6" + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "44d79408ce9f07052095ef1f9a693c258d6373dc3944249374e30eff7219ccb0" + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" url: "https://pub.dev" source: hosted - version: "2.0.14" + version: "2.3.3" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "387e227c4b979034cc52afb11d66b04ed9b288ca1f45beeef39b2ea69e714fa5" + sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.1.3" uuid: dependency: transitive description: name: uuid - sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "4.5.1" vector_math: dependency: transitive description: @@ -668,70 +1068,126 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + visibility_detector: + dependency: transitive + description: + name: visibility_detector + sha256: dd5cc11e13494f432d15939c3aa8ae76844c42b723398643ce9addb88a5ed420 + url: "https://pub.dev" + source: hosted + version: "0.4.0+2" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" + source: hosted + version: "14.2.5" + volume_controller: + dependency: transitive + description: + name: volume_controller + sha256: c71d4c62631305df63b72da79089e078af2659649301807fa746088f365cb48e + url: "https://pub.dev" + source: hosted + version: "2.0.8" + wakelock_plus: + dependency: transitive + description: + name: wakelock_plus + sha256: bf4ee6f17a2fa373ed3753ad0e602b7603f8c75af006d5b9bdade263928c0484 + url: "https://pub.dev" + source: hosted + version: "1.2.8" + wakelock_plus_platform_interface: + dependency: transitive + description: + name: wakelock_plus_platform_interface + sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16" + url: "https://pub.dev" + source: hosted + version: "1.2.1" + web: + dependency: transitive + description: + name: web + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "3.0.1" webview_flutter: dependency: transitive description: name: webview_flutter - sha256: b6cd42db3ced5411f3d01599906156885b18e4188f7065a8a351eb84bee347e0 + sha256: "889a0a678e7c793c308c68739996227c9661590605e70b1f6cf6b9a6634f7aec" url: "https://pub.dev" source: hosted - version: "4.0.6" + version: "4.10.0" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - sha256: c849dcb6bf7367f696869006fb9575c15bdc6a1d624ae13f12de5a147a740b12 + sha256: "285cedfd9441267f6cca8843458620b5fda1af75b04f5818d0441acda5d7df19" url: "https://pub.dev" source: hosted - version: "3.4.2" + version: "4.1.0" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface - sha256: "1939c39e2150fb4d30fd3cc59a891a49fed9935db53007df633ed83581b6117b" + sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.10.0" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview - sha256: ab12479f7a0cf112b9420c36aaf206a1ca47cd60cd42de74a4be2e97a697587b + sha256: b7e92f129482460951d96ef9a46b49db34bd2e1621685de26e9eaafd9674e7eb url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.16.3" win32: dependency: transitive description: name: win32 - sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 + sha256: "84ba388638ed7a8cb3445a320c8273136ab2631cd5f2c57888335504ddab1bc2" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "5.8.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: bd512f03919aac5f1313eb8249f223bacf4927031bf60b02601f81f687689e86 + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "0.2.0+3" + version: "1.1.0" xml: dependency: transitive description: name: xml - sha256: "979ee37d622dec6365e2efa4d906c37470995871fe9ae080d967e192d88286b5" + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 url: "https://pub.dev" source: hosted - version: "6.2.2" + version: "6.5.0" sdks: - dart: ">=2.18.0 <3.0.0" - flutter: ">=3.3.0" + dart: ">=3.5.3 <4.0.0" + flutter: ">=3.24.0" diff --git a/example/pubspec.yaml b/example/pubspec.yaml index 8631553..f6b0b41 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: "^3.5.3" dependencies: flutter: @@ -29,9 +29,11 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 - image_picker: ^0.8.7 + image_picker: ^1.1.2 image: ^4.0.15 path_provider: ^2.0.13 + open_filex: ^4.5.0 + file_picker: ^8.0.7 dev_dependencies: flutter_test: diff --git a/lib/chatwoot_callbacks.dart b/lib/chatwoot_callbacks.dart index 1a4c50e..32e0f86 100644 --- a/lib/chatwoot_callbacks.dart +++ b/lib/chatwoot_callbacks.dart @@ -2,6 +2,7 @@ import 'package:chatwoot_sdk/data/chatwoot_repository.dart'; import 'package:chatwoot_sdk/data/local/entity/chatwoot_message.dart'; import 'package:chatwoot_sdk/data/remote/chatwoot_client_exception.dart'; import 'package:chatwoot_sdk/data/remote/responses/chatwoot_event.dart'; +import 'package:chatwoot_sdk/data/remote/responses/csat_survey_response.dart'; ///Chatwoot callback are specified for each created client instance. Methods are triggered ///when a method satisfying their respective conditions occur. @@ -62,7 +63,10 @@ class ChatwootCallbacks { void Function(List)? onMessagesRetrieved; ///Triggered when an agent resolves the current conversation - void Function()? onConversationResolved; + void Function(String)? onConversationResolved; + + ///Triggered when csat feedbaack is sent + void Function(CsatSurveyFeedbackResponse)? onCsatSurveyResponseRecorded; /// Triggered when any error occurs in chatwoot client's operations with the error /// @@ -84,6 +88,7 @@ class ChatwootCallbacks { this.onConversationIsOnline, this.onConversationIsOffline, this.onConversationResolved, + this.onCsatSurveyResponseRecorded, this.onError, }); } diff --git a/lib/chatwoot_client.dart b/lib/chatwoot_client.dart index 0e12d7a..d45afae 100644 --- a/lib/chatwoot_client.dart +++ b/lib/chatwoot_client.dart @@ -4,10 +4,12 @@ import 'package:chatwoot_sdk/data/local/entity/chatwoot_contact.dart'; import 'package:chatwoot_sdk/data/local/entity/chatwoot_conversation.dart'; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_action_data.dart'; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_new_message_request.dart'; +import 'package:chatwoot_sdk/data/remote/requests/send_csat_survey_request.dart'; import 'package:chatwoot_sdk/di/modules.dart'; import 'package:chatwoot_sdk/chatwoot_parameters.dart'; import 'package:chatwoot_sdk/repository_parameters.dart'; import 'package:riverpod/riverpod.dart'; +import 'package:uuid/uuid.dart'; import 'data/local/local_storage.dart'; @@ -55,8 +57,8 @@ class ChatwootClient { /// [ChatwootMessage] will be returned with the [echoId] on [ChatwootCallbacks.onMessageSent]. If /// message fails to send [ChatwootCallbacks.onError] will be triggered [echoId] as data. Future sendMessage( - {required String content, required String echoId}) async { - final request = ChatwootNewMessageRequest(content: content, echoId: echoId); + {required String content, required String echoId, List? attachment}) async { + final request = ChatwootNewMessageRequest(content: content, echoId: echoId, attachments: attachment ?? []); await _repository.sendMessage(request); } @@ -67,6 +69,11 @@ class ChatwootClient { _repository.sendAction(action); } + ///Send chatwoot csat survey results. + Future sendCsatSurveyResults(String conversationUuid, int rating, String feedback) async { + _repository.sendCsatFeedBack(conversationUuid, SendCsatSurveyRequest(rating: rating, feedbackMessage: feedback)); + } + ///Disposes chatwoot client and cancels all stream subscriptions dispose() { final container = providerContainerMap[_parameters.clientInstanceKey]!; @@ -87,7 +94,8 @@ class ChatwootClient { /// handling chatwoot events. By default persistence is enabled, to disable persistence set [enablePersistence] as false static Future create( {required String baseUrl, - required String inboxIdentifier, + required String inboxIdentifier, + String? userIdentityValidationKey, ChatwootUser? user, bool enablePersistence = true, ChatwootCallbacks? callbacks}) async { @@ -103,10 +111,28 @@ class ChatwootClient { isPersistenceEnabled: enablePersistence, baseUrl: baseUrl, inboxIdentifier: inboxIdentifier, - userIdentifier: user?.identifier); + userIdentityValidationKey: userIdentityValidationKey); + + ChatwootUser? chatUser = user; + if(userIdentityValidationKey != null && user != null ){ + final userIdentifier = user.identifier ?? user.email ?? Uuid().v4(); + final identifierHash = chatwootParams.generateHmacHash(userIdentityValidationKey, userIdentifier); + chatUser = ChatwootUser( + identifier: userIdentifier, + identifierHash: identifierHash, + name: user.name, + email: user.email, + avatarUrl: user.avatarUrl, + customAttributes: user.customAttributes + ); + } final client = - ChatwootClient._(chatwootParams, callbacks: callbacks, user: user); + ChatwootClient._( + chatwootParams, + callbacks: callbacks, + user: chatUser + ); client._init(); diff --git a/lib/chatwoot_parameters.dart b/lib/chatwoot_parameters.dart index d8dc5db..4c914d8 100644 --- a/lib/chatwoot_parameters.dart +++ b/lib/chatwoot_parameters.dart @@ -1,18 +1,35 @@ +import 'dart:convert'; + import 'package:equatable/equatable.dart'; +import 'package:crypto/crypto.dart'; class ChatwootParameters extends Equatable { final bool isPersistenceEnabled; final String baseUrl; final String clientInstanceKey; final String inboxIdentifier; - final String? userIdentifier; + final String? userIdentityValidationKey; ChatwootParameters( {required this.isPersistenceEnabled, required this.baseUrl, required this.inboxIdentifier, required this.clientInstanceKey, - this.userIdentifier}); + this.userIdentityValidationKey}); + + + String generateHmacHash(String key, String userIdentifier) { + // Convert the key and message to bytes + final keyBytes = utf8.encode(key); + final messageBytes = utf8.encode(userIdentifier); + + // Create the HMAC using SHA256 + final hmac = Hmac(sha256, keyBytes); + + final digest = hmac.convert(messageBytes); + + return digest.toString(); + } @override List get props => [ @@ -20,6 +37,6 @@ class ChatwootParameters extends Equatable { baseUrl, clientInstanceKey, inboxIdentifier, - userIdentifier + userIdentityValidationKey ]; } diff --git a/lib/data/chatwoot_repository.dart b/lib/data/chatwoot_repository.dart index ea78561..e05734f 100644 --- a/lib/data/chatwoot_repository.dart +++ b/lib/data/chatwoot_repository.dart @@ -4,12 +4,15 @@ import 'dart:core'; import 'package:chatwoot_sdk/chatwoot_callbacks.dart'; import 'package:chatwoot_sdk/chatwoot_client.dart'; +import 'package:chatwoot_sdk/data/local/entity/chatwoot_message.dart'; import 'package:chatwoot_sdk/data/local/entity/chatwoot_user.dart'; import 'package:chatwoot_sdk/data/local/local_storage.dart'; import 'package:chatwoot_sdk/data/remote/chatwoot_client_exception.dart'; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_action_data.dart'; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_new_message_request.dart'; +import 'package:chatwoot_sdk/data/remote/requests/send_csat_survey_request.dart'; import 'package:chatwoot_sdk/data/remote/responses/chatwoot_event.dart'; +import 'package:chatwoot_sdk/data/remote/responses/csat_survey_response.dart'; import 'package:chatwoot_sdk/data/remote/service/chatwoot_client_service.dart'; import 'package:flutter/material.dart'; @@ -41,6 +44,8 @@ abstract class ChatwootRepository { void sendAction(ChatwootActionType action); + Future sendCsatFeedBack(String conversationUuid, SendCsatSurveyRequest request); + Future clear(); void dispose(); @@ -50,6 +55,8 @@ class ChatwootRepositoryImpl extends ChatwootRepository { bool _isListeningForEvents = false; Timer? _publishPresenceTimer; Timer? _presenceResetTimer; + Timer? _checkPingTimer; + DateTime? _lastPingTime; ChatwootRepositoryImpl( {required ChatwootClientService clientService, @@ -126,11 +133,37 @@ class ChatwootRepositoryImpl extends ChatwootRepository { } } + @override + Future sendCsatFeedBack(String conversationUuid, SendCsatSurveyRequest request) async{ + try { + CsatSurveyFeedbackResponse feedback = await clientService.sendCsatFeedBack(conversationUuid, request); + if(feedback.csatSurveyResponse == null){ + feedback = CsatSurveyFeedbackResponse( + id: feedback.id, + csatSurveyResponse: CsatResponse( + id:feedback.id, + conversationId: feedback.conversationId, + rating: request.rating, + feedbackMessage: request.feedbackMessage + ), + inboxAvatarUrl: feedback.inboxAvatarUrl, + inboxName: feedback.inboxName, + createdAt: feedback.createdAt, + conversationId: feedback.conversationId + ); + } + callbacks.onCsatSurveyResponseRecorded?.call(feedback); + } on ChatwootClientException catch (e) { + callbacks.onError?.call( + ChatwootClientException(e.cause, e.type)); + } + } + /// Connects to chatwoot websocket and starts listening for updates /// /// Received events/messages are pushed through [ChatwootClient.callbacks] @override - void listenForEvents() { + void listenForEvents(){ final token = localStorage.contactDao.getContact()?.pubsubToken; if (token == null) { return; @@ -138,11 +171,16 @@ class ChatwootRepositoryImpl extends ChatwootRepository { clientService.startWebSocketConnection( localStorage.contactDao.getContact()!.pubsubToken ?? ""); - final newSubscription = clientService.connection!.stream.listen((event) { + final newSubscription = clientService.connection!.stream.listen( + (event) async{ ChatwootEvent chatwootEvent = ChatwootEvent.fromJson(jsonDecode(event)); if (chatwootEvent.type == ChatwootEventType.welcome) { callbacks.onWelcome?.call(); } else if (chatwootEvent.type == ChatwootEventType.ping) { + if(_lastPingTime == null){ + _startPingCheck(); + } + _lastPingTime = DateTime.now(); callbacks.onPing?.call(); } else if (chatwootEvent.type == ChatwootEventType.confirm_subscription) { if (!_isListeningForEvents) { @@ -153,7 +191,9 @@ class ChatwootRepositoryImpl extends ChatwootRepository { } else if (chatwootEvent.message?.event == ChatwootEventMessageType.message_created) { print("here comes message: $event"); - final message = chatwootEvent.message!.data!.getMessage(); + + final ChatwootMessage message = chatwootEvent.message!.data!.getMessage(); + localStorage.messagesDao.saveMessage(message); if (message.isMine) { callbacks.onMessageDelivered @@ -165,7 +205,8 @@ class ChatwootRepositoryImpl extends ChatwootRepository { ChatwootEventMessageType.message_updated) { print("here comes the updated message: $event"); - final message = chatwootEvent.message!.data!.getMessage(); + + final ChatwootMessage message = chatwootEvent.message!.data!.getMessage(); localStorage.messagesDao.saveMessage(message); callbacks.onMessageUpdated?.call(message); @@ -181,9 +222,10 @@ class ChatwootRepositoryImpl extends ChatwootRepository { chatwootEvent.message?.data?.id == (localStorage.conversationDao.getConversation()?.id ?? 0)) { //delete conversation result + final conversationUuid = localStorage.conversationDao.getConversation()?.uuid ??''; localStorage.conversationDao.deleteConversation(); localStorage.messagesDao.clear(); - callbacks.onConversationResolved?.call(); + callbacks.onConversationResolved?.call(conversationUuid); } else if (chatwootEvent.message?.event == ChatwootEventMessageType.presence_update) { final presenceStatuses = @@ -200,6 +242,11 @@ class ChatwootRepositoryImpl extends ChatwootRepository { } else { print("chatwoot unknown event: $event"); } + }, + onError: (e){ + //auto reconnect on error + print("chatwoot websocket: $e"); + listenForEvents(); }); _subscriptions.add(newSubscription); } @@ -217,6 +264,7 @@ class ChatwootRepositoryImpl extends ChatwootRepository { callbacks = ChatwootCallbacks(); _presenceResetTimer?.cancel(); _publishPresenceTimer?.cancel(); + _checkPingTimer?.cancel(); _subscriptions.forEach((subs) { subs.cancel(); }); @@ -229,6 +277,23 @@ class ChatwootRepositoryImpl extends ChatwootRepository { localStorage.contactDao.getContact()!.pubsubToken ?? "", action); } + /// Start a timer to check for missed pings + void _startPingCheck() { + _checkPingTimer = Timer.periodic(const Duration(seconds: 1), (timer) { + final now = DateTime.now(); + if (_lastPingTime != null && + now.difference(_lastPingTime!).inSeconds > 30) { + print("No ping received in 30 seconds. Reconnecting..."); + _lastPingTime = null; + _checkPingTimer?.cancel(); + _checkPingTimer = null; + listenForEvents(); + //get any lost messages + getMessages(); + } + }); + } + ///Publishes presence update to websocket channel at a 30 second interval void _publishPresenceUpdates() { sendAction(ChatwootActionType.update_presence); diff --git a/lib/data/local/entity/chatwoot_conversation.dart b/lib/data/local/entity/chatwoot_conversation.dart index e50d05a..46e19c5 100644 --- a/lib/data/local/entity/chatwoot_conversation.dart +++ b/lib/data/local/entity/chatwoot_conversation.dart @@ -29,8 +29,14 @@ class ChatwootConversation extends Equatable { @HiveField(3) final ChatwootContact contact; + ///The uuid ID of the conversation + @JsonKey(name: "uuid") + @HiveField(4) + final String? uuid; + ChatwootConversation( {required this.id, + this.uuid, required this.inboxId, required this.messages, required this.contact}); diff --git a/lib/data/local/entity/chatwoot_message.dart b/lib/data/local/entity/chatwoot_message.dart index 6a679d3..01e6604 100644 --- a/lib/data/local/entity/chatwoot_message.dart +++ b/lib/data/local/entity/chatwoot_message.dart @@ -50,7 +50,7 @@ class ChatwootMessage extends Equatable { ///list of media/doc/file attachment for message @JsonKey() @HiveField(7) - final List? attachments; + final List? attachments; ///The user this message belongs to @JsonKey(name: "sender") @@ -58,7 +58,7 @@ class ChatwootMessage extends Equatable { final ChatwootEventMessageUser? sender; ///checks if message belongs to contact making the request - bool get isMine => messageType != 1; + bool get isMine => messageType != 1 && messageType !=3; ChatwootMessage( {required this.id, @@ -90,6 +90,50 @@ class ChatwootMessage extends Equatable { ]; } +@JsonSerializable(explicitToJson: true) +@HiveType(typeId: CHATWOOT_MESSAGE_ATTACHMENT_HIVE_TYPE_ID) +class ChatwootMessageAttachment { + @JsonKey(name: "id") + @HiveField(1) + int? id; + @JsonKey(name: "message_id") + @HiveField(2) + int? messageId; + @JsonKey(name: "file_type") + @HiveField(3) + String? fileType; + @JsonKey(name: "account_id") + @HiveField(4) + int? accountId; + @JsonKey(name: "data_url") + @HiveField(5) + String? dataUrl; + + @JsonKey(name: "thumb_url") + @HiveField(6) + String? thumbUrl; + @JsonKey(name: "file_size") + @HiveField(7) + int? fileSize; + + ChatwootMessageAttachment( + {this.id, + this.messageId, + this.fileType, + this.accountId, + this.dataUrl, + this.thumbUrl, + this.fileSize}); + + + + factory ChatwootMessageAttachment.fromJson(Map json) => + _$ChatwootMessageAttachmentFromJson(json); + + Map toJson() => _$ChatwootMessageAttachmentToJson(this); +} + + int idFromJson(value) { if (value is String) { return int.tryParse(value) ?? 0; diff --git a/lib/data/local/local_storage.dart b/lib/data/local/local_storage.dart index 4e9fe47..270507f 100644 --- a/lib/data/local/local_storage.dart +++ b/lib/data/local/local_storage.dart @@ -10,11 +10,12 @@ import 'entity/chatwoot_contact.dart'; import 'entity/chatwoot_message.dart'; import 'entity/chatwoot_user.dart'; -const CHATWOOT_CONTACT_HIVE_TYPE_ID = 0; -const CHATWOOT_CONVERSATION_HIVE_TYPE_ID = 1; -const CHATWOOT_MESSAGE_HIVE_TYPE_ID = 2; -const CHATWOOT_USER_HIVE_TYPE_ID = 3; -const CHATWOOT_EVENT_USER_HIVE_TYPE_ID = 4; +const CHATWOOT_CONTACT_HIVE_TYPE_ID = 110; +const CHATWOOT_CONVERSATION_HIVE_TYPE_ID = 111; +const CHATWOOT_MESSAGE_HIVE_TYPE_ID = 112; +const CHATWOOT_USER_HIVE_TYPE_ID = 113; +const CHATWOOT_EVENT_USER_HIVE_TYPE_ID = 114; +const CHATWOOT_MESSAGE_ATTACHMENT_HIVE_TYPE_ID = 115; class LocalStorage { ChatwootUserDao userDao; @@ -31,12 +32,12 @@ class LocalStorage { static Future openDB({void Function()? onInitializeHive}) async { if (onInitializeHive == null) { - await Hive.initFlutter(); + await Hive.initFlutter("chatwoot"); if (!Hive.isAdapterRegistered(CHATWOOT_CONTACT_HIVE_TYPE_ID)) { - Hive..registerAdapter(ChatwootContactAdapter()); + await Hive..registerAdapter(ChatwootContactAdapter()); } if (!Hive.isAdapterRegistered(CHATWOOT_CONVERSATION_HIVE_TYPE_ID)) { - Hive..registerAdapter(ChatwootConversationAdapter()); + await Hive..registerAdapter(ChatwootConversationAdapter()); } if (!Hive.isAdapterRegistered(CHATWOOT_MESSAGE_HIVE_TYPE_ID)) { Hive..registerAdapter(ChatwootMessageAdapter()); @@ -47,6 +48,9 @@ class LocalStorage { if (!Hive.isAdapterRegistered(CHATWOOT_USER_HIVE_TYPE_ID)) { Hive..registerAdapter(ChatwootUserAdapter()); } + if (!Hive.isAdapterRegistered(CHATWOOT_MESSAGE_ATTACHMENT_HIVE_TYPE_ID)) { + Hive..registerAdapter(ChatwootMessageAttachmentAdapter()); + } } else { onInitializeHive(); } diff --git a/lib/data/remote/chatwoot_client_exception.dart b/lib/data/remote/chatwoot_client_exception.dart index 0d0e50a..9a1109a 100644 --- a/lib/data/remote/chatwoot_client_exception.dart +++ b/lib/data/remote/chatwoot_client_exception.dart @@ -17,5 +17,7 @@ enum ChatwootClientExceptionType { GET_CONTACT_FAILED, GET_CONVERSATION_FAILED, UPDATE_CONTACT_FAILED, - UPDATE_MESSAGE_FAILED + UPDATE_MESSAGE_FAILED, + GET_CSAT_FEEDBACK, + SEND_CSAT_FEEDBACK } diff --git a/lib/data/remote/requests/chatwoot_new_message_request.dart b/lib/data/remote/requests/chatwoot_new_message_request.dart index d24531d..e165452 100644 --- a/lib/data/remote/requests/chatwoot_new_message_request.dart +++ b/lib/data/remote/requests/chatwoot_new_message_request.dart @@ -1,22 +1,16 @@ +import 'package:chatwoot_sdk/ui/chatwoot_chat_page.dart'; import 'package:equatable/equatable.dart'; -import 'package:json_annotation/json_annotation.dart'; -part 'chatwoot_new_message_request.g.dart'; -@JsonSerializable(explicitToJson: true) + class ChatwootNewMessageRequest extends Equatable { - @JsonKey() final String content; - @JsonKey(name: "echo_id") final String echoId; + final List attachments; - ChatwootNewMessageRequest({required this.content, required this.echoId}); + ChatwootNewMessageRequest({required this.content, required this.echoId, this.attachments = const[]}); @override List get props => [content, echoId]; - factory ChatwootNewMessageRequest.fromJson(Map json) => - _$ChatwootNewMessageRequestFromJson(json); - - Map toJson() => _$ChatwootNewMessageRequestToJson(this); } diff --git a/lib/data/remote/requests/send_csat_survey_request.dart b/lib/data/remote/requests/send_csat_survey_request.dart new file mode 100644 index 0000000..9fb82ec --- /dev/null +++ b/lib/data/remote/requests/send_csat_survey_request.dart @@ -0,0 +1,28 @@ +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; + + +part 'send_csat_survey_request.g.dart'; + +@JsonSerializable(explicitToJson: true) +class SendCsatSurveyRequest extends Equatable{ + @JsonKey(name: "rating") + final int rating; + + @JsonKey(name: "feedback_message") + final String feedbackMessage; + + + SendCsatSurveyRequest({required this.rating, required this.feedbackMessage}); + + factory SendCsatSurveyRequest.fromJson(Map json) => + _$SendCsatSurveyRequestFromJson(json); + + Map toJson() => _$SendCsatSurveyRequestToJson(this); + + @override + List get props => [ + this.rating, + this.feedbackMessage + ]; +} diff --git a/lib/data/remote/responses/csat_survey_response.dart b/lib/data/remote/responses/csat_survey_response.dart new file mode 100644 index 0000000..53f32ac --- /dev/null +++ b/lib/data/remote/responses/csat_survey_response.dart @@ -0,0 +1,107 @@ + + +import 'package:equatable/equatable.dart'; +import 'package:json_annotation/json_annotation.dart'; +part 'csat_survey_response.g.dart'; + +@JsonSerializable(explicitToJson: true) +class CsatSurveyFeedbackResponse extends Equatable{ + @JsonKey() + final int? id; + @JsonKey(name: "csat_survey_response") + final CsatResponse? csatSurveyResponse; + @JsonKey(name: "inbox_avatar_url") + final String? inboxAvatarUrl; + @JsonKey(name: "inbox_name") + final String? inboxName; + @JsonKey(name: "locale") + final String? locale; + @JsonKey(name: "consversation_id") + final int? conversationId; + @JsonKey(name: "created_at") + final String? createdAt; + + CsatSurveyFeedbackResponse( + {this.id, + this.csatSurveyResponse, + this.inboxAvatarUrl, + this.inboxName, + this.locale, + this.conversationId, + this.createdAt}); + + + + factory CsatSurveyFeedbackResponse.fromJson(Map json) => + _$CsatSurveyFeedbackResponseFromJson(json); + + Map toJson() => _$CsatSurveyFeedbackResponseToJson(this); + + @override + List get props => [ + this.id, + this.csatSurveyResponse, + this.inboxAvatarUrl, + this.inboxName, + this.conversationId, + this.locale, + this.createdAt + ]; +} + +@JsonSerializable(explicitToJson: true) +class CsatResponse extends Equatable{ + @JsonKey(name: "id") + final int? id; + @JsonKey(name: "account_id") + final int? accountId; + @JsonKey(name: "conversation_id") + final int? conversationId; + @JsonKey(name: "message_id") + final int? messageId; + @JsonKey(name: "rating") + final int? rating; + @JsonKey(name: "feedback_message") + final String? feedbackMessage; + @JsonKey(name: "contact_id") + final int? contactId; + @JsonKey(name: "assigned_agent_id") + final int? assignedAgentId; + @JsonKey(name: "created_at") + final String? createdAt; + @JsonKey(name: "updated_at") + final String? updatedAt; + + CsatResponse( + {this.id, + this.accountId, + this.conversationId, + this.messageId, + this.rating, + this.feedbackMessage, + this.contactId, + this.assignedAgentId, + this.createdAt, + this.updatedAt}); + + + + factory CsatResponse.fromJson(Map json) => + _$CsatResponseFromJson(json); + + Map toJson() => _$CsatResponseToJson(this); + + @override + List get props => [ + this.id, + this.accountId, + this.conversationId, + this.messageId, + this.rating, + this.feedbackMessage, + this.contactId, + this.assignedAgentId, + this.createdAt, + this.updatedAt + ]; +} \ No newline at end of file diff --git a/lib/data/remote/service/chatwoot_client_api_interceptor.dart b/lib/data/remote/service/chatwoot_client_api_interceptor.dart index 06de475..717d657 100644 --- a/lib/data/remote/service/chatwoot_client_api_interceptor.dart +++ b/lib/data/remote/service/chatwoot_client_api_interceptor.dart @@ -1,3 +1,4 @@ +import 'package:chatwoot_sdk/chatwoot_sdk.dart'; import 'package:chatwoot_sdk/data/local/entity/chatwoot_contact.dart'; import 'package:chatwoot_sdk/data/local/entity/chatwoot_conversation.dart'; import 'package:chatwoot_sdk/data/local/local_storage.dart'; @@ -28,6 +29,7 @@ class ChatwootClientApiInterceptor extends Interceptor { RequestOptions options, RequestInterceptorHandler handler) async { await requestLock.synchronized(() async { RequestOptions newOptions = options; + ChatwootUser? user = _localStorage.userDao.getUser(); ChatwootContact? contact = _localStorage.contactDao.getContact(); ChatwootConversation? conversation = _localStorage.conversationDao.getConversation(); @@ -35,7 +37,7 @@ class ChatwootClientApiInterceptor extends Interceptor { if (contact == null) { // create new contact from user if no token found contact = await _authService.createNewContact( - _inboxIdentifier, _localStorage.userDao.getUser()); + _inboxIdentifier, user); conversation = await _authService.createNewConversation( _inboxIdentifier, contact.contactIdentifier!); await _localStorage.conversationDao.saveConversation(conversation); @@ -57,6 +59,12 @@ class ChatwootClientApiInterceptor extends Interceptor { INTERCEPTOR_CONVERSATION_IDENTIFIER_PLACEHOLDER, "${conversation.id}"); + if(user?.identifierHash != null){ + //if user identifier hash has been set attach it requests + newOptions.queryParameters["identifier_hash"] = user!.identifierHash; + newOptions.queryParameters["identifier"] = user.identifier; + } + handler.next(newOptions); }); } diff --git a/lib/data/remote/service/chatwoot_client_auth_service.dart b/lib/data/remote/service/chatwoot_client_auth_service.dart index e809b5c..438c3bb 100644 --- a/lib/data/remote/service/chatwoot_client_auth_service.dart +++ b/lib/data/remote/service/chatwoot_client_auth_service.dart @@ -44,9 +44,9 @@ class ChatwootClientAuthServiceImpl extends ChatwootClientAuthService { createResponse.statusMessage ?? "unknown error", ChatwootClientExceptionType.CREATE_CONTACT_FAILED); } - } on DioError catch (e) { + } on DioException catch (e) { throw ChatwootClientException( - e.message, ChatwootClientExceptionType.CREATE_CONTACT_FAILED); + e.message ?? '', ChatwootClientExceptionType.CREATE_CONTACT_FAILED); } } @@ -67,9 +67,9 @@ class ChatwootClientAuthServiceImpl extends ChatwootClientAuthService { createResponse.statusMessage ?? "unknown error", ChatwootClientExceptionType.CREATE_CONVERSATION_FAILED); } - } on DioError catch (e) { + } on DioException catch (e) { throw ChatwootClientException( - e.message, ChatwootClientExceptionType.CREATE_CONVERSATION_FAILED); + e.message ?? '', ChatwootClientExceptionType.CREATE_CONVERSATION_FAILED); } } } diff --git a/lib/data/remote/service/chatwoot_client_service.dart b/lib/data/remote/service/chatwoot_client_service.dart index 3a7a965..0032b90 100644 --- a/lib/data/remote/service/chatwoot_client_service.dart +++ b/lib/data/remote/service/chatwoot_client_service.dart @@ -8,9 +8,13 @@ import 'package:chatwoot_sdk/data/remote/chatwoot_client_exception.dart'; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_action.dart'; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_action_data.dart'; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_new_message_request.dart'; +import 'package:chatwoot_sdk/data/remote/requests/send_csat_survey_request.dart'; +import 'package:chatwoot_sdk/data/remote/responses/csat_survey_response.dart'; import 'package:chatwoot_sdk/data/remote/service/chatwoot_client_api_interceptor.dart'; import 'package:dio/dio.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; +import 'package:mime/mime.dart'; + /// Service for handling chatwoot api calls /// See [ChatwootClientServiceImpl] @@ -18,8 +22,9 @@ abstract class ChatwootClientService { final String _baseUrl; WebSocketChannel? connection; final Dio _dio; + final Dio _udio; - ChatwootClientService(this._baseUrl, this._dio); + ChatwootClientService(this._baseUrl, this._dio, this._udio); Future updateContact(update); @@ -31,6 +36,10 @@ abstract class ChatwootClientService { Future updateMessage(String messageIdentifier, update); + Future sendCsatFeedBack(String conversationUuid, SendCsatSurveyRequest request); + + Future getCsatFeedback(String conversationUuid); + Future> getAllMessages(); void startWebSocketConnection(String contactPubsubToken, @@ -40,27 +49,41 @@ abstract class ChatwootClientService { } class ChatwootClientServiceImpl extends ChatwootClientService { - ChatwootClientServiceImpl(String baseUrl, {required Dio dio}) - : super(baseUrl, dio); + ChatwootClientServiceImpl(String baseUrl, {required Dio dio, required Dio uDio}) + : super(baseUrl, dio, uDio); ///Sends message to chatwoot inbox @override Future createMessage( ChatwootNewMessageRequest request) async { try { + + FormData formData = FormData.fromMap({ + 'echo_id': request.echoId, + 'content': request.content, + }); + for(final attachment in request.attachments){ + formData.files.add(MapEntry('attachments[]',await MultipartFile.fromBytes( + attachment.bytes, + filename: attachment.name, + contentType: DioMediaType.parse(lookupMimeType(attachment.name) ?? 'application/octet-stream') + ))); + } final createResponse = await _dio.post( "/public/api/v1/inboxes/${ChatwootClientApiInterceptor.INTERCEPTOR_INBOX_IDENTIFIER_PLACEHOLDER}/contacts/${ChatwootClientApiInterceptor.INTERCEPTOR_CONTACT_IDENTIFIER_PLACEHOLDER}/conversations/${ChatwootClientApiInterceptor.INTERCEPTOR_CONVERSATION_IDENTIFIER_PLACEHOLDER}/messages", - data: request.toJson()); + data: formData); if ((createResponse.statusCode ?? 0).isBetween(199, 300)) { - return ChatwootMessage.fromJson(createResponse.data); + final message = ChatwootMessage.fromJson(createResponse.data); + + return message; } else { throw ChatwootClientException( createResponse.statusMessage ?? "unknown error", ChatwootClientExceptionType.SEND_MESSAGE_FAILED); } - } on DioError catch (e) { + } on DioException catch (e) { throw ChatwootClientException( - e.message, ChatwootClientExceptionType.SEND_MESSAGE_FAILED); + e.message ?? '', ChatwootClientExceptionType.SEND_MESSAGE_FAILED); } } @@ -71,17 +94,18 @@ class ChatwootClientServiceImpl extends ChatwootClientService { final createResponse = await _dio.get( "/public/api/v1/inboxes/${ChatwootClientApiInterceptor.INTERCEPTOR_INBOX_IDENTIFIER_PLACEHOLDER}/contacts/${ChatwootClientApiInterceptor.INTERCEPTOR_CONTACT_IDENTIFIER_PLACEHOLDER}/conversations/${ChatwootClientApiInterceptor.INTERCEPTOR_CONVERSATION_IDENTIFIER_PLACEHOLDER}/messages"); if ((createResponse.statusCode ?? 0).isBetween(199, 300)) { - return (createResponse.data as List) + final messages = (createResponse.data as List) .map(((json) => ChatwootMessage.fromJson(json))) .toList(); + return messages; } else { throw ChatwootClientException( createResponse.statusMessage ?? "unknown error", ChatwootClientExceptionType.GET_MESSAGES_FAILED); } - } on DioError catch (e) { + } on DioException catch (e) { throw ChatwootClientException( - e.message, ChatwootClientExceptionType.GET_MESSAGES_FAILED); + e.message ?? '', ChatwootClientExceptionType.GET_MESSAGES_FAILED); } } @@ -89,18 +113,18 @@ class ChatwootClientServiceImpl extends ChatwootClientService { @override Future getContact() async { try { - final createResponse = await _dio.get( + final getResponse = await _dio.get( "/public/api/v1/inboxes/${ChatwootClientApiInterceptor.INTERCEPTOR_INBOX_IDENTIFIER_PLACEHOLDER}/contacts/${ChatwootClientApiInterceptor.INTERCEPTOR_CONTACT_IDENTIFIER_PLACEHOLDER}"); - if ((createResponse.statusCode ?? 0).isBetween(199, 300)) { - return ChatwootContact.fromJson(createResponse.data); + if ((getResponse.statusCode ?? 0).isBetween(199, 300)) { + return ChatwootContact.fromJson(getResponse.data); } else { throw ChatwootClientException( - createResponse.statusMessage ?? "unknown error", + getResponse.statusMessage ?? "unknown error", ChatwootClientExceptionType.GET_CONTACT_FAILED); } - } on DioError catch (e) { + } on DioException catch (e) { throw ChatwootClientException( - e.message, ChatwootClientExceptionType.GET_CONTACT_FAILED); + e.message ?? '', ChatwootClientExceptionType.GET_CONTACT_FAILED); } } @@ -119,9 +143,9 @@ class ChatwootClientServiceImpl extends ChatwootClientService { createResponse.statusMessage ?? "unknown error", ChatwootClientExceptionType.GET_CONVERSATION_FAILED); } - } on DioError catch (e) { + } on DioException catch (e) { throw ChatwootClientException( - e.message, ChatwootClientExceptionType.GET_CONVERSATION_FAILED); + e.message ?? '', ChatwootClientExceptionType.GET_CONVERSATION_FAILED); } } @@ -139,9 +163,9 @@ class ChatwootClientServiceImpl extends ChatwootClientService { updateResponse.statusMessage ?? "unknown error", ChatwootClientExceptionType.UPDATE_CONTACT_FAILED); } - } on DioError catch (e) { + } on DioException catch (e) { throw ChatwootClientException( - e.message, ChatwootClientExceptionType.UPDATE_CONTACT_FAILED); + e.message ?? '', ChatwootClientExceptionType.UPDATE_CONTACT_FAILED); } } @@ -154,15 +178,16 @@ class ChatwootClientServiceImpl extends ChatwootClientService { "/public/api/v1/inboxes/${ChatwootClientApiInterceptor.INTERCEPTOR_INBOX_IDENTIFIER_PLACEHOLDER}/contacts/${ChatwootClientApiInterceptor.INTERCEPTOR_CONTACT_IDENTIFIER_PLACEHOLDER}/conversations/${ChatwootClientApiInterceptor.INTERCEPTOR_CONVERSATION_IDENTIFIER_PLACEHOLDER}/messages/$messageIdentifier", data: update); if ((updateResponse.statusCode ?? 0).isBetween(199, 300)) { - return ChatwootMessage.fromJson(updateResponse.data); + final message = ChatwootMessage.fromJson(updateResponse.data); + return message; } else { throw ChatwootClientException( updateResponse.statusMessage ?? "unknown error", ChatwootClientExceptionType.UPDATE_MESSAGE_FAILED); } - } on DioError catch (e) { + } on DioException catch (e) { throw ChatwootClientException( - e.message, ChatwootClientExceptionType.UPDATE_MESSAGE_FAILED); + e.message ?? '', ChatwootClientExceptionType.UPDATE_MESSAGE_FAILED); } } @@ -198,4 +223,47 @@ class ChatwootClientServiceImpl extends ChatwootClientService { } connection?.sink.add(jsonEncode(action.toJson())); } + + @override + Future getCsatFeedback(String conversationUuid) async{ + try { + final response = await _dio.get( + "/public/api/v1/csat_survey/$conversationUuid"); + if ((response.statusCode ?? 0).isBetween(199, 300)) { + return response.data != null ? CsatSurveyFeedbackResponse.fromJson(response.data) : null; + } else { + throw ChatwootClientException( + response.statusMessage ?? "unknown error", + ChatwootClientExceptionType.GET_CSAT_FEEDBACK); + } + } on DioException catch (e) { + throw ChatwootClientException( + e.message ?? '', ChatwootClientExceptionType.GET_CSAT_FEEDBACK); + } + } + + @override + Future sendCsatFeedBack(String conversationUuid, SendCsatSurveyRequest request) async{ + try { + final response = await _udio.put( + "/public/api/v1/csat_survey/$conversationUuid", + data: { + "message":{ + "submitted_values":{ + "csat_survey_response": request.toJson() + } + } + }); + if ((response.statusCode ?? 0).isBetween(199, 300)) { + return CsatSurveyFeedbackResponse.fromJson(response.data); + } else { + throw ChatwootClientException( + response.statusMessage ?? "unknown error", + ChatwootClientExceptionType.SEND_CSAT_FEEDBACK); + } + } on DioException catch (e) { + throw ChatwootClientException( + e.message ?? '', ChatwootClientExceptionType.SEND_CSAT_FEEDBACK); + } + } } diff --git a/lib/di/modules.dart b/lib/di/modules.dart index 2d3873e..2197f4b 100644 --- a/lib/di/modules.dart +++ b/lib/di/modules.dart @@ -53,8 +53,9 @@ final chatwootClientAuthServiceProvider = ///Provides instance of chatwoot client api service [ChatwootClientService]. final chatwootClientServiceProvider = Provider.family((ref, params) { - final authenticatedDio = ref.read(authenticatedDioProvider(params)); - return ChatwootClientServiceImpl(params.baseUrl, dio: authenticatedDio); + final authenticatedDio = ref.read(authenticatedDioProvider(params)); + final unauthenticatedDio = ref.read(unauthenticatedDioProvider(params)); + return ChatwootClientServiceImpl(params.baseUrl, dio: authenticatedDio, uDio: unauthenticatedDio); }); ///Provides hive box to store relations between chatwoot client instance and contact object, diff --git a/lib/ui/chat_input.dart b/lib/ui/chat_input.dart new file mode 100644 index 0000000..67fd800 --- /dev/null +++ b/lib/ui/chat_input.dart @@ -0,0 +1,116 @@ +import 'package:chatwoot_sdk/ui/chatwoot_chat_theme.dart'; +import 'package:chatwoot_sdk/ui/chatwoot_l10n.dart'; +import 'package:flutter/material.dart'; + +class ChatInput extends StatefulWidget { + + final ChatwootChatTheme theme; + final ChatwootL10n l10n; + final void Function(String) onMessageSent; + final void Function() onAttachmentPressed; + const ChatInput({Key? key, required this.theme, required this.l10n, required this.onMessageSent, required this.onAttachmentPressed}) : super(key: key); + + @override + _ChatInputState createState() => _ChatInputState(); +} + +class _ChatInputState extends State { + final FocusNode _focusNode = FocusNode(); + bool _isFocused = false; + String text = ''; + late TextEditingController _controller; + + @override + void initState() { + super.initState(); + this._controller = TextEditingController(); + _focusNode.addListener(() { + setState(() { + _isFocused = _focusNode.hasFocus; + }); + }); + } + + @override + void dispose() { + _focusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: widget.theme.inputPadding, + child: AnimatedContainer( + duration: Duration(milliseconds: 300), + decoration: BoxDecoration( + borderRadius: widget.theme.inputBorderRadius, + border: Border.all( + color: _isFocused ? widget.theme.primaryColor : Colors.grey.shade300, + width: 1.0, + ), + boxShadow: _isFocused + ? [ + BoxShadow( + color: widget.theme.primaryColor.withOpacity(0.2), + blurRadius: 6.0, + spreadRadius: 2.0, + ), + ] + : [], + color: Colors.white, + ), + child: Row( + children: [ + // Text Field + Expanded( + child: TextField( + controller: _controller, + focusNode: _focusNode, + decoration: InputDecoration( + hintText: widget.l10n.inputPlaceholder, + border: InputBorder.none, + contentPadding: widget.theme.inputPadding, + ), + onSubmitted: (submittedText){ + widget.onMessageSent(submittedText); + }, + onChanged: (newText){ + setState(() { + text = newText; + }); + }, + ), + ), + // Attachment Icon + IconButton( + onPressed: () { + widget.onAttachmentPressed(); + }, + icon: const Icon( + Icons.attach_file, + color: Colors.grey, + ), + ), + // Emoji Icon + IconButton( + onPressed: _submit, + icon: Icon( + Icons.send_rounded, + color: text.isNotEmpty ? widget.theme.primaryColor:Colors.grey, + ), + ), + ], + ), + ), + ); + } + + _submit(){ + if(text.isNotEmpty){ + widget.onMessageSent(text); + text = ""; + _controller.text = ""; + } + } +} diff --git a/lib/ui/chatwoot_chat_dialog.dart b/lib/ui/chatwoot_chat_dialog.dart index 03f8fad..60b0d18 100644 --- a/lib/ui/chatwoot_chat_dialog.dart +++ b/lib/ui/chatwoot_chat_dialog.dart @@ -2,19 +2,17 @@ import 'package:chatwoot_sdk/data/local/entity/chatwoot_user.dart'; import 'package:chatwoot_sdk/ui/chatwoot_chat_theme.dart'; import 'package:chatwoot_sdk/ui/chatwoot_l10n.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_chat_ui/flutter_chat_ui.dart'; -import 'package:intl/intl.dart'; import 'chatwoot_chat_page.dart'; ///Chatwoot chat modal widget /// {@category FlutterClientSdk} -@deprecated class ChatwootChatDialog extends StatefulWidget { static show( BuildContext context, { required String baseUrl, required String inboxIdentifier, + String? userIdentityValidationKey, bool enablePersistence = true, required String title, ChatwootUser? user, @@ -22,8 +20,8 @@ class ChatwootChatDialog extends StatefulWidget { Color? secondaryColor, Color? backgroundColor, ChatwootL10n? l10n, - DateFormat? timeFormat, - DateFormat? dateFormat, + Future Function()? onAttachmentPressed, + Future Function(String)? openFile }) { showDialog( context: context, @@ -31,6 +29,7 @@ class ChatwootChatDialog extends StatefulWidget { return ChatwootChatDialog( baseUrl: baseUrl, inboxIdentifier: inboxIdentifier, + userIdentityValidationKey: userIdentityValidationKey, title: title, user: user, enablePersistence: enablePersistence, @@ -38,8 +37,8 @@ class ChatwootChatDialog extends StatefulWidget { secondaryColor: secondaryColor, backgroundColor: backgroundColor, l10n: l10n, - timeFormat: timeFormat, - dateFormat: dateFormat, + onAttachmentPressed: onAttachmentPressed, + openFile: openFile, ); }); } @@ -52,6 +51,12 @@ class ChatwootChatDialog extends StatefulWidget { /// For more details see https://www.chatwoot.com/docs/product/channels/api/client-apis final String inboxIdentifier; + + ///Key used to generate user identifier hash + /// + /// For more details see https://www.chatwoot.com/docs/product/channels/api/client-apis + final String? userIdentityValidationKey; + /// Enables persistence of chatwoot client instance's contact, conversation and messages to disk /// for convenience. /// @@ -77,16 +82,15 @@ class ChatwootChatDialog extends StatefulWidget { /// See [ChatwootL10n] final ChatwootL10n? l10n; - /// See [Chat.timeFormat] - final DateFormat? timeFormat; + final Future Function()? onAttachmentPressed; - /// See [Chat.dateFormat] - final DateFormat? dateFormat; + final Future Function(String)? openFile; const ChatwootChatDialog({ Key? key, required this.baseUrl, required this.inboxIdentifier, + this.userIdentityValidationKey, this.enablePersistence = true, required this.title, this.user, @@ -94,15 +98,14 @@ class ChatwootChatDialog extends StatefulWidget { this.secondaryColor, this.backgroundColor, this.l10n, - this.timeFormat, - this.dateFormat, + this.onAttachmentPressed, + this.openFile }) : super(key: key); @override _ChatwootChatDialogState createState() => _ChatwootChatDialogState(); } -@deprecated class _ChatwootChatDialogState extends State { late String status; late ChatwootL10n localizedStrings; @@ -185,10 +188,9 @@ class _ChatwootChatDialogState extends State { child: ChatwootChat( baseUrl: widget.baseUrl, inboxIdentifier: widget.inboxIdentifier, + userIdentityValidationKey: widget.userIdentityValidationKey, user: widget.user, enablePersistence: widget.enablePersistence, - timeFormat: widget.timeFormat, - dateFormat: widget.dateFormat, theme: ChatwootChatTheme( primaryColor: widget.primaryColor ?? CHATWOOT_COLOR_PRIMARY, secondaryColor: widget.secondaryColor ?? Colors.white, @@ -220,6 +222,8 @@ class _ChatwootChatDialogState extends State { status = localizedStrings.typingText; }); }, + onAttachmentPressed: widget.onAttachmentPressed, + openFile: widget.openFile, ), ), ], diff --git a/lib/ui/chatwoot_chat_page.dart b/lib/ui/chatwoot_chat_page.dart index 19ed99a..10a1cad 100644 --- a/lib/ui/chatwoot_chat_page.dart +++ b/lib/ui/chatwoot_chat_page.dart @@ -1,19 +1,43 @@ +import 'dart:async'; +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:cached_network_image/cached_network_image.dart'; import 'package:chatwoot_sdk/chatwoot_callbacks.dart'; import 'package:chatwoot_sdk/chatwoot_client.dart'; import 'package:chatwoot_sdk/data/local/entity/chatwoot_message.dart'; import 'package:chatwoot_sdk/data/local/entity/chatwoot_user.dart'; import 'package:chatwoot_sdk/data/remote/chatwoot_client_exception.dart'; +import 'package:chatwoot_sdk/ui/chat_input.dart'; import 'package:chatwoot_sdk/ui/chatwoot_chat_theme.dart'; import 'package:chatwoot_sdk/ui/chatwoot_l10n.dart'; +import 'package:chatwoot_sdk/ui/link_preview.dart'; +import 'package:chatwoot_sdk/ui/media_widgets.dart'; +import 'package:chatwoot_sdk/ui/video_preview.dart'; +import 'package:easy_image_viewer/easy_image_viewer.dart'; import 'package:flutter/material.dart'; import 'package:flutter_chat_types/flutter_chat_types.dart' as types; import 'package:flutter_chat_ui/flutter_chat_ui.dart'; import 'package:intl/intl.dart'; +import 'package:media_kit/media_kit.dart'; +import 'package:media_kit_video/media_kit_video.dart'; +import 'package:mime/mime.dart'; +import 'package:path_provider/path_provider.dart'; import 'package:uuid/uuid.dart'; +import 'package:http/http.dart' as http; + + +class FileAttachment{ + final Uint8List bytes; + final String name; + final String path; + + FileAttachment({required this.bytes, required this.name, required this.path}); +} + ///Chatwoot chat widget /// {@category FlutterClientSdk} -@deprecated class ChatwootChat extends StatefulWidget { /// Specifies a custom app bar for chatwoot page widget final PreferredSizeWidget? appBar; @@ -26,6 +50,12 @@ class ChatwootChat extends StatefulWidget { /// For more details see https://www.chatwoot.com/docs/product/channels/api/client-apis final String inboxIdentifier; + + ///Key used to generate user identifier hash + /// + /// For more details see https://www.chatwoot.com/docs/product/channels/api/client-apis + final String? userIdentityValidationKey; + /// Enables persistence of chatwoot client instance's contact, conversation and messages to disk /// for convenience. /// @@ -43,16 +73,13 @@ class ChatwootChat extends StatefulWidget { final double? onEndReachedThreshold; /// See [Message.onMessageLongPress] - final void Function(types.Message)? onMessageLongPress; + final void Function(BuildContext context, types.Message)? onMessageLongPress; /// See [Message.onMessageTap] - final void Function(types.Message)? onMessageTap; + final void Function(BuildContext context, types.Message)? onMessageTap; /// See [Input.onSendPressed] - final void Function(types.PartialText)? onSendPressed; - - /// See [Input.onTextChanged] - final void Function(String)? onTextChanged; + final void Function(String)? onSendPressed; /// Show avatars for received messages. final bool showUserAvatars; @@ -60,17 +87,11 @@ class ChatwootChat extends StatefulWidget { /// Show user names for received messages. final bool showUserNames; - final ChatwootChatTheme theme; + final ChatwootChatTheme? theme; /// See [ChatwootL10n] final ChatwootL10n l10n; - /// See [Chat.timeFormat] - final DateFormat? timeFormat; - - /// See [Chat.dateFormat] - final DateFormat? dateFormat; - ///See [ChatwootCallbacks.onWelcome] final void Function()? onWelcome; @@ -110,6 +131,10 @@ class ChatwootChat extends StatefulWidget { ///See [ChatwootCallbacks.onMessagesRetrieved] final void Function(List)? onMessagesRetrieved; + final Future Function()? onAttachmentPressed; + + final Future Function(String)? openFile; + ///See [ChatwootCallbacks.onError] final void Function(ChatwootClientException)? onError; @@ -120,6 +145,7 @@ class ChatwootChat extends StatefulWidget { {Key? key, required this.baseUrl, required this.inboxIdentifier, + this.userIdentityValidationKey, this.enablePersistence = true, this.user, this.appBar, @@ -128,13 +154,10 @@ class ChatwootChat extends StatefulWidget { this.onMessageLongPress, this.onMessageTap, this.onSendPressed, - this.onTextChanged, this.showUserAvatars = true, this.showUserNames = true, - this.theme = const ChatwootChatTheme(), + this.theme, this.l10n = const ChatwootL10n(), - this.timeFormat, - this.dateFormat, this.onWelcome, this.onPing, this.onConfirmedSubscription, @@ -148,6 +171,8 @@ class ChatwootChat extends StatefulWidget { this.onConversationStoppedTyping, this.onConversationIsOnline, this.onConversationIsOffline, + this.onAttachmentPressed, + this.openFile, this.onError, this.isPresentedInDialog = false}) : super(key: key); @@ -156,23 +181,27 @@ class ChatwootChat extends StatefulWidget { _ChatwootChatState createState() => _ChatwootChatState(); } -@deprecated -class _ChatwootChatState extends State { +class _ChatwootChatState extends State with WidgetsBindingObserver{ /// List _messages = []; late String status; final idGen = Uuid(); - late final _user; + late final types.User _user; ChatwootClient? chatwootClient; - late final chatwootCallbacks; + late final ChatwootCallbacks chatwootCallbacks; + late VideoController controller; + late VideoPreviewLoader videoPreviewLoader; @override void initState() { super.initState(); - + MediaKit.ensureInitialized(); + controller = VideoController(Player()); + videoPreviewLoader = VideoPreviewLoader(controller: controller); + videoPreviewLoader.listen(_handleVideoPreviewLoaded); if (widget.user == null) { _user = types.User(id: idGen.v4()); } else { @@ -193,16 +222,23 @@ class _ChatwootChatState extends State { onConfirmedSubscription: () { widget.onConfirmedSubscription?.call(); }, + onConversationIsOnline: (){ + widget.onConversationIsOnline?.call(); + }, + onConversationIsOffline: (){ + widget.onConversationIsOffline?.call(); + }, onConversationStartedTyping: () { - widget.onConversationStoppedTyping?.call(); + widget.onConversationStartedTyping?.call(); }, onConversationStoppedTyping: () { - widget.onConversationStartedTyping?.call(); + widget.onConversationStoppedTyping?.call(); }, onPersistedMessagesRetrieved: (persistedMessages) { if (widget.enablePersistence) { setState(() { _messages = persistedMessages + .where((m)=>m.contentType != "input_csat") .map((message) => _chatwootMessageToTextMessage(message)) .toList(); }); @@ -215,10 +251,16 @@ class _ChatwootChatState extends State { } setState(() { final chatMessages = messages - .map((message) => _chatwootMessageToTextMessage(message)) + .where((m)=>m.contentType != "input_csat") + .map((message){ + return _chatwootMessageToTextMessage(message); + }) .toList(); - final mergedMessages = - [..._messages, ...chatMessages].toSet().toList(); + final mergedMessages = mergeLists( + list1: chatMessages, list2: _messages, + getItemKey: (item)=>item.id, + merger: (item1, item2)=>item1 + ); final now = DateTime.now().millisecondsSinceEpoch; mergedMessages.sort((a, b) { return (b.createdAt ?? now).compareTo(a.createdAt ?? now); @@ -228,12 +270,14 @@ class _ChatwootChatState extends State { widget.onMessagesRetrieved?.call(messages); }, onMessageReceived: (chatwootMessage) { + if(chatwootMessage.contentType == "input_csat"){ + //csat message is handled manually + return; + } _addMessage(_chatwootMessageToTextMessage(chatwootMessage)); widget.onMessageReceived?.call(chatwootMessage); }, onMessageDelivered: (chatwootMessage, echoId) { - _handleMessageSent( - _chatwootMessageToTextMessage(chatwootMessage, echoId: echoId)); widget.onMessageDelivered?.call(chatwootMessage); }, onMessageUpdated: (chatwootMessage) { @@ -242,25 +286,40 @@ class _ChatwootChatState extends State { widget.onMessageUpdated?.call(chatwootMessage); }, onMessageSent: (chatwootMessage, echoId) { - final textMessage = types.TextMessage( - id: echoId, - author: _user, - text: chatwootMessage.content ?? "", - status: types.Status.delivered); + types.Message textMessage = _chatwootMessageToTextMessage(chatwootMessage, echoId: echoId, messageStatus: types.Status.sent); _handleMessageSent(textMessage); widget.onMessageSent?.call(chatwootMessage); }, - onConversationResolved: () { + onConversationResolved: (conversationUuid) { + final resolvedMessage = types.TextMessage( - id: idGen.v4(), + id: "resolved", text: widget.l10n.conversationResolvedMessage, author: types.User( - id: idGen.v4(), - firstName: "Bot", - imageUrl: - "https://d2cbg94ubxgsnp.cloudfront.net/Pictures/480x270//9/9/3/512993_shutterstock_715962319converted_920340.png"), + id: idGen.v4(),), status: types.Status.delivered); _addMessage(resolvedMessage); + final csatMessage = types.CustomMessage( + id: "csat", + author: types.User( + id: idGen.v4(),), + metadata: { + "conversationUuid": conversationUuid + }, + status: types.Status.delivered); + _addMessage(csatMessage); + }, + onCsatSurveyResponseRecorded: (feedback){ + + final resolvedMessage = types.CustomMessage( + id: "csat", + author: types.User( + id: idGen.v4()), + metadata: { + "feedback": feedback + }, + status: types.Status.delivered); + _handleMessageUpdated(resolvedMessage); }, onError: (error) { if (error.type == ChatwootClientExceptionType.SEND_MESSAGE_FAILED) { @@ -274,6 +333,7 @@ class _ChatwootChatState extends State { ChatwootClient.create( baseUrl: widget.baseUrl, inboxIdentifier: widget.inboxIdentifier, + userIdentityValidationKey: widget.userIdentityValidationKey, user: widget.user, enablePersistence: widget.enablePersistence, callbacks: chatwootCallbacks) @@ -289,8 +349,40 @@ class _ChatwootChatState extends State { }); } - types.TextMessage _chatwootMessageToTextMessage(ChatwootMessage message, - {String? echoId}) { + List mergeLists({ + required List list1, + required List list2, + required K Function(T item) getItemKey, + required T Function(T item1, T item2) merger, + }) { + final Map map = {}; + + for (final item in list2) { + final key = getItemKey(item); + map[key] = item; + } + + final List result = []; + + // Merge items from list1 with list2 or add them directly if no match + for (final item in list1) { + final key = getItemKey(item); + if (map.containsKey(key)) { + result.add(merger(item, map[key]!)); + map.remove(key); // Remove matched item to prevent duplicates + } else { + result.add(item); + } + } + + // Add remaining items from list2 that were not matched + result.addAll(map.values); + + return result; + } + + + types.Message _chatwootMessageToTextMessage(ChatwootMessage message, {String? echoId, types.Status? messageStatus}) { String? avatarUrl = message.sender?.avatarUrl ?? message.sender?.thumbnail; //Sets avatar url to null if its a gravatar not found url @@ -298,16 +390,81 @@ class _ChatwootChatState extends State { if (avatarUrl?.contains("?d=404") ?? false) { avatarUrl = null; } + final nameSplit = (message.sender?.name??"C ").split(" "); + final firstName = nameSplit.first; + final lastName = nameSplit.last; + types.User author = message.isMine + ? _user + : types.User( + id: message.sender?.id.toString() ?? idGen.v4(), + firstName: firstName, + lastName: lastName, + imageUrl: avatarUrl, + ); + final metadata = { + "sentAt": DateFormat("MMM d, hh:mm a").format(DateTime.parse(message.createdAt)) + }; + if(message.attachments?.first.dataUrl?.isNotEmpty ?? false){ + Uri uri = Uri.parse(message.attachments!.first.dataUrl!); + + // Get the last path segment from the URL (after the last '/') + String fileName = uri.pathSegments.isNotEmpty + ? uri.pathSegments.last + : ''; + if(message.attachments!.first.fileType == "image"){ + return types.ImageMessage( + id: echoId ?? message.id.toString(), + author: author, + name: fileName, + metadata: metadata, + size: message.attachments!.first.fileSize ?? 0, + uri: message.attachments!.first.dataUrl!, + status: messageStatus ?? types.Status.seen, + createdAt: DateTime.parse(message.createdAt).millisecondsSinceEpoch); + }else if(message.attachments!.first.fileType == "video"){ + final videoMessage = types.VideoMessage( + id: echoId ?? message.id.toString(), + author: author, + height: 500, + width: 500, + name: fileName, + metadata: metadata, + size: message.attachments!.first.fileSize ?? 0, + uri: message.attachments!.first.dataUrl!, + status: messageStatus ?? types.Status.seen, + createdAt: DateTime.parse(message.createdAt).millisecondsSinceEpoch); + + videoPreviewLoader.getPreview(jobId: videoMessage.id, uri: videoMessage.uri); + return videoMessage; + }else if(message.attachments!.first.fileType == "audio"){ + return types.AudioMessage( + id: echoId ?? message.id.toString(), + author: author, + duration:Duration.zero, + name: fileName, + metadata: metadata, + size: message.attachments!.first.fileSize ?? 0, + uri: message.attachments!.first.dataUrl!, + status: messageStatus ?? types.Status.seen, + createdAt: DateTime.parse(message.createdAt).millisecondsSinceEpoch); + }else{ + return types.FileMessage( + id: echoId ?? message.id.toString(), + author: author, + name: fileName, + metadata: metadata, + size: message.attachments!.first.fileSize ?? 0, + uri: message.attachments!.first.dataUrl!, + status: messageStatus ?? types.Status.seen, + createdAt: DateTime.parse(message.createdAt).millisecondsSinceEpoch); + } + } + return types.TextMessage( id: echoId ?? message.id.toString(), - author: message.isMine - ? _user - : types.User( - id: message.sender?.id.toString() ?? idGen.v4(), - firstName: message.sender?.name, - imageUrl: avatarUrl, - ), + author: author, text: message.content ?? "", + metadata: metadata, status: types.Status.seen, createdAt: DateTime.parse(message.createdAt).millisecondsSinceEpoch); } @@ -333,19 +490,14 @@ class _ChatwootChatState extends State { }); } - void _handleMessageTap(types.Message message) async { - if (message.status == types.Status.error && message is types.TextMessage) { - _handleResendMessage(message); - } - widget.onMessageTap?.call(message); - } - void _handlePreviewDataFetched( types.TextMessage message, types.PreviewData previewData, ) { final index = _messages.indexWhere((element) => element.id == message.id); - final updatedMessage = _messages[index].copyWith(previewData: previewData); + final updatedMetaData = _messages[index].metadata ?? Map(); + updatedMetaData["previewData"] = previewData; + final updatedMessage = _messages[index].copyWith(metadata: updatedMetaData); WidgetsBinding.instance.addPostFrameCallback((_) { setState(() { @@ -354,15 +506,49 @@ class _ChatwootChatState extends State { }); } + + void _handleMessageTap(BuildContext _, types.Message message) async { + + if (message.status == types.Status.error && message is types.TextMessage) { + _handleResendMessage(message); + return; + } + if ((message is types.FileMessage) && widget.openFile != null) { + var localPath = message.uri; + + if (localPath.startsWith('http')) { + + final documentsDir = (await getApplicationDocumentsDirectory()).path; + final cacheLocalPath = '$documentsDir/${message.name}'; + + if (!File(cacheLocalPath).existsSync()) { + + final client = http.Client(); + final request = await client.get(Uri.parse(localPath)); + final bytes = request.bodyBytes; + final file = File(cacheLocalPath); + await file.writeAsBytes(bytes); + } + localPath = cacheLocalPath; + + } + widget.onMessageTap?.call(context, message); + + await widget.openFile?.call(localPath); + } + + if(message is types.ImageMessage){ + final imageProvider = CachedNetworkImageProvider(message.uri); + showImageViewer(context, imageProvider); + } + } + + void _handleMessageSent( types.Message message, ) { final index = _messages.indexWhere((element) => element.id == message.id); - if (_messages[index].status == types.Status.seen) { - return; - } - WidgetsBinding.instance.addPostFrameCallback((_) { setState(() { _messages[index] = message; @@ -371,10 +557,12 @@ class _ChatwootChatState extends State { } void _handleMessageUpdated( - types.Message message, - ) { + types.Message message, + ) { final index = _messages.indexWhere((element) => element.id == message.id); - + if(index == -1){ + return; + } WidgetsBinding.instance.addPostFrameCallback((_) { setState(() { _messages[index] = message; @@ -382,12 +570,28 @@ class _ChatwootChatState extends State { }); } - void _handleSendPressed(types.PartialText message) { + void _handleVideoPreviewLoaded( + VideoMessagePreviewResult result + ) { + + final index = _messages.indexWhere((element) => element.id == result.jobId); + if(index > -1){ + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + _messages[index] = _messages[index].copyWith(metadata: { + "preview": result.preview + }); + }); + }); + } + } + + void _handleSendPressed(String message) { final textMessage = types.TextMessage( author: _user, createdAt: DateTime.now().millisecondsSinceEpoch, id: const Uuid().v4(), - text: message.text, + text: message, status: types.Status.sending); _addMessage(textMessage); @@ -397,66 +601,222 @@ class _ChatwootChatState extends State { widget.onSendPressed?.call(message); } + void _handleAttachmentPressed() async{ + final attachment = await widget.onAttachmentPressed?.call(); + if(attachment != null){ + types.Message message; + if(lookupMimeType(attachment.name)?.startsWith("image") ?? false){ + message = types.ImageMessage( + author: _user, + createdAt: DateTime.now().millisecondsSinceEpoch, + id: const Uuid().v4(), + name: attachment.name, + uri: attachment.path, + size: attachment.bytes.length, + status: types.Status.sending); + }else if(lookupMimeType(attachment.name)?.startsWith("video") ?? false){ + + message = types.VideoMessage( + author: _user, + createdAt: DateTime.now().millisecondsSinceEpoch, + id: const Uuid().v4(), + name: attachment.name, + uri: attachment.path, + size: attachment.bytes.length, + status: types.Status.sending); + + videoPreviewLoader.getPreview(jobId: message.id, uri: attachment.path); + }else if(lookupMimeType(attachment.name)?.startsWith("audio") ?? false){ + message = types.AudioMessage( + author: _user, + createdAt: DateTime.now().millisecondsSinceEpoch, + id: const Uuid().v4(), + name: attachment.name, + uri: attachment.path, + size: attachment.bytes.length, + duration: Duration.zero, + status: types.Status.sending); + }else{ + message = types.FileMessage( + author: _user, + createdAt: DateTime.now().millisecondsSinceEpoch, + id: const Uuid().v4(), + name: attachment.name, + uri: attachment.path, + size: attachment.bytes.length, + status: types.Status.sending); + } + + _addMessage(message); + + chatwootClient! + .sendMessage(content: attachment.name, echoId: message.id, attachment: [attachment]); + } + } + + @override Widget build(BuildContext context) { final horizontalPadding = widget.isPresentedInDialog ? 8.0 : 16.0; + final theme = widget.theme ?? ChatwootChatTheme(); return Scaffold( appBar: widget.appBar, - backgroundColor: widget.theme.backgroundColor, - body: Column( + backgroundColor: widget.theme?.backgroundColor, + body: Stack( children: [ - Flexible( - child: Padding( - padding: EdgeInsets.only( - left: horizontalPadding, right: horizontalPadding), - child: Chat( - messages: _messages, - onMessageTap: _handleMessageTap, - onPreviewDataFetched: _handlePreviewDataFetched, - onSendPressed: _handleSendPressed, - user: _user, - onEndReached: widget.onEndReached, - onEndReachedThreshold: widget.onEndReachedThreshold, - onMessageLongPress: widget.onMessageLongPress, - onTextChanged: widget.onTextChanged, - showUserAvatars: widget.showUserAvatars, - showUserNames: widget.showUserNames, - timeFormat: widget.timeFormat ?? DateFormat.Hm(), - dateFormat: widget.timeFormat ?? DateFormat("EEEE MMMM d"), - theme: widget.theme, - l10n: widget.l10n, + //offscreen video player used to fetch first frame of video messages. media_kit screenshot doesn't work without + //controller tied to the video widget + IgnorePointer(child:Opacity(opacity: 0,child: Video(controller: controller, fit: BoxFit.contain,))), + //actual chat + Column( + children: [ + Flexible( + child: Padding( + padding: EdgeInsets.only( + left: horizontalPadding, right: horizontalPadding), + child: Chat( + messages: _messages, + onMessageTap: _handleMessageTap, + onPreviewDataFetched: (_,__){}, + onSendPressed: (_){}, + user: _user, + onEndReached: widget.onEndReached, + onEndReachedThreshold: widget.onEndReachedThreshold, + onMessageLongPress: widget.onMessageLongPress, + onAttachmentPressed: (){}, + showUserAvatars: widget.showUserAvatars, + showUserNames: widget.showUserNames, + theme: theme, + disableImageGallery: true, + dateHeaderBuilder: (_){ + return SizedBox(); + }, + customBottomWidget: ChatInput( + theme: theme, + l10n: widget.l10n, + onMessageSent: _handleSendPressed, + onAttachmentPressed: _handleAttachmentPressed), + textMessageBuilder: (message, {messageWidth=0, showName=true}){ + return TextChatMessage( + theme: theme, + message: message, + isMine: message.author.id == _user.id, + maxWidth: messageWidth, + onPreviewFetched: _handlePreviewDataFetched + ); + }, + videoMessageBuilder: (message, {messageWidth=0}){ + return VideoChatMessage( + theme: theme, + message: message, + isMine: message.author.id == _user.id, + maxWidth: messageWidth + ); + }, + audioMessageBuilder: (message, {messageWidth=0}){ + return AudioChatMessage( + theme: theme, + message: message, + isMine: message.author.id == _user.id, + ); + }, + avatarBuilder: (user){ + return Row( + children: [ + ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(15)), + child: CachedNetworkImage( + imageUrl: user.imageUrl ?? '', + width: 30, + height: 30, + fit:BoxFit.cover, + errorWidget: (_,__, ___){ + String name = "${user.firstName} ${user.lastName}"; + List words = name.trim().split(RegExp(r'\s+')); + String initials = words.map((word) => word[0].toUpperCase()).join(); + return PlaceholderCircle( + text: initials, + textColor: theme.primaryColor, + ); + }, + ), + ), + SizedBox(width: 5,) + ], + ); + }, + customMessageBuilder: (message, {messageWidth=0}){ + if(message.metadata?["feedback"] != null){ + return RecordedCsatChatMessage( + theme: theme, + l10n: widget.l10n, + message: message, + maxWidth: messageWidth, + ); + } + return CSATChatMessage( + theme: theme, + l10n: widget.l10n, + message: message, + maxWidth: messageWidth, + sendCsatResults: (rating, feedback){ + chatwootClient?.sendCsatSurveyResults(message.metadata!['conversationUuid'], rating, feedback); + }, + ); + }, + l10n: widget.l10n, + ), + ), ), - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Image.asset( - "assets/logo_grey.png", - package: 'chatwoot_sdk', - width: 15, - height: 15, + Padding( + padding: const EdgeInsets.all(8.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Image.asset( + "assets/logo_grey.png", + package: 'chatwoot_sdk', + width: 15, + height: 15, + ), + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Text( + "Powered by Chatwoot", + style: TextStyle(color: Colors.black45, fontSize: 12), + ), + ) + ], ), - Padding( - padding: const EdgeInsets.only(left: 8.0), - child: Text( - "Powered by Chatwoot", - style: TextStyle(color: Colors.black45, fontSize: 12), - ), - ) - ], - ), - ) + ) + ], + ), ], ), ); } + @override + void didChangeAppLifecycleState(AppLifecycleState state) { + if (state == AppLifecycleState.resumed) { + chatwootClient?.loadMessages(); + } + } + @override void dispose() { super.dispose(); chatwootClient?.dispose(); + videoPreviewLoader.dispose(); + LinkMetadata.dispose(); + controller.player.dispose(); + _messages.forEach((m){ + if(m is types.VideoMessage){ + final controller= m.metadata?["controller"] as VideoController?; + controller?.player.dispose(); + } + }); } } + + diff --git a/lib/ui/chatwoot_chat_theme.dart b/lib/ui/chatwoot_chat_theme.dart index a8d5c24..5086982 100644 --- a/lib/ui/chatwoot_chat_theme.dart +++ b/lib/ui/chatwoot_chat_theme.dart @@ -1,9 +1,11 @@ + import 'package:flutter/material.dart'; import 'package:flutter_chat_ui/flutter_chat_ui.dart'; const CHATWOOT_COLOR_PRIMARY = Color(0xff1f93ff); const CHATWOOT_BG_COLOR = Color(0xfff4f6fb); const CHATWOOT_AVATAR_COLORS = [CHATWOOT_COLOR_PRIMARY]; +const PRIMARY = CHATWOOT_COLOR_PRIMARY; /// Default chatwoot chat theme which extends [ChatTheme] @immutable @@ -22,16 +24,16 @@ class ChatwootChatTheme extends ChatTheme { Widget? deliveredIcon, Widget? documentIcon, TextStyle emptyChatPlaceholderTextStyle = const TextStyle( - color: NEUTRAL_2, + color: Colors.black54, fontSize: 16, fontWeight: FontWeight.w500, height: 1.5, ), - Color errorColor = ERROR, + Color errorColor = Colors.red, Widget? errorIcon, Color inputBackgroundColor = Colors.white, BorderRadius inputBorderRadius = const BorderRadius.all( - Radius.circular(10), + Radius.circular(6), ), Color inputTextColor = Colors.black87, TextStyle inputTextStyle = const TextStyle( @@ -48,20 +50,20 @@ class ChatwootChatTheme extends ChatTheme { height: 1.5, ), TextStyle receivedMessageCaptionTextStyle = const TextStyle( - color: NEUTRAL_2, + color: Colors.black54, fontSize: 12, fontWeight: FontWeight.w500, height: 1.333, ), Color receivedMessageDocumentIconColor = PRIMARY, TextStyle receivedMessageLinkDescriptionTextStyle = const TextStyle( - color: NEUTRAL_0, + color: primary, fontSize: 14, fontWeight: FontWeight.w400, height: 1.428, ), TextStyle receivedMessageLinkTitleTextStyle = const TextStyle( - color: NEUTRAL_0, + color: primary, fontSize: 16, fontWeight: FontWeight.w800, height: 1.375, @@ -77,27 +79,27 @@ class ChatwootChatTheme extends ChatTheme { height: 1.5, ), TextStyle sentMessageCaptionTextStyle = const TextStyle( - color: NEUTRAL_7_WITH_OPACITY, + color: Colors.white, fontSize: 12, fontWeight: FontWeight.w500, height: 1.333, ), - Color sentMessageDocumentIconColor = NEUTRAL_7, + Color sentMessageDocumentIconColor = Colors.white, TextStyle sentMessageLinkDescriptionTextStyle = const TextStyle( - color: NEUTRAL_7, + color: Colors.black54, fontSize: 14, fontWeight: FontWeight.w400, height: 1.428, ), TextStyle sentMessageLinkTitleTextStyle = const TextStyle( - color: NEUTRAL_7, + color: Colors.black87, fontSize: 16, fontWeight: FontWeight.w800, height: 1.375, ), List userAvatarNameColors = CHATWOOT_AVATAR_COLORS, TextStyle userAvatarTextStyle = const TextStyle( - color: NEUTRAL_7, + color: primary, fontSize: 12, fontWeight: FontWeight.w800, height: 1.333, @@ -108,6 +110,37 @@ class ChatwootChatTheme extends ChatTheme { fontWeight: FontWeight.w800, height: 1.333, ), + EdgeInsets? attachmentButtonMargin, + EdgeInsets dateDividerMargin = const EdgeInsets.all(8), + Color inputSurfaceTintColor = Colors.blueAccent, + double inputElevation= 0, + EdgeInsets inputMargin = const EdgeInsets.all(8), + EdgeInsets inputPadding= const EdgeInsets.all(8), + double messageInsetsHorizontal= 8, + double messageInsetsVertical= 8, + double messageMaxWidth= 500, + TextStyle receivedEmojiMessageTextStyle= const TextStyle(), + EdgeInsets sendButtonMargin= const EdgeInsets.all(8), + TextStyle sentEmojiMessageTextStyle= const TextStyle(), + EdgeInsets statusIconPadding= const EdgeInsets.all(8), + SystemMessageTheme systemMessageTheme= const SystemMessageTheme( + margin: const EdgeInsets.all(8), + textStyle: const TextStyle() + ), + TypingIndicatorTheme typingIndicatorTheme= const TypingIndicatorTheme( + animatedCirclesColor: primary, + animatedCircleSize: 8, + bubbleBorder: const BorderRadius.all(const Radius.circular(8)), + bubbleColor: Colors.white, + countAvatarColor: primary, + countTextColor: Colors.black87, + multipleUserTextStyle: const TextStyle() + ), + UnreadHeaderTheme unreadHeaderTheme= const UnreadHeaderTheme( + color: CHATWOOT_COLOR_PRIMARY, + textStyle: const TextStyle() + ), + Color userAvatarImageBackgroundColor= Colors.white, }) : super( attachmentButtonIcon: attachmentButtonIcon, backgroundColor: backgroundColor, @@ -142,5 +175,23 @@ class ChatwootChatTheme extends ChatTheme { userAvatarNameColors: userAvatarNameColors, userAvatarTextStyle: userAvatarTextStyle, userNameTextStyle: userNameTextStyle, + attachmentButtonMargin: attachmentButtonMargin, + dateDividerMargin: dateDividerMargin, + inputSurfaceTintColor: inputSurfaceTintColor, + inputElevation: inputElevation, + inputMargin: inputMargin, + inputPadding: inputPadding, + inputTextDecoration: const InputDecoration(), + messageInsetsHorizontal: messageInsetsHorizontal, + messageInsetsVertical: messageInsetsVertical, + messageMaxWidth: messageMaxWidth, + receivedEmojiMessageTextStyle: receivedEmojiMessageTextStyle, + sendButtonMargin: sendButtonMargin, + sentEmojiMessageTextStyle: sentEmojiMessageTextStyle, + statusIconPadding: statusIconPadding, + systemMessageTheme: systemMessageTheme, + typingIndicatorTheme: typingIndicatorTheme, + unreadHeaderTheme: unreadHeaderTheme, + userAvatarImageBackgroundColor: userAvatarImageBackgroundColor, ); } diff --git a/lib/ui/chatwoot_l10n.dart b/lib/ui/chatwoot_l10n.dart index ed6d187..ffc6867 100644 --- a/lib/ui/chatwoot_l10n.dart +++ b/lib/ui/chatwoot_l10n.dart @@ -29,6 +29,39 @@ class ChatwootL10n extends ChatL10n { /// Message when agent resolves conversation final String conversationResolvedMessage; + final String and; + + final String isTyping; + + final String others; + + /// Unread messages + final String unreadMessagesLabel; + + /// Action text for csat form + final String csatInquiryQuestion; + + /// CSAT option rating: 1 + final String csatVeryUnsatisfied; + + /// CSAT option rating: 2 + final String csatUnsatisfied; + + /// CSAT option rating: 3 + final String csatOK; + + /// CSAT option rating: 4 + final String csatSatisfied; + + /// CSAT option rating: 5 + final String csatVerySatisfied; + + /// CSAT form feed back text placholder + final String csatFeedbackPlaceholder; + + /// Message displayed to user after completing csat survey + final String csatThankYouMessage; + /// Creates a new chatwoot l10n const ChatwootL10n( {this.attachmentButtonAccessibilityLabel = "", @@ -39,13 +72,30 @@ class ChatwootL10n extends ChatL10n { this.typingText = "typing...", this.inputPlaceholder = "Type your message", this.sendButtonAccessibilityLabel = "Send Message", - this.conversationResolvedMessage = - "Your ticket has been marked as resolved"}) + this.conversationResolvedMessage = "Your ticket has been marked as resolved", + this.and = "and", + this.isTyping = "is typing...", + this.others = "others", + this.unreadMessagesLabel = "Your ticket has been marked as resolved", + this.csatInquiryQuestion = "Rate your experience", + this.csatVeryUnsatisfied = "Very poor", + this.csatUnsatisfied = "Poor", + this.csatOK = "Okay", + this.csatSatisfied = "Good", + this.csatVerySatisfied = "Excellent", + this.csatFeedbackPlaceholder = "Leave your feedback (optional)...", + this.csatThankYouMessage = "Thank you for your feedback" + }) : super( attachmentButtonAccessibilityLabel: attachmentButtonAccessibilityLabel, emptyChatPlaceholder: emptyChatPlaceholder, fileButtonAccessibilityLabel: fileButtonAccessibilityLabel, inputPlaceholder: inputPlaceholder, - sendButtonAccessibilityLabel: sendButtonAccessibilityLabel); + sendButtonAccessibilityLabel: sendButtonAccessibilityLabel, + and: and, + isTyping: isTyping, + others: others, + unreadMessagesLabel: unreadMessagesLabel + ); } diff --git a/lib/ui/link_preview.dart b/lib/ui/link_preview.dart new file mode 100644 index 0000000..17c9f5d --- /dev/null +++ b/lib/ui/link_preview.dart @@ -0,0 +1,199 @@ +import 'dart:convert'; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:http/http.dart' as http; +import 'package:html/parser.dart'; +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; + + +class LinkMetadata { + + + static final _previews = { + + }; + final String? title; + final String? description; + final String? imageUrl; + + LinkMetadata({this.title, this.description, this.imageUrl}); + + + + static Future fetchLinkMetadata(String url) async { + final cachedMetadata = _previews[url]; + if(cachedMetadata!=null){ + return cachedMetadata; + } + try { + final response = await http.get(Uri.parse(url)); + if (response.statusCode == 200) { + final document = parse(utf8.decode(response.bodyBytes)); + + // Extract metadata from meta tags + String title = document + .querySelector('meta[property="og:title"]') + ?.attributes['content'] ?? + document.querySelector('title')?.text ?? ''; + + if(title.isEmpty){ + //if no title is set fallback to url + title = url; + } + + final description = document + .querySelector('meta[property="og:description"]') + ?.attributes['content'] ?? + document.querySelector('meta[name="description"]')?.attributes['content']; + + final imageUrl = document.head?.querySelector('meta[name="og:image"]') + ?.attributes['content'] ?? document.head?.querySelector('meta[property="og:image"]') + ?.attributes['content']; + final metadata = LinkMetadata( + title: title, + description: description, + imageUrl: imageUrl, + ); + _previews[url] = metadata; + return metadata; + } + } catch (e) { + print("Error fetching metadata: $e"); + } + return null; + } + + static dispose(){ + _previews.clear(); + } + +} + + + +class LinkPreview extends StatefulWidget { + final String url; + + const LinkPreview({Key? key, required this.url}) : super(key: key); + + @override + _LinkPreviewState createState() => _LinkPreviewState(); +} + +class _LinkPreviewState extends State { + Future? _metadataFuture; + + @override + void initState() { + super.initState(); + _metadataFuture = LinkMetadata.fetchLinkMetadata(widget.url); + } + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: _metadataFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return Container( + padding: EdgeInsets.all(16.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12.0), + ), + child: Row( + children: [ + CircularProgressIndicator(color: Colors.black,), + SizedBox(width: 16.0), + Text('Loading...'), + ], + ), + ); + } + + if (snapshot.hasError || snapshot.data == null) { + return InkWell( + onTap: (){ + launchUrl(Uri.parse(widget.url)); + }, + child: Container( + padding: EdgeInsets.all(16.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12.0), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 8, + offset: Offset(0, 4), + ), + ], + ), + child: Text( + widget.url, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ), + ); + } + + final metadata = snapshot.data!; + return Container( + padding: EdgeInsets.all(16.0), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12.0), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.2), + blurRadius: 8, + offset: Offset(0, 4), + ), + ], + ), + child: InkWell( + onTap: (){ + launchUrl(Uri.parse(widget.url)); + }, + child: Column( + children: [ + if (metadata.imageUrl != null) + ClipRRect( + borderRadius: BorderRadius.circular(8.0), + child: CachedNetworkImage( + imageUrl: metadata.imageUrl!, + height: 150, + width: 250, + fit: BoxFit.cover, + ), + ), + if (metadata.imageUrl != null) SizedBox(height: 16.0), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + metadata.title ?? '', + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + SizedBox(height: 8.0), + Text( + metadata.description ?? '', + style: TextStyle( + color: Colors.grey[600], + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ], + ), + ), + ); + }, + ); + } +} diff --git a/lib/ui/media_widgets.dart b/lib/ui/media_widgets.dart new file mode 100644 index 0000000..f6bd6f0 --- /dev/null +++ b/lib/ui/media_widgets.dart @@ -0,0 +1,598 @@ + +import 'package:chatwoot_sdk/data/remote/responses/csat_survey_response.dart'; +import 'package:chatwoot_sdk/ui/chatwoot_chat_theme.dart'; +import 'package:chatwoot_sdk/ui/chatwoot_l10n.dart'; +import 'package:chatwoot_sdk/ui/link_preview.dart'; +import 'package:chatwoot_sdk/ui/video_preview.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:media_kit/media_kit.dart'; +import 'package:media_kit_video/media_kit_video.dart'; + +import 'package:flutter_chat_types/flutter_chat_types.dart' as types; +import 'package:url_launcher/url_launcher.dart'; + +class FullScreenMediaViewer extends StatefulWidget { + final String uri; + const FullScreenMediaViewer({Key? key, required this.uri}) : super(key: key); + + @override + State createState() => _FullScreenMediaViewerState(); +} + +class _FullScreenMediaViewerState extends State { + late final Player player; + late VideoController _controller; + + @override + void initState() { + super.initState(); + player = Player(); + _controller = VideoController(player); + player.open(Media(widget.uri)); // Replace with your media URL + } + + @override + void dispose() { + player.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.black, + body: Stack( + children: [ + Center( + child: Video( + controller: _controller, + fit: BoxFit.contain, + ), + ), + Positioned( + top: 20.0, + right: 20.0, + child: IconButton( + icon: const Icon(Icons.close, color: Colors.white, size: 30.0), + onPressed: () { + Navigator.pop(context); + }, + ), + ), + ], + ), + ); + } +} + + +class AudioChatMessage extends StatefulWidget { + final ChatwootChatTheme theme; + final types.AudioMessage message; + final bool isMine; + const AudioChatMessage({Key? key, required this.message, required this.isMine, required this.theme}) : super(key: key); + + @override + _AudioChatMessageState createState() => _AudioChatMessageState(); +} + +class _AudioChatMessageState extends State { + + + void playAudio() { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => FullScreenMediaViewer(uri: widget.message.uri,)), + ); + } + + @override + Widget build(BuildContext context) { + final activeColor = widget.isMine ? widget.theme.sentMessageBodyTextStyle.color : widget.theme.receivedMessageBodyTextStyle.color; + return Container( + padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + // Play Button + GestureDetector( + onTap: playAudio, + child: IconButton( + icon: Icon( + Icons.play_arrow, + color: activeColor, + size: 40, + ), + onPressed: playAudio, + ), + ), + const SizedBox(width: 10.0), + // Progress Slider + Expanded( + child: Slider( + value: 0, + max: 0, + activeColor: activeColor, + inactiveColor: Colors.grey.shade400, + onChanged: (value) {}, + ), + ), + // Timer + ], + ), + ); + } +} + + +class VideoChatMessage extends StatefulWidget { + final ChatwootChatTheme theme; + final types.VideoMessage message; + final bool isMine; + final int maxWidth; + const VideoChatMessage({Key? key, required this.theme, required this.message, required this.isMine, required this.maxWidth}) : super(key: key); + + @override + _VideoChatMessageState createState() => _VideoChatMessageState(); +} + +class _VideoChatMessageState extends State { + final double height = 300; + void playVideo() { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => FullScreenMediaViewer(uri: widget.message.uri,)), + ); + } + + VideoMessagePreview? get previewData =>widget.message.metadata?["preview"]; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: playVideo, + child: Container( + height: height, + width: widget.maxWidth.toDouble(), + child: Stack( + children: [ + if(previewData != null) + RawImage(image: previewData?.firstFrame?.image, fit: BoxFit.cover, width: widget.maxWidth.toDouble(), height: height,), + Positioned.fill( + child: Center( + child: Container( + height: 60.0, + width: 60.0, + decoration: const BoxDecoration( + color: Colors.black54, + shape: BoxShape.circle, + ), + child: const Icon( + Icons.play_arrow, + color: Colors.white, + size: 40.0, + ), + ), + ), + ), + ], + ), + ), + ); + } +} + + + +class TextChatMessage extends StatefulWidget { + final ChatwootChatTheme theme; + final types.TextMessage message; + final bool isMine; + final int maxWidth; + final void Function(types.TextMessage,types.PreviewData) onPreviewFetched; + const TextChatMessage({ + Key? key, + required this.theme, + required this.message, + required this.isMine, + required this.maxWidth, + required this.onPreviewFetched + }) : super(key: key); + + @override + _TextChatMessageState createState() => _TextChatMessageState(); +} + +class _TextChatMessageState extends State { + + @override + Widget build(BuildContext context) { + print("link: $messageLink"); + final styleSheet = MarkdownStyleSheet.fromTheme(Theme.of(context)); + final textColor = widget.isMine ? widget.theme.sentMessageBodyTextStyle.color: widget.theme.receivedMessageBodyTextStyle.color; + return Container( + padding: EdgeInsets.symmetric(vertical: widget.theme.messageInsetsVertical, horizontal: widget.theme.messageInsetsHorizontal), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if(messageLink != null) + LinkPreview( + url: messageLink!, // This disables tap event + ), + if(messageLink != null) + SizedBox(height: 8.0), + if(messageLink != widget.message.text.trim()) + MarkdownBody( + data: widget.message.text, + onTapLink: (text,href,title){ + if(href != null){ + launchUrl(Uri.parse(href)); + } + }, + styleSheet: styleSheet.copyWith( + code: widget.isMine ? widget.theme.sentMessageBodyCodeTextStyle: widget.theme.receivedMessageBodyCodeTextStyle, + p: widget.isMine ? widget.theme.sentMessageBodyTextStyle: widget.theme.receivedMessageBodyTextStyle, + h1: styleSheet.h1?.copyWith(color: textColor), + h2: styleSheet.h2?.copyWith(color: textColor), + h3: styleSheet.h3?.copyWith(color: textColor), + h4: styleSheet.h4?.copyWith(color: textColor), + h5: styleSheet.h5?.copyWith(color: textColor), + h6: styleSheet.h6?.copyWith(color: textColor), + tableBody: styleSheet.tableBody?.copyWith(color: textColor), + tableHead: styleSheet.tableHead?.copyWith(color: textColor), + a: widget.isMine ? styleSheet.a?.copyWith(color: Colors.white): styleSheet.a?.copyWith(color: widget.theme.primaryColor), + ) + ), + if(widget.message.metadata?["sentAt"] != null) + Text( + widget.message.metadata!["sentAt"], + style: (widget.isMine ? widget.theme.sentMessageBodyTextStyle: widget.theme.receivedMessageBodyTextStyle.copyWith(color: Colors.grey)).copyWith(fontSize: 12), + ) + ], + ), + ); + } + + String? get messageLink { + // Regular expression to match URLs + final RegExp urlRegex = RegExp( + r'(https?:\/\/[^\s]+)', // Match http or https URLs + caseSensitive: false, + ); + + // Find the first match + final Match? match = urlRegex.firstMatch(widget.message.text); + + // If a match is found, return the matched string; otherwise, return null + return match != null ? match.group(0) : null; + } +} + + + + +class CSATChatMessage extends StatefulWidget { + + final ChatwootChatTheme theme; + final ChatwootL10n l10n; + final types.CustomMessage message; + final int maxWidth; + final void Function(int,String) sendCsatResults; + const CSATChatMessage({ + Key? key, + required this.theme, + required this.message, + required this.l10n, + required this.maxWidth, + required this.sendCsatResults + }) : super(key: key); + + @override + _CSATChatMessageState createState() => _CSATChatMessageState(); +} + +class _CSATChatMessageState extends State { + String? selectedOption; + String? feedback; + bool isSentTapped = false; + late List options ; + final TextEditingController feedbackController = TextEditingController(); + + @override + void initState() { + options = [ + widget.l10n.csatVeryUnsatisfied, + widget.l10n.csatUnsatisfied, + widget.l10n.csatOK, + widget.l10n.csatSatisfied, + widget.l10n.csatVerySatisfied, + ]; + super.initState(); + } + @override + void dispose() { + feedbackController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Container( + width: widget.maxWidth.toDouble(), + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Question + Text( + widget.l10n.csatInquiryQuestion, + style: widget.theme.receivedMessageBodyBoldTextStyle, + ), + const SizedBox(height: 16.0), + + // Options + Column( + children: options.map((option) { + return GestureDetector( + onTap: isSentTapped ? null : () { + setState(() { + selectedOption = option; + }); + }, + child: Container( + margin: const EdgeInsets.symmetric(vertical: 4.0), + padding: const EdgeInsets.symmetric( + horizontal: 12.0, + vertical: 10.0, + ), + decoration: BoxDecoration( + color: selectedOption == option + ? widget.theme.primaryColor.withOpacity(0.1) + : Colors.white, + borderRadius: BorderRadius.circular(8.0), + border: Border.all( + color: selectedOption == option + ? widget.theme.primaryColor + : Colors.grey.shade300, + ), + ), + child: Row( + children: [ + Icon( + selectedOption == option + ? Icons.radio_button_checked + : Icons.radio_button_off, + color: selectedOption == option + ? widget.theme.primaryColor + : Colors.black, + ), + const SizedBox(width: 12.0), + Text( + option, + style: const TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ), + ); + }).toList(), + ), + const SizedBox(height: 16.0), + + // Feedback Field + Container( + color: Colors.white, + child: TextField( + controller: feedbackController, + maxLines: 3, + minLines: 3, + enabled: !isSentTapped, + decoration: InputDecoration( + hintText: widget.l10n.csatFeedbackPlaceholder, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8.0), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 12.0, + vertical: 10.0, + ), + ), + onChanged: (text){ + feedback = text; + }, + ), + ), + const SizedBox(height: 16.0), + + // Send Button + if(!isSentTapped) + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: selectedOption == null + ? null + : () { + // Handle submission + final rating = options.indexWhere((e)=>e == selectedOption)+1; + widget.sendCsatResults(rating, feedback??''); + setState(() { + isSentTapped = true; + }); + }, + style: ElevatedButton.styleFrom( + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + backgroundColor: selectedOption == null + ? Colors.grey + : widget.theme.primaryColor, // Disabled button styling + ), + child: Text( + "Send", + style: widget.theme.sentMessageBodyTextStyle, + ), + ), + ), + ], + ), + ); + } +} + + +class RecordedCsatChatMessage extends StatelessWidget{ + + + final ChatwootChatTheme theme; + final ChatwootL10n l10n; + final types.CustomMessage message; + final int maxWidth; + List get options => [ + l10n.csatVeryUnsatisfied, + l10n.csatUnsatisfied, + l10n.csatOK, + l10n.csatSatisfied, + l10n.csatVerySatisfied, + ]; + CsatSurveyFeedbackResponse get feedback => message.metadata!["feedback"]! as CsatSurveyFeedbackResponse; + String get selectedOption => options[(feedback.csatSurveyResponse?.rating ?? 3)-1]; + String get feedBackText => feedback.csatSurveyResponse?.feedbackMessage??''; + + RecordedCsatChatMessage({ + Key? key, + required this.theme, + required this.message, + required this.l10n, + required this.maxWidth, + }):super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + width: maxWidth.toDouble(), + padding: const EdgeInsets.all(16.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Question + Text( + l10n.csatThankYouMessage, + style: theme.receivedMessageBodyBoldTextStyle, + ), + const SizedBox(height: 16.0), + + // Options + Column( + children: options.map((option) { + return Container( + margin: const EdgeInsets.symmetric(vertical: 4.0), + padding: const EdgeInsets.symmetric( + horizontal: 12.0, + vertical: 10.0, + ), + decoration: BoxDecoration( + color: selectedOption == option + ? theme.primaryColor.withOpacity(0.1) + : Colors.white, + borderRadius: BorderRadius.circular(8.0), + border: Border.all( + color: selectedOption == option + ? theme.primaryColor + : Colors.grey.shade300, + ), + ), + child: Row( + children: [ + Icon( + selectedOption == option + ? Icons.radio_button_checked + : Icons.radio_button_off, + color: selectedOption == option + ? theme.primaryColor + : Colors.grey.shade300, + ), + const SizedBox(width: 12.0), + Text( + option, + style: TextStyle( + fontSize: 16.0, + fontWeight: FontWeight.w500, + color: selectedOption == option + ? theme.primaryColor + : Colors.grey.shade300, + ), + ), + ], + ), + ); + }).toList(), + ), + const SizedBox(height: 16.0), + + // Feedback Field + Text( + feedBackText, + style: theme.receivedMessageBodyTextStyle, + ), + + ], + ), + ); + } + +} + +class PlaceholderCircle extends StatelessWidget { + final String text; + final double size; + final Color backgroundColor; + final Color textColor; + final TextStyle? textStyle; + + const PlaceholderCircle({ + Key? key, + required this.text, + this.size = 30.0, + this.backgroundColor = Colors.white, + this.textColor = CHATWOOT_COLOR_PRIMARY, + this.textStyle, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Container( + width: size, + height: size, + decoration: BoxDecoration( + color: backgroundColor, + shape: BoxShape.circle, + ), + alignment: Alignment.center, + child: Text( + text, + style: textStyle ?? + TextStyle( + color: textColor, + fontSize: size / 2.5, // Scales font size relative to the widget size + fontWeight: FontWeight.bold, + ), + ), + ); + } +} + + + + + diff --git a/lib/ui/video_preview.dart b/lib/ui/video_preview.dart new file mode 100644 index 0000000..821e5eb --- /dev/null +++ b/lib/ui/video_preview.dart @@ -0,0 +1,162 @@ + + +import 'dart:async'; +import 'dart:collection'; +import 'dart:typed_data'; +import 'dart:ui' as ui; +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:media_kit/media_kit.dart'; +import 'package:media_kit_video/media_kit_video.dart'; + +class VideoMessagePreview{ + final ui.FrameInfo? firstFrame; + final double width; + final double height; + + + VideoMessagePreview({this.firstFrame, this.width=0, this.height=0}); + + +} + +class VideoMessagePreviewJob{ + final String jobId ; + final String uri; + + VideoMessagePreviewJob({required this.jobId, required this.uri}); + +} + +class VideoMessagePreviewResult{ + ///Fetch preview job identification + final String jobId ; + + ///Video uri + final String uri; + + ///Preview results + final VideoMessagePreview preview; + + VideoMessagePreviewResult({required this.jobId, required this.uri, required this.preview}); + +} + + +class VideoPreviewLoader{ + ///Video controller for loading first video frame. See [ChatwootChat.build] + VideoController controller; + + ///Queue for registering preview jobs + final _previewJobQueue = Queue(); + + ///Stream to send preview results + final _previewResponseStreamController = StreamController(); + + StreamSubscription? _previewResponseStreamSubscription; + + VideoPreviewLoader({required this.controller}); + + void getPreview({required String jobId, required String uri})async{ + if(_previewJobQueue.isEmpty){ + //no video previews are being fetched + _previewJobQueue.add(VideoMessagePreviewJob(jobId: jobId, uri: uri)); + _fromUri(jobId, uri); + }else{ + //ongoing video preview fetch. add to queue + _previewJobQueue.add(VideoMessagePreviewJob(jobId: jobId, uri: uri)); + } + } + + Future _getCacheVideoPreview(String jobId, String uri) async{ + + final fileInfo = await CachedNetworkImageProvider.defaultCacheManager.getFileFromCache(uri); + if(fileInfo != null){ + // return cached preview + final codec = await ui.instantiateImageCodec(await fileInfo.file.readAsBytes()); + final frame = await codec.getNextFrame(); + final firstframe = frame; + final width = frame.image.width.toDouble(); + final height = frame.image.height.toDouble(); + final cachedPreview = VideoMessagePreview( + firstFrame: firstframe, + width: width, + height: height + ); + return cachedPreview; + } + return null; + } + + ///Loads first frame from video url + Future _fromUri(String jobId, String uri) async{ + + //check for cached preview + final cachedPreview = await _getCacheVideoPreview(jobId, uri); + if(cachedPreview != null){ + // return cached preview + _previewResponseStreamController.add(VideoMessagePreviewResult(jobId: jobId, uri: uri, preview: cachedPreview)); + //check for pending jobs and execute + if(_previewJobQueue.isNotEmpty){ + final job = _previewJobQueue.removeFirst(); + _fromUri(job.jobId, job.uri); + } + return; + } + + //fetch video preview + ui.FrameInfo? firstframe; + double width = 0; + double height = 0; + try { + // Load the video into the player + await controller.player.setVolume(0); + await controller.player.open(Media(uri)); + await Future.delayed(Duration(seconds: 10)); + await controller.player.stream.position.firstWhere((d)=>d>Duration.zero); + Uint8List? frameBytes = await controller.player.screenshot(); + + + if (frameBytes != null) { + // Convert the Uint8List to a ui.Image + final codec = await ui.instantiateImageCodec(frameBytes); + final frame = await codec.getNextFrame(); + firstframe = frame; + width = frame.image.width.toDouble(); + height = frame.image.height.toDouble(); + await CachedNetworkImageProvider.defaultCacheManager.putFile(uri, frameBytes); + } + + } catch (e) { + print('Error capturing first frame: $e'); + } finally { + // Dispose the player + controller.player.stop(); + } + + final p = VideoMessagePreview( + firstFrame: firstframe, + width: width, + height: height + ); + + + //send preview result + _previewResponseStreamController.add( + VideoMessagePreviewResult(jobId: jobId, uri: uri, preview: p) + ); + + //check for pending jobs and execute + if(_previewJobQueue.isNotEmpty){ + final job = _previewJobQueue.removeFirst(); + _fromUri(job.jobId, job.uri); + } + } + + listen(void Function(VideoMessagePreviewResult) callback){ + _previewResponseStreamSubscription = _previewResponseStreamController.stream.listen(callback); + } + + dispose(){ + _previewResponseStreamSubscription?.cancel(); + } +} diff --git a/pubspec.lock b/pubspec.lock index 0d1087e..c213b36 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,34 +5,47 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "98d1d33ed129b372846e862de23a0fc365745f4d7b5e786ce667fcbbb7ac5c07" + sha256: f256b0c0ba6c7577c15e2e4e114755640a875e885099367bf6e012b19314c834 url: "https://pub.dev" source: hosted - version: "55.0.0" + version: "72.0.0" + _macros: + dependency: transitive + description: dart + source: sdk + version: "0.3.2" analyzer: dependency: transitive description: name: analyzer - sha256: "881348aed9b0b425882c97732629a6a31093c8ff20fc4b3b03fb9d3d50a3a126" + sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 + url: "https://pub.dev" + source: hosted + version: "6.7.0" + archive: + dependency: transitive + description: + name: archive + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d url: "https://pub.dev" source: hosted - version: "5.7.1" + version: "3.6.1" args: dependency: transitive description: name: args - sha256: "4cab82a83ffef80b262ddedf47a0a8e56ee6fbf7fe21e6e768b02792034dd440" + sha256: bf9f5caeea8d8fe6721a9c358dd8a5c1947b27f1cfaa18b39c301273594919e6 url: "https://pub.dev" source: hosted - version: "2.4.0" + version: "2.6.0" async: dependency: "direct main" description: name: async - sha256: bfe67ef28df125b7dddcea62755991f807aa39a2492a23e1550161692950bbe0 + sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" url: "https://pub.dev" source: hosted - version: "2.10.0" + version: "2.11.0" boolean_selector: dependency: transitive description: @@ -45,10 +58,10 @@ packages: dependency: transitive description: name: build - sha256: "3fbda25365741f8251b39f3917fb3c8e286a96fd068a5a242e11c2012d495777" + sha256: "80184af8b6cb3e5c1c4ec6d8544d27711700bc3e6d2efad04238c7b5290889f0" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.4.1" build_config: dependency: transitive description: @@ -61,34 +74,34 @@ packages: dependency: transitive description: name: build_daemon - sha256: "757153e5d9cd88253cb13f28c2fb55a537dc31fefd98137549895b5beb7c6169" + sha256: "79b2aef6ac2ed00046867ed354c88778c9c0f029df8a20fe10b5436826721ef9" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "4.0.2" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: db49b8609ef8c81cca2b310618c3017c00f03a92af44c04d310b907b2d692d95 + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.4.2" build_runner: dependency: "direct dev" description: name: build_runner - sha256: b0a8a7b8a76c493e85f1b84bffa0588859a06197863dba8c9036b15581fd9727 + sha256: "028819cfb90051c6b5440c7e574d1896f8037e3c96cf17aaeb054c9311cfbf4d" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.4.13" build_runner_core: dependency: transitive description: name: build_runner_core - sha256: "0db1b64c84fa803603fa406f8721959036e898cc9575d6ce4a3067581b9276c0" + sha256: f8126682b87a7282a339b871298cc12009cb67109cfa1614d6436fb0289193e0 url: "https://pub.dev" source: hosted - version: "7.2.2" + version: "7.3.2" built_collection: dependency: transitive description: @@ -101,26 +114,50 @@ packages: dependency: transitive description: name: built_value - sha256: "31b7c748fd4b9adf8d25d72a4c4a59ef119f12876cf414f94f8af5131d5fa2b0" + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb + url: "https://pub.dev" + source: hosted + version: "8.9.2" + cached_network_image: + dependency: "direct main" + description: + name: cached_network_image + sha256: "4a5d8d2c728b0f3d0245f69f921d7be90cae4c2fd5288f773088672c0893f819" url: "https://pub.dev" source: hosted - version: "8.4.4" + version: "3.4.0" + cached_network_image_platform_interface: + dependency: transitive + description: + name: cached_network_image_platform_interface + sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" + url: "https://pub.dev" + source: hosted + version: "4.1.1" + cached_network_image_web: + dependency: transitive + description: + name: cached_network_image_web + sha256: "6322dde7a5ad92202e64df659241104a43db20ed594c41ca18de1014598d7996" + url: "https://pub.dev" + source: hosted + version: "1.3.0" characters: dependency: transitive description: name: characters - sha256: e6a326c8af69605aec75ed6c187d06b349707a27fbff8222ca9cc2cff167975c + sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" url: "https://pub.dev" source: hosted - version: "1.2.1" + version: "1.3.0" checked_yaml: dependency: transitive description: name: checked_yaml - sha256: dd007e4fb8270916820a0d66e24f619266b60773cddd082c6439341645af2659 + sha256: feb6bed21949061731a7a75fc5d2aa727cf160b91af9a3e464c5e3a32e28b5ff url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.3" clock: dependency: transitive description: @@ -133,74 +170,98 @@ packages: dependency: transitive description: name: code_builder - sha256: "0d43dd1288fd145de1ecc9a3948ad4a6d5a82f0a14c4fdd0892260787d975cbe" + sha256: "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e" url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "4.10.1" collection: dependency: transitive description: name: collection - sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.0" + version: "1.18.0" convert: dependency: transitive description: name: convert - sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592" + sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" crypto: - dependency: transitive + dependency: "direct main" description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.6" csslib: dependency: transitive description: name: csslib - sha256: b36c7f7e24c0bdf1bf9a3da461c837d1de64b9f8beb190c9011d8c72a3dfd745 + sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e" url: "https://pub.dev" source: hosted - version: "0.17.2" + version: "1.0.2" dart_style: dependency: transitive description: name: dart_style - sha256: "6d691edde054969f0e0f26abb1b30834b5138b963793e56f69d3a9a4435e6352" + sha256: "7856d364b589d1f08986e140938578ed36ed948581fbc3bc9aef1805039ac5ab" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.7" + dbus: + dependency: transitive + description: + name: dbus + sha256: "365c771ac3b0e58845f39ec6deebc76e3276aa9922b0cc60840712094d9047ac" + url: "https://pub.dev" + source: hosted + version: "0.7.10" diffutil_dart: dependency: transitive description: name: diffutil_dart - sha256: "21bcad3fcc89389da5c72c59b9da31eabb301a6548f715c17b0dfdd27d2ac6d5" + sha256: "5e74883aedf87f3b703cb85e815bdc1ed9208b33501556e4a8a5572af9845c81" url: "https://pub.dev" source: hosted - version: "2.0.0+1" + version: "4.0.1" dio: dependency: "direct main" description: name: dio - sha256: "7d328c4d898a61efc3cd93655a0955858e29a0aa647f0f9e02d59b3bb275e2e8" + sha256: "5598aa796bbf4699afd5c67c0f5f6e2ed542afc956884b9cd58c306966efc260" + url: "https://pub.dev" + source: hosted + version: "5.7.0" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "33259a9276d6cea88774a0000cfae0d861003497755969c92faa223108620dc8" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + easy_image_viewer: + dependency: "direct main" + description: + name: easy_image_viewer + sha256: fb6cb123c3605552cc91150dcdb50ca977001dcddfb71d20caa0c5edc9a80947 url: "https://pub.dev" source: hosted - version: "4.0.6" + version: "1.5.1" equatable: dependency: "direct main" description: name: equatable - sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.7" fake_async: dependency: transitive description: @@ -213,119 +274,143 @@ packages: dependency: transitive description: name: ffi - sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.1.3" file: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.1" fixnum: dependency: transitive description: name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" + sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" + flutter_cache_manager: + dependency: transitive + description: + name: flutter_cache_manager + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" + url: "https://pub.dev" + source: hosted + version: "3.4.1" flutter_chat_types: dependency: "direct main" description: name: flutter_chat_types - sha256: cb9e72c6dee5f32e4b379b6b953dff95253c54242ee4e21ad81652b11902d5a8 + sha256: e285b588f6d19d907feb1f6d912deaf22e223656769c34093b64e1c59b094fb9 url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "3.6.2" flutter_chat_ui: dependency: "direct main" description: name: flutter_chat_ui - sha256: "9c19396e59de978da092a935a04542ecf9746e3d75b9b7a038638e2a1982a5a1" + sha256: "168a4231464ad00a17ea5f0813f1b58393bdd4035683ea4dc37bbe26be62891e" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.6.15" flutter_link_previewer: dependency: transitive description: name: flutter_link_previewer - sha256: "0adc16359ce8385d623ee4b2985e702d7766d52e351bf0fd6a12366f8e49a63f" + sha256: "007069e60f42419fb59872beb7a3cc3ea21e9f1bdff5d40239f376fa62ca9f20" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "3.2.2" flutter_linkify: dependency: transitive description: name: flutter_linkify - sha256: c89fe74de985ec22f23d3538d2249add085a4f37ac1c29fd79e1a207efb81d63 + sha256: "74669e06a8f358fee4512b4320c0b80e51cffc496607931de68d28f099254073" url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "6.0.0" flutter_lints: dependency: "direct dev" description: name: flutter_lints - sha256: aeb0b80a8b3709709c9cc496cdc027c5b3216796bc0af0ce1007eaf24464fd4c + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "5.0.0" + flutter_markdown: + dependency: "direct main" + description: + name: flutter_markdown + sha256: "999a4e3cb3e1532a971c86d6c73a480264f6a687959d4887cb4e2990821827e4" + url: "https://pub.dev" + source: hosted + version: "0.7.4+2" + flutter_parsed_text: + dependency: transitive + description: + name: flutter_parsed_text + sha256: "529cf5793b7acdf16ee0f97b158d0d4ba0bf06e7121ef180abe1a5b59e32c1e2" + url: "https://pub.dev" + source: hosted + version: "2.2.1" flutter_secure_storage: dependency: "direct main" description: name: flutter_secure_storage - sha256: "98352186ee7ad3639ccc77ad7924b773ff6883076ab952437d20f18a61f0a7c5" + sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0" url: "https://pub.dev" source: hosted - version: "8.0.0" + version: "9.2.2" flutter_secure_storage_linux: dependency: transitive description: name: flutter_secure_storage_linux - sha256: "0912ae29a572230ad52d8a4697e5518d7f0f429052fd51df7e5a7952c7efe2a3" + sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b" url: "https://pub.dev" source: hosted - version: "1.1.3" + version: "1.2.1" flutter_secure_storage_macos: dependency: transitive description: name: flutter_secure_storage_macos - sha256: "083add01847fc1c80a07a08e1ed6927e9acd9618a35e330239d4422cd2a58c50" + sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "3.1.2" flutter_secure_storage_platform_interface: dependency: transitive description: name: flutter_secure_storage_platform_interface - sha256: b3773190e385a3c8a382007893d678ae95462b3c2279e987b55d140d3b0cb81b + sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8 url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.1.2" flutter_secure_storage_web: dependency: transitive description: name: flutter_secure_storage_web - sha256: "42938e70d4b872e856e678c423cc0e9065d7d294f45bc41fc1981a4eb4beaffe" + sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9 url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.2.1" flutter_secure_storage_windows: dependency: transitive description: name: flutter_secure_storage_windows - sha256: fc2910ec9b28d60598216c29ea763b3a96c401f0ce1d13cdf69ccb0e5c93c3ee + sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709 url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "3.1.2" flutter_test: dependency: "direct dev" description: flutter @@ -336,38 +421,30 @@ packages: description: flutter source: sdk version: "0.0.0" - freezed_annotation: - dependency: transitive - description: - name: freezed_annotation - sha256: "70776c4541e5cacfe45bcaf00fe79137b8c61aa34fb5765a05ce6c57fd72c6e9" - url: "https://pub.dev" - source: hosted - version: "0.14.3" frontend_server_client: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" glob: dependency: transitive description: name: glob - sha256: "4515b5b6ddb505ebdd242a5f2cc5d22d3d6a80013789debfbda7777f47ea308c" + sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" graphs: dependency: transitive description: name: graphs - sha256: f9e130f3259f52d26f0cfc0e964513796dafed572fa52e45d2f8d6ca14db39b2 + sha256: "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.2" hive: dependency: "direct main" description: @@ -388,26 +465,26 @@ packages: dependency: "direct dev" description: name: hive_generator - sha256: "65998cc4d2cd9680a3d9709d893d2f6bb15e6c1f92626c3f1fa650b4b3281521" + sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4" url: "https://pub.dev" source: hosted - version: "2.0.0" + version: "2.0.1" html: dependency: transitive description: name: html - sha256: "79d498e6d6761925a34ee5ea8fa6dfef38607781d2fa91e37523474282af55cb" + sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec" url: "https://pub.dev" source: hosted - version: "0.15.2" + version: "0.15.5" http: dependency: transitive description: name: http - sha256: "6aa2946395183537c8b880962d935877325d6a09a2867c3970c05c0fed6ac482" + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 url: "https://pub.dev" source: hosted - version: "0.13.5" + version: "1.2.2" http_multi_server: dependency: transitive description: @@ -424,14 +501,22 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d + url: "https://pub.dev" + source: hosted + version: "4.3.0" intl: dependency: "direct main" description: name: intl - sha256: "910f85bce16fb5c6f614e117efa303e85a1731bb0081edf3604a2ae6e9a3cc91" + sha256: "99f282cb0e02edcbbf8c6b3bbc7c90b65635156c412e58f3975a7e55284ce685" url: "https://pub.dev" source: hosted - version: "0.17.0" + version: "0.20.0" io: dependency: transitive description: @@ -444,90 +529,210 @@ packages: dependency: transitive description: name: js - sha256: "5528c2f391ededb7775ec1daa69e65a2d61276f7552de2b5f7b8d34ee9fd4ab7" + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.6.7" json_annotation: dependency: "direct main" description: name: json_annotation - sha256: c33da08e136c3df0190bd5bbe51ae1df4a7d96e7954d1d7249fea2968a72d317 + sha256: "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1" url: "https://pub.dev" source: hosted - version: "4.8.0" + version: "4.9.0" json_serializable: dependency: "direct dev" description: name: json_serializable - sha256: dadc08bd61f72559f938dd08ec20dbfec6c709bba83515085ea943d2078d187a + sha256: c2fcb3920cf2b6ae6845954186420fca40bc0a8abcc84903b7801f17d7050d7c + url: "https://pub.dev" + source: hosted + version: "6.9.0" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + url: "https://pub.dev" + source: hosted + version: "10.0.5" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" url: "https://pub.dev" source: hosted - version: "6.6.1" + version: "3.0.5" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" linkify: dependency: transitive description: name: linkify - sha256: bdfbdafec6cdc9cd0ebb333a868cafc046714ad508e48be8095208c54691d959 + sha256: "4139ea77f4651ab9c315b577da2dd108d9aa0bd84b5d03d33323f1970c645832" url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "5.0.0" lints: dependency: transitive description: name: lints - sha256: "5e4a9cd06d447758280a8ac2405101e0e2094d2a1dbdd3756aec3fe7775ba593" + sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "5.0.0" logging: dependency: transitive description: name: logging - sha256: "04094f2eb032cbb06c6f6e8d3607edcfcb0455e2bb6cbc010cb01171dcb64e6d" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.3.0" + macros: + dependency: transitive + description: + name: macros + sha256: "0acaed5d6b7eab89f63350bccd82119e6c602df0f391260d0e32b5e23db79536" + url: "https://pub.dev" + source: hosted + version: "0.1.2-main.4" + markdown: + dependency: transitive + description: + name: markdown + sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051 + url: "https://pub.dev" + source: hosted + version: "7.2.2" matcher: dependency: transitive description: name: matcher - sha256: "16db949ceee371e9b99d22f88fa3a73c4e59fd0afed0bd25fc336eb76c198b72" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.13" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + media_kit: + dependency: "direct main" + description: + name: media_kit + sha256: "1f1deee148533d75129a6f38251ff8388e33ee05fc2d20a6a80e57d6051b7b62" + url: "https://pub.dev" + source: hosted + version: "1.1.11" + media_kit_libs_android_video: + dependency: transitive + description: + name: media_kit_libs_android_video + sha256: "9dd8012572e4aff47516e55f2597998f0a378e3d588d0fad0ca1f11a53ae090c" + url: "https://pub.dev" + source: hosted + version: "1.3.6" + media_kit_libs_ios_video: + dependency: transitive + description: + name: media_kit_libs_ios_video + sha256: b5382994eb37a4564c368386c154ad70ba0cc78dacdd3fb0cd9f30db6d837991 + url: "https://pub.dev" + source: hosted + version: "1.1.4" + media_kit_libs_linux: + dependency: transitive + description: + name: media_kit_libs_linux + sha256: e186891c31daa6bedab4d74dcdb4e8adfccc7d786bfed6ad81fe24a3b3010310 + url: "https://pub.dev" + source: hosted + version: "1.1.3" + media_kit_libs_macos_video: + dependency: transitive + description: + name: media_kit_libs_macos_video + sha256: f26aa1452b665df288e360393758f84b911f70ffb3878032e1aabba23aa1032d url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "1.1.4" + media_kit_libs_video: + dependency: "direct main" + description: + name: media_kit_libs_video + sha256: "20bb4aefa8fece282b59580e1cd8528117297083a6640c98c2e98cfc96b93288" + url: "https://pub.dev" + source: hosted + version: "1.0.5" + media_kit_libs_windows_video: + dependency: transitive + description: + name: media_kit_libs_windows_video + sha256: "32654572167825c42c55466f5d08eee23ea11061c84aa91b09d0e0f69bdd0887" + url: "https://pub.dev" + source: hosted + version: "1.0.10" + media_kit_native_event_loop: + dependency: transitive + description: + name: media_kit_native_event_loop + sha256: "7d82e3b3e9ded5c35c3146c5ba1da3118d1dd8ac3435bac7f29f458181471b40" + url: "https://pub.dev" + source: hosted + version: "1.0.9" + media_kit_video: + dependency: "direct main" + description: + name: media_kit_video + sha256: "2cc3b966679963ba25a4ce5b771e532a521ebde7c6aa20e9802bec95d9916c8f" + url: "https://pub.dev" + source: hosted + version: "1.2.5" meta: dependency: transitive description: name: meta - sha256: "6c268b42ed578a53088d834796959e4a1814b5e9e164f147f580a386e5decf42" + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.8.0" + version: "1.15.0" mime: - dependency: transitive + dependency: "direct main" description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "2.0.0" mockito: dependency: "direct dev" description: name: mockito - sha256: "2a8a17b82b1bde04d514e75d90d634a0ac23f6cb4991f6098009dd56836aeafe" + sha256: "6841eed20a7befac0ce07df8116c8b8233ed1f4486a7647c7fc5a02ae6163917" url: "https://pub.dev" source: hosted - version: "5.3.2" + version: "5.4.4" + octo_image: + dependency: transitive + description: + name: octo_image + sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" + url: "https://pub.dev" + source: hosted + version: "2.1.0" package_config: dependency: transitive description: @@ -536,86 +741,110 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + package_info_plus: + dependency: transitive + description: + name: package_info_plus + sha256: da8d9ac8c4b1df253d1a328b7bf01ae77ef132833479ab40763334db13b91cce + url: "https://pub.dev" + source: hosted + version: "8.1.1" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66 + url: "https://pub.dev" + source: hosted + version: "3.0.1" path: dependency: transitive description: name: path - sha256: db9d4f58c908a4ba5953fcee2ae317c94889433e5024c27ce74a37f94267945b + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.2" + version: "1.9.0" path_provider: dependency: "direct main" description: name: path_provider - sha256: "04890b994ee89bfa80bf3080bfec40d5a92c5c7a785ebb02c13084a099d2b6f9" + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" url: "https://pub.dev" source: hosted - version: "2.0.13" + version: "2.1.5" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "019f18c9c10ae370b08dce1f3e3b73bc9f58e7f087bb5e921f06529438ac0ae7" + sha256: c464428172cb986b758c6d1724c603097febb8fb855aa265aeecc9280c294d4a url: "https://pub.dev" source: hosted - version: "2.0.24" + version: "2.2.12" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "026b97a6c29da75181a37aae2eba9227f5fe13cb2838c6b975ce209328b8ab4e" + sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.4.0" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1" + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 url: "https://pub.dev" source: hosted - version: "2.1.10" + version: "2.2.1" path_provider_platform_interface: dependency: transitive description: name: path_provider_platform_interface - sha256: "57585299a729335f1298b43245842678cb9f43a6310351b18fb577d6e33165ec" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.0.6" + version: "2.1.2" path_provider_windows: dependency: transitive description: name: path_provider_windows - sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130 + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" photo_view: dependency: transitive description: name: photo_view - sha256: aedb4371e5bf67546ecd92aed341df714f9de5db7c417ce7538a91c2b43d931a + sha256: "1fc3d970a91295fbd1364296575f854c9863f225505c28c46e0a03e48960c75e" url: "https://pub.dev" source: hosted - version: "0.12.0" + version: "0.15.0" platform: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.6" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface - sha256: "6a2128648c854906c53fa8e33986fc0247a1116122f9534dd20e3ab9e16a32bc" + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.4" + version: "2.1.8" pool: dependency: transitive description: @@ -624,54 +853,118 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" - process: - dependency: transitive - description: - name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" - url: "https://pub.dev" - source: hosted - version: "4.2.4" pub_semver: dependency: transitive description: name: pub_semver - sha256: "307de764d305289ff24ad257ad5c5793ce56d04947599ad68b3baa124105fc17" + sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c" url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" pubspec_parse: dependency: transitive description: name: pubspec_parse - sha256: "0e01f805457ef610ccaf8d18067596afc34107a27149778b06b2083edbc140c1" + sha256: c799b721d79eb6ee6fa56f00c04b472dcd44a30d258fac2174a6ec57302678f8 url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.3.0" riverpod: dependency: "direct main" description: name: riverpod - sha256: "13cbe0e17b659f38027986df967b3eaf7f42c519786352167fc3db1be44eae07" + sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959" + url: "https://pub.dev" + source: hosted + version: "2.6.1" + rxdart: + dependency: transitive + description: + name: rxdart + sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" + url: "https://pub.dev" + source: hosted + version: "0.28.0" + safe_local_storage: + dependency: transitive + description: + name: safe_local_storage + sha256: ede4eb6cb7d88a116b3d3bf1df70790b9e2038bc37cb19112e381217c74d9440 + url: "https://pub.dev" + source: hosted + version: "1.0.2" + screen_brightness: + dependency: transitive + description: + name: screen_brightness + sha256: ed8da4a4511e79422fc1aa88138e920e4008cd312b72cdaa15ccb426c0faaedd + url: "https://pub.dev" + source: hosted + version: "0.2.2+1" + screen_brightness_android: + dependency: transitive + description: + name: screen_brightness_android + sha256: "3df10961e3a9e968a5e076fe27e7f4741fa8a1d3950bdeb48cf121ed529d0caf" + url: "https://pub.dev" + source: hosted + version: "0.1.0+2" + screen_brightness_ios: + dependency: transitive + description: + name: screen_brightness_ios + sha256: "99adc3ca5490b8294284aad5fcc87f061ad685050e03cf45d3d018fe398fd9a2" + url: "https://pub.dev" + source: hosted + version: "0.1.0" + screen_brightness_macos: + dependency: transitive + description: + name: screen_brightness_macos + sha256: "64b34e7e3f4900d7687c8e8fb514246845a73ecec05ab53483ed025bd4a899fd" + url: "https://pub.dev" + source: hosted + version: "0.1.0+1" + screen_brightness_platform_interface: + dependency: transitive + description: + name: screen_brightness_platform_interface + sha256: b211d07f0c96637a15fb06f6168617e18030d5d74ad03795dd8547a52717c171 + url: "https://pub.dev" + source: hosted + version: "0.1.0" + screen_brightness_windows: + dependency: transitive + description: + name: screen_brightness_windows + sha256: "9261bf33d0fc2707d8cf16339ce25768100a65e70af0fcabaf032fc12408ba86" url: "https://pub.dev" source: hosted - version: "0.14.0+3" + version: "0.1.3" + scroll_to_index: + dependency: transitive + description: + name: scroll_to_index + sha256: b707546e7500d9f070d63e5acf74fd437ec7eeeb68d3412ef7b0afada0b4f176 + url: "https://pub.dev" + source: hosted + version: "3.0.1" shelf: dependency: transitive description: name: shelf - sha256: c24a96135a2ccd62c64b69315a14adc5c3419df63b4d7c05832a346fdb73682c + sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.4.1" shelf_web_socket: dependency: transitive description: name: shelf_web_socket - sha256: a988c0e8d8ffbdb8a28aa7ec8e449c260f3deb808781fe1284d22c5bba7156e8 + sha256: cc36c297b52866d203dbf9332263c94becc2fe0ceaa9681d07b6ef9807023b67 url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "2.0.1" sky_engine: dependency: transitive description: flutter @@ -681,50 +974,98 @@ packages: dependency: transitive description: name: source_gen - sha256: c2bea18c95cfa0276a366270afaa2850b09b4a76db95d546f3d003dcc7011298 + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" url: "https://pub.dev" source: hosted - version: "1.2.7" + version: "1.5.0" source_helper: dependency: transitive description: name: source_helper - sha256: "3b67aade1d52416149c633ba1bb36df44d97c6b51830c2198e934e3fca87ca1f" + sha256: "6adebc0006c37dd63fe05bca0a929b99f06402fc95aa35bf36d67f5c06de01fd" url: "https://pub.dev" source: hosted - version: "1.3.3" + version: "1.3.4" source_span: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" + url: "https://pub.dev" + source: hosted + version: "1.10.0" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" + sqflite: + dependency: transitive + description: + name: sqflite + sha256: "2d7299468485dca85efeeadf5d38986909c5eb0cd71fd3db2c2f000e6c9454bb" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sqflite_android: + dependency: transitive + description: + name: sqflite_android + sha256: "78f489aab276260cdd26676d2169446c7ecd3484bbd5fead4ca14f3ed4dd9ee3" + url: "https://pub.dev" + source: hosted + version: "2.4.0" + sqflite_common: + dependency: transitive + description: + name: sqflite_common + sha256: "761b9740ecbd4d3e66b8916d784e581861fd3c3553eda85e167bc49fdb68f709" + url: "https://pub.dev" + source: hosted + version: "2.5.4+6" + sqflite_darwin: + dependency: transitive + description: + name: sqflite_darwin + sha256: "96a698e2bc82bd770a4d6aab00b42396a7c63d9e33513a56945cbccb594c2474" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sqflite_platform_interface: + dependency: transitive + description: + name: sqflite_platform_interface + sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "2.4.0" stack_trace: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" state_notifier: dependency: transitive description: name: state_notifier - sha256: "8fe42610f179b843b12371e40db58c9444f8757f8b69d181c97e50787caed289" + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb url: "https://pub.dev" source: hosted - version: "0.7.2+1" + version: "1.0.0" stream_channel: dependency: "direct main" description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" stream_transform: dependency: transitive description: @@ -745,10 +1086,10 @@ packages: dependency: "direct main" description: name: synchronized - sha256: "33b31b6beb98100bf9add464a36a8dd03eb10c7a8cf15aeec535e9b054aaf04b" + sha256: "69fe30f3a8b04a0be0c15ae6490fc859a78ef4c43ae2dd5e8a623d45bfcf9225" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.3.0+3" term_glyph: dependency: transitive description: @@ -761,98 +1102,114 @@ packages: dependency: transitive description: name: test_api - sha256: ad540f65f92caa91bf21dfc8ffb8c589d6e4dc0c2267818b4cc2792857706206 + sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" url: "https://pub.dev" source: hosted - version: "0.4.16" + version: "0.7.2" timing: dependency: transitive description: name: timing - sha256: c386d07d7f5efc613479a7c4d9d64b03710b03cfaa7e8ad5f2bfb295a1f0dfad + sha256: "70a3b636575d4163c477e6de42f247a23b315ae20e86442bebe32d3cabf61c32" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" typed_data: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.4.0" + universal_platform: + dependency: transitive + description: + name: universal_platform + sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + uri_parser: + dependency: transitive + description: + name: uri_parser + sha256: "6543c9fd86d2862fac55d800a43e67c0dcd1a41677cb69c2f8edfe73bbcf1835" + url: "https://pub.dev" + source: hosted + version: "2.0.2" url_launcher: dependency: "direct main" description: name: url_launcher - sha256: "75f2846facd11168d007529d6cd8fcb2b750186bea046af9711f10b907e1587e" + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" url: "https://pub.dev" source: hosted - version: "6.1.10" + version: "6.3.1" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: "845530e5e05db5500c1a4c1446785d60cbd8f9bd45e21e7dd643a3273bb4bbd1" + sha256: "6fc2f56536ee873eeb867ad176ae15f304ccccc357848b351f6f0d8d4a40d193" url: "https://pub.dev" source: hosted - version: "6.0.25" + version: "6.3.14" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "7ab1e5b646623d6a2537aa59d5d039f90eebef75a7c25e105f6f75de1f7750c3" + sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e url: "https://pub.dev" source: hosted - version: "6.1.2" + version: "6.3.1" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: "206fb8334a700ef7754d6a9ed119e7349bc830448098f21a69bf1b4ed038cabc" + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.2.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "0ef2b4f97942a16523e51256b799e9aa1843da6c60c55eefbfa9dbc2dcb8331a" + sha256: "769549c999acdb42b8bcfa7c43d72bf79a382ca7441ab18a808e101149daf672" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.2.1" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370" + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "81fe91b6c4f84f222d186a9d23c73157dc4c8e1c71489c4d08be1ad3b228f1aa" + sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e" url: "https://pub.dev" source: hosted - version: "2.0.16" + version: "2.3.3" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: a83ba3607a507758669cfafb03f9de09bf6e6280c14d9b9cb18f013e406dcacd + sha256: "44cf3aabcedde30f2dba119a9dea3b0f2672fbe6fa96e85536251d678216b3c4" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.1.3" uuid: dependency: "direct main" description: name: uuid - sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "4.5.1" vector_math: dependency: transitive description: @@ -861,78 +1218,142 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" + visibility_detector: + dependency: transitive + description: + name: visibility_detector + sha256: dd5cc11e13494f432d15939c3aa8ae76844c42b723398643ce9addb88a5ed420 + url: "https://pub.dev" + source: hosted + version: "0.4.0+2" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + url: "https://pub.dev" + source: hosted + version: "14.2.5" + volume_controller: + dependency: transitive + description: + name: volume_controller + sha256: c71d4c62631305df63b72da79089e078af2659649301807fa746088f365cb48e + url: "https://pub.dev" + source: hosted + version: "2.0.8" + wakelock_plus: + dependency: transitive + description: + name: wakelock_plus + sha256: bf4ee6f17a2fa373ed3753ad0e602b7603f8c75af006d5b9bdade263928c0484 + url: "https://pub.dev" + source: hosted + version: "1.2.8" + wakelock_plus_platform_interface: + dependency: transitive + description: + name: wakelock_plus_platform_interface + sha256: "422d1cdbb448079a8a62a5a770b69baa489f8f7ca21aef47800c726d404f9d16" + url: "https://pub.dev" + source: hosted + version: "1.2.1" watcher: dependency: transitive description: name: watcher - sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0" + sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + url: "https://pub.dev" + source: hosted + version: "0.5.1" + web_socket: + dependency: transitive + description: + name: web_socket + sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83" + url: "https://pub.dev" + source: hosted + version: "0.1.6" web_socket_channel: dependency: "direct main" description: name: web_socket_channel - sha256: ca49c0bc209c687b887f30527fb6a9d80040b072cc2990f34b9bec3e7663101b + sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "3.0.1" webview_flutter: dependency: "direct main" description: name: webview_flutter - sha256: b6cd42db3ced5411f3d01599906156885b18e4188f7065a8a351eb84bee347e0 + sha256: "889a0a678e7c793c308c68739996227c9661590605e70b1f6cf6b9a6634f7aec" url: "https://pub.dev" source: hosted - version: "4.0.6" + version: "4.10.0" webview_flutter_android: dependency: transitive description: name: webview_flutter_android - sha256: c849dcb6bf7367f696869006fb9575c15bdc6a1d624ae13f12de5a147a740b12 + sha256: "285cedfd9441267f6cca8843458620b5fda1af75b04f5818d0441acda5d7df19" url: "https://pub.dev" source: hosted - version: "3.4.2" + version: "4.1.0" webview_flutter_platform_interface: dependency: transitive description: name: webview_flutter_platform_interface - sha256: "1939c39e2150fb4d30fd3cc59a891a49fed9935db53007df633ed83581b6117b" + sha256: d937581d6e558908d7ae3dc1989c4f87b786891ab47bb9df7de548a151779d8d url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.10.0" webview_flutter_wkwebview: dependency: transitive description: name: webview_flutter_wkwebview - sha256: ab12479f7a0cf112b9420c36aaf206a1ca47cd60cd42de74a4be2e97a697587b + sha256: b7e92f129482460951d96ef9a46b49db34bd2e1621685de26e9eaafd9674e7eb url: "https://pub.dev" source: hosted - version: "3.2.1" + version: "3.16.3" win32: dependency: transitive description: name: win32 - sha256: c9ebe7ee4ab0c2194e65d3a07d8c54c5d00bb001b76081c4a04cdb8448b59e46 + sha256: "84ba388638ed7a8cb3445a320c8273136ab2631cd5f2c57888335504ddab1bc2" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "5.8.0" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" yaml: dependency: transitive description: name: yaml - sha256: "23812a9b125b48d4007117254bca50abb6c712352927eece9e155207b1db2370" + sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5" url: "https://pub.dev" source: hosted - version: "3.1.1" + version: "3.1.2" sdks: - dart: ">=2.19.0 <3.0.0" - flutter: ">=3.3.0" + dart: ">=3.5.3 <4.0.0" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index a40f874..ec204ea 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,10 @@ name: chatwoot_sdk description: A flutter client sdk for chatwoot. Integrate Chatwoot flutter client into your flutter app and talk to your visitors/users in real time. -version: 0.0.9 +version: 0.1.0 homepage: https://github.com/chatwoot/chatwoot-flutter-sdk environment: - sdk: ">=2.12.0 <3.0.0" - flutter: ">=1.17.0" + sdk: "^3.5.3" dependencies: flutter: @@ -13,21 +12,29 @@ dependencies: flutter_chat_ui: ^1.1.9 hive: ^2.2.3 hive_flutter: ^1.1.0 - uuid: ^3.0.4 - web_socket_channel: ^2.1.0 + uuid: ^4.5.1 + web_socket_channel: ^3.0.1 json_annotation: ^4.0.1 - dio: ^4.0.0 + dio: ^5.7.0 equatable: ^2.0.3 - riverpod: ^0.14.0+3 + riverpod: ^2.6.1 synchronized: ^3.0.0 - intl: ^0.17.0 - flutter_chat_types: ^2.4.0 + intl: ^0.20.0 + flutter_chat_types: ^3.6.2 stream_channel: ^2.1.0 async: ^2.5.0 - webview_flutter: ^4.0.6 - flutter_secure_storage: ^8.0.0 - url_launcher: ^6.1.10 + flutter_secure_storage: ^9.2.2 + url_launcher: ^6.3.1 path_provider: ^2.0.13 + mime: ^2.0.0 + media_kit: ^1.1.11 + media_kit_video: ^1.2.5 + media_kit_libs_video: ^1.0.5 + easy_image_viewer: ^1.5.1 + cached_network_image: ^3.4.0 + flutter_markdown: ^0.7.4+2 + webview_flutter: ^4.10.0 + crypto: ^3.0.6 dev_dependencies: flutter_test: @@ -36,7 +43,7 @@ dev_dependencies: json_serializable: ^6.6.1 hive_generator: ^2.0.0 build_runner: ^2.3.3 - flutter_lints: ^2.0.1 + flutter_lints: ^5.0.0 # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec diff --git a/test/chatwoot_client_test.dart b/test/chatwoot_client_test.dart index 9d141a4..7b05c80 100644 --- a/test/chatwoot_client_test.dart +++ b/test/chatwoot_client_test.dart @@ -2,6 +2,7 @@ import 'package:chatwoot_sdk/chatwoot_client.dart'; import 'package:chatwoot_sdk/data/chatwoot_repository.dart'; import 'package:chatwoot_sdk/data/local/entity/chatwoot_user.dart'; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_action_data.dart'; +import 'package:chatwoot_sdk/data/remote/requests/send_csat_survey_request.dart'; import 'package:chatwoot_sdk/di/modules.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; @@ -21,7 +22,9 @@ void main() { final testBaseUrl = "https://testbaseurl.com"; late ProviderContainer mockProviderContainer; final mockLocalStorage = MockLocalStorage(); + final mockLocalStorageProvider = Provider.family((ref,params)=>mockLocalStorage); final mockRepository = MockChatwootRepository(); + final mockRepositoryProvider = Provider.family((ref,params)=>mockRepository); final testUser = ChatwootUser( identifier: "identifier", @@ -38,13 +41,14 @@ void main() { setUp(() async { when(mockRepository.initialize(testUser)) .thenAnswer((realInvocation) => Future.microtask(() {})); - mockProviderContainer = ProviderContainer(); - mockProviderContainer.updateOverrides([ - localStorageProvider - .overrideWithProvider((ref, param) => mockLocalStorage), - chatwootRepositoryProvider - .overrideWithProvider((ref, param) => mockRepository) - ]); + mockProviderContainer = ProviderContainer( + overrides:[ + localStorageProvider + .overrideWithProvider(mockLocalStorageProvider), + chatwootRepositoryProvider + .overrideWithProvider(mockRepositoryProvider) + ] + ); ChatwootClient.providerContainerMap.update( testClientInstanceKey, (_) => mockProviderContainer, ifAbsent: () => mockProviderContainer); @@ -174,19 +178,36 @@ void main() { verify(mockRepository.getMessages()); }); + test( + 'Given csat feedback is sent successfully when a sendCsatSurveyResults is called, then repository should be called', + () async { + //GIVEN + final testConversationUuid = "conversation-uuid"; + final rating = 5; + final feedback = "Excellent service"; + when(mockRepository.sendCsatFeedBack(any, any)) + .thenAnswer((_) => Future.microtask(() {})); + + //WHEN + client.sendCsatSurveyResults(testConversationUuid, rating, feedback); + + //THEN + verify(mockRepository.sendCsatFeedBack(testConversationUuid, SendCsatSurveyRequest(rating: rating, feedbackMessage: feedback))); + }); + test( 'Given action is sent successfully when a sendAction is called, then repository should be called', - () async { - //GIVEN - when(mockRepository.sendAction(any)) - .thenAnswer((_) => Future.microtask(() {})); + () async { + //GIVEN + when(mockRepository.sendAction(any)) + .thenAnswer((_) => Future.microtask(() {})); - //WHEN - client.sendAction(ChatwootActionType.update_presence); + //WHEN + client.sendAction(ChatwootActionType.update_presence); - //THEN - verify(mockRepository.sendAction(ChatwootActionType.update_presence)); - }); + //THEN + verify(mockRepository.sendAction(ChatwootActionType.update_presence)); + }); test( 'Given client is successfully initialized when a create is called without persistence enabled, then repository should be initialized', diff --git a/test/chatwoot_client_test.mocks.dart b/test/chatwoot_client_test.mocks.dart index b66c3de..19900e3 100644 --- a/test/chatwoot_client_test.mocks.dart +++ b/test/chatwoot_client_test.mocks.dart @@ -1,7 +1,8 @@ -// Mocks generated by Mockito 5.0.15 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in chatwoot_sdk/test/chatwoot_client_test.dart. // Do not manually edit this file. +// ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i6; import 'package:chatwoot_sdk/chatwoot_callbacks.dart' as _i4; @@ -12,25 +13,56 @@ import 'package:chatwoot_sdk/data/remote/requests/chatwoot_action_data.dart' as _i9; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_new_message_request.dart' as _i8; +import 'package:chatwoot_sdk/data/remote/requests/send_csat_survey_request.dart' + as _i10; import 'package:chatwoot_sdk/data/remote/service/chatwoot_client_service.dart' as _i2; import 'package:mockito/mockito.dart' as _i1; +// ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class -class _FakeChatwootClientService_0 extends _i1.Fake - implements _i2.ChatwootClientService {} +class _FakeChatwootClientService_0 extends _i1.SmartFake + implements _i2.ChatwootClientService { + _FakeChatwootClientService_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeLocalStorage_1 extends _i1.Fake implements _i3.LocalStorage {} +class _FakeLocalStorage_1 extends _i1.SmartFake implements _i3.LocalStorage { + _FakeLocalStorage_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeChatwootCallbacks_2 extends _i1.Fake - implements _i4.ChatwootCallbacks {} +class _FakeChatwootCallbacks_2 extends _i1.SmartFake + implements _i4.ChatwootCallbacks { + _FakeChatwootCallbacks_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} /// A class which mocks [ChatwootRepository]. /// @@ -42,56 +74,132 @@ class MockChatwootRepository extends _i1.Mock } @override - _i2.ChatwootClientService get clientService => - (super.noSuchMethod(Invocation.getter(#clientService), - returnValue: _FakeChatwootClientService_0()) - as _i2.ChatwootClientService); + _i2.ChatwootClientService get clientService => (super.noSuchMethod( + Invocation.getter(#clientService), + returnValue: _FakeChatwootClientService_0( + this, + Invocation.getter(#clientService), + ), + ) as _i2.ChatwootClientService); + @override - _i3.LocalStorage get localStorage => - (super.noSuchMethod(Invocation.getter(#localStorage), - returnValue: _FakeLocalStorage_1()) as _i3.LocalStorage); + _i3.LocalStorage get localStorage => (super.noSuchMethod( + Invocation.getter(#localStorage), + returnValue: _FakeLocalStorage_1( + this, + Invocation.getter(#localStorage), + ), + ) as _i3.LocalStorage); + @override - _i4.ChatwootCallbacks get callbacks => - (super.noSuchMethod(Invocation.getter(#callbacks), - returnValue: _FakeChatwootCallbacks_2()) as _i4.ChatwootCallbacks); + _i4.ChatwootCallbacks get callbacks => (super.noSuchMethod( + Invocation.getter(#callbacks), + returnValue: _FakeChatwootCallbacks_2( + this, + Invocation.getter(#callbacks), + ), + ) as _i4.ChatwootCallbacks); + @override - set callbacks(_i4.ChatwootCallbacks? _callbacks) => - super.noSuchMethod(Invocation.setter(#callbacks, _callbacks), - returnValueForMissingStub: null); + set callbacks(_i4.ChatwootCallbacks? _callbacks) => super.noSuchMethod( + Invocation.setter( + #callbacks, + _callbacks, + ), + returnValueForMissingStub: null, + ); + @override - _i6.Future initialize(_i7.ChatwootUser? user) => - (super.noSuchMethod(Invocation.method(#initialize, [user]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i6.Future); + _i6.Future initialize(_i7.ChatwootUser? user) => (super.noSuchMethod( + Invocation.method( + #initialize, + [user], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + @override - void getPersistedMessages() => - super.noSuchMethod(Invocation.method(#getPersistedMessages, []), - returnValueForMissingStub: null); + void getPersistedMessages() => super.noSuchMethod( + Invocation.method( + #getPersistedMessages, + [], + ), + returnValueForMissingStub: null, + ); + @override - _i6.Future getMessages() => - (super.noSuchMethod(Invocation.method(#getMessages, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i6.Future); + _i6.Future getMessages() => (super.noSuchMethod( + Invocation.method( + #getMessages, + [], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + @override - void listenForEvents() => - super.noSuchMethod(Invocation.method(#listenForEvents, []), - returnValueForMissingStub: null); + void listenForEvents() => super.noSuchMethod( + Invocation.method( + #listenForEvents, + [], + ), + returnValueForMissingStub: null, + ); + @override _i6.Future sendMessage(_i8.ChatwootNewMessageRequest? request) => - (super.noSuchMethod(Invocation.method(#sendMessage, [request]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i6.Future); + (super.noSuchMethod( + Invocation.method( + #sendMessage, + [request], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + @override - void sendAction(_i9.ChatwootActionType? action) => - super.noSuchMethod(Invocation.method(#sendAction, [action]), - returnValueForMissingStub: null); + void sendAction(_i9.ChatwootActionType? action) => super.noSuchMethod( + Invocation.method( + #sendAction, + [action], + ), + returnValueForMissingStub: null, + ); + @override - _i6.Future clear() => (super.noSuchMethod(Invocation.method(#clear, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i6.Future); + _i6.Future sendCsatFeedBack( + String? conversationUuid, + _i10.SendCsatSurveyRequest? request, + ) => + (super.noSuchMethod( + Invocation.method( + #sendCsatFeedBack, + [ + conversationUuid, + request, + ], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + @override - void dispose() => super.noSuchMethod(Invocation.method(#dispose, []), - returnValueForMissingStub: null); + _i6.Future clear() => (super.noSuchMethod( + Invocation.method( + #clear, + [], + ), + returnValue: _i6.Future.value(), + returnValueForMissingStub: _i6.Future.value(), + ) as _i6.Future); + @override - String toString() => super.toString(); + void dispose() => super.noSuchMethod( + Invocation.method( + #dispose, + [], + ), + returnValueForMissingStub: null, + ); } diff --git a/test/data/chatwoot_repository_test.dart b/test/data/chatwoot_repository_test.dart index 73b02ed..dace57f 100644 --- a/test/data/chatwoot_repository_test.dart +++ b/test/data/chatwoot_repository_test.dart @@ -11,6 +11,8 @@ import 'package:chatwoot_sdk/data/local/local_storage.dart'; import 'package:chatwoot_sdk/data/remote/chatwoot_client_exception.dart'; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_action_data.dart'; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_new_message_request.dart'; +import 'package:chatwoot_sdk/data/remote/requests/send_csat_survey_request.dart'; +import 'package:chatwoot_sdk/data/remote/responses/csat_survey_response.dart'; import 'package:chatwoot_sdk/data/remote/service/chatwoot_client_service.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mockito/annotations.dart'; @@ -36,6 +38,7 @@ void main() { avatarUrl: "avatarUrl", customAttributes: {}); late final ChatwootMessage testMessage; + late final CsatSurveyFeedbackResponse testCsatFeedback; final mockLocalStorage = MockLocalStorage(); final mockChatwootClientService = MockChatwootClientService(); @@ -56,6 +59,8 @@ void main() { await TestResourceUtil.readJsonResource(fileName: "conversation")); testMessage = ChatwootMessage.fromJson( await TestResourceUtil.readJsonResource(fileName: "message")); + testCsatFeedback = CsatSurveyFeedbackResponse.fromJson( + await TestResourceUtil.readJsonResource(fileName: "csat_feedback")); when(mockLocalStorage.messagesDao).thenReturn(mockMessagesDao); when(mockLocalStorage.contactDao).thenReturn(mockContactDao); @@ -146,45 +151,81 @@ void main() { test( 'Given message is successfully sent when sendMessage is called, then callback should be called with sent message', - () async { - //GIVEN - final messageRequest = + () async { + //GIVEN + final messageRequest = ChatwootNewMessageRequest(content: "new message", echoId: "echoId"); - when(mockChatwootClientService.createMessage(any)) - .thenAnswer((_) => Future.value(testMessage)); - when(mockChatwootCallbacks.onMessageSent).thenAnswer((_) => (_, __) {}); - when(mockMessagesDao.saveMessage(any)) - .thenAnswer((_) => Future.microtask(() {})); - - //WHEN - await repo.sendMessage(messageRequest); - - //THEN - verify(mockChatwootClientService.createMessage(messageRequest)); - verify(mockChatwootCallbacks.onMessageSent - ?.call(testMessage, messageRequest.echoId)); - verify(mockMessagesDao.saveMessage(testMessage)); - }); + when(mockChatwootClientService.createMessage(any)) + .thenAnswer((_) => Future.value(testMessage)); + when(mockChatwootCallbacks.onMessageSent).thenAnswer((_) => (_, __) {}); + when(mockMessagesDao.saveMessage(any)) + .thenAnswer((_) => Future.microtask(() {})); + + //WHEN + await repo.sendMessage(messageRequest); + + //THEN + verify(mockChatwootClientService.createMessage(messageRequest)); + verify(mockChatwootCallbacks.onMessageSent + ?.call(testMessage, messageRequest.echoId)); + verify(mockMessagesDao.saveMessage(testMessage)); + }); test( 'Given message fails to send when sendMessage is called, then callback should be called with an error', - () async { - //GIVEN - final testError = ChatwootClientException( - "error", ChatwootClientExceptionType.SEND_MESSAGE_FAILED); - final messageRequest = + () async { + //GIVEN + final testError = ChatwootClientException( + "error", ChatwootClientExceptionType.SEND_MESSAGE_FAILED); + final messageRequest = ChatwootNewMessageRequest(content: "new message", echoId: "echoId"); - when(mockChatwootClientService.createMessage(any)).thenThrow(testError); - when(mockChatwootCallbacks.onError).thenAnswer((_) => (_) {}); + when(mockChatwootClientService.createMessage(any)).thenThrow(testError); + when(mockChatwootCallbacks.onError).thenAnswer((_) => (_) {}); - //WHEN - await repo.sendMessage(messageRequest); + //WHEN + await repo.sendMessage(messageRequest); - //THEN - verify(mockChatwootClientService.createMessage(messageRequest)); - verify(mockChatwootCallbacks.onError?.call(testError)); - verifyNever(mockMessagesDao.saveMessage(any)); - }); + //THEN + verify(mockChatwootClientService.createMessage(messageRequest)); + verify(mockChatwootCallbacks.onError?.call(testError)); + verifyNever(mockMessagesDao.saveMessage(any)); + }); + + test( + 'Given csat survey is successfully recorded when sendCsatFeedBack is called, then callback should be called with feedback response', + () async { + //GIVEN + final csatRequest = SendCsatSurveyRequest(rating: 5, feedbackMessage: "My issue was resolved promptly"); + when(mockChatwootClientService.sendCsatFeedBack(testConversation.uuid, csatRequest)) + .thenAnswer((_) => Future.value(testCsatFeedback)); + when(mockChatwootCallbacks.onCsatSurveyResponseRecorded).thenAnswer((_) => (_) {}); + + //WHEN + await repo.sendCsatFeedBack(testConversation.uuid!, csatRequest); + + //THEN + verify(mockChatwootClientService.sendCsatFeedBack(testConversation.uuid, csatRequest)); + verify(mockChatwootCallbacks.onCsatSurveyResponseRecorded + ?.call(testCsatFeedback)); + }); + + test( + 'Given send csat survey fails to send when sendCsatFeedBack is called, then callback should be called with an error', + () async { + //GIVEN + final testError = ChatwootClientException( + "error", ChatwootClientExceptionType.SEND_CSAT_FEEDBACK); + final csatRequest = SendCsatSurveyRequest(rating: 5, feedbackMessage: "My issue was resolved promptly"); + when(mockChatwootClientService.sendCsatFeedBack(testConversation.uuid, csatRequest)).thenThrow(testError); + when(mockChatwootCallbacks.onError).thenAnswer((_) => (_) {}); + + //WHEN + await repo.sendCsatFeedBack(testConversation.uuid!, csatRequest); + + //THEN + verify(mockChatwootClientService.sendCsatFeedBack(testConversation.uuid, csatRequest)); + verify(mockChatwootCallbacks.onError?.call(testError)); + }); test( 'Given repo is initialized with user successfully when initialize is called, then client should be properly initialized', @@ -343,6 +384,7 @@ void main() { () async { //GIVEN when(mockLocalStorage.dispose()).thenAnswer((_) => (_) {}); + when(mockChatwootCallbacks.onError).thenAnswer((_) => (_) {}); when(mockChatwootCallbacks.onConversationIsOffline) .thenAnswer((_) => () {}); when(mockChatwootCallbacks.onConversationIsOnline) @@ -388,7 +430,7 @@ void main() { when(mockConversationDao.getConversation()).thenReturn(testConversation); when(mockLocalStorage.dispose()).thenAnswer((_) => (_) {}); when(mockChatwootCallbacks.onConversationResolved) - .thenAnswer((_) => () {}); + .thenAnswer((_) => (_) {}); final dynamic resolvedEvent = await TestResourceUtil.readJsonResource( fileName: "websocket_conversation_status_changed"); repo.listenForEvents(); @@ -398,7 +440,7 @@ void main() { await Future.delayed(Duration(seconds: 1)); //THEN - verify(mockChatwootCallbacks.onConversationResolved?.call()); + verify(mockChatwootCallbacks.onConversationResolved?.call(testConversation.uuid!)); }); test( diff --git a/test/data/chatwoot_repository_test.mocks.dart b/test/data/chatwoot_repository_test.mocks.dart index 8beac8d..02acd22 100644 --- a/test/data/chatwoot_repository_test.mocks.dart +++ b/test/data/chatwoot_repository_test.mocks.dart @@ -1,11 +1,12 @@ -// Mocks generated by Mockito 5.0.15 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in chatwoot_sdk/test/data/chatwoot_repository_test.dart. // Do not manually edit this file. -import 'dart:async' as _i11; +// ignore_for_file: no_leading_underscores_for_library_prefixes +import 'dart:async' as _i12; -import 'package:async/async.dart' as _i18; -import 'package:chatwoot_sdk/chatwoot_callbacks.dart' as _i16; +import 'package:async/async.dart' as _i20; +import 'package:chatwoot_sdk/chatwoot_callbacks.dart' as _i18; import 'package:chatwoot_sdk/data/local/dao/chatwoot_contact_dao.dart' as _i4; import 'package:chatwoot_sdk/data/local/dao/chatwoot_conversation_dao.dart' as _i3; @@ -13,323 +14,744 @@ import 'package:chatwoot_sdk/data/local/dao/chatwoot_messages_dao.dart' as _i5; import 'package:chatwoot_sdk/data/local/dao/chatwoot_user_dao.dart' as _i2; import 'package:chatwoot_sdk/data/local/entity/chatwoot_contact.dart' as _i6; import 'package:chatwoot_sdk/data/local/entity/chatwoot_conversation.dart' - as _i13; + as _i14; import 'package:chatwoot_sdk/data/local/entity/chatwoot_message.dart' as _i7; -import 'package:chatwoot_sdk/data/local/local_storage.dart' as _i10; +import 'package:chatwoot_sdk/data/local/local_storage.dart' as _i11; import 'package:chatwoot_sdk/data/remote/chatwoot_client_exception.dart' - as _i17; + as _i19; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_action_data.dart' - as _i15; + as _i17; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_new_message_request.dart' - as _i14; + as _i15; +import 'package:chatwoot_sdk/data/remote/requests/send_csat_survey_request.dart' + as _i16; +import 'package:chatwoot_sdk/data/remote/responses/csat_survey_response.dart' + as _i8; import 'package:chatwoot_sdk/data/remote/service/chatwoot_client_service.dart' - as _i12; + as _i13; import 'package:mockito/mockito.dart' as _i1; -import 'package:stream_channel/stream_channel.dart' as _i9; -import 'package:web_socket_channel/web_socket_channel.dart' as _i8; +import 'package:stream_channel/stream_channel.dart' as _i10; +import 'package:web_socket_channel/web_socket_channel.dart' as _i9; +// ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class -class _FakeChatwootUserDao_0 extends _i1.Fake implements _i2.ChatwootUserDao {} +class _FakeChatwootUserDao_0 extends _i1.SmartFake + implements _i2.ChatwootUserDao { + _FakeChatwootUserDao_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} + +class _FakeChatwootConversationDao_1 extends _i1.SmartFake + implements _i3.ChatwootConversationDao { + _FakeChatwootConversationDao_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeChatwootConversationDao_1 extends _i1.Fake - implements _i3.ChatwootConversationDao {} +class _FakeChatwootContactDao_2 extends _i1.SmartFake + implements _i4.ChatwootContactDao { + _FakeChatwootContactDao_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeChatwootContactDao_2 extends _i1.Fake - implements _i4.ChatwootContactDao {} +class _FakeChatwootMessagesDao_3 extends _i1.SmartFake + implements _i5.ChatwootMessagesDao { + _FakeChatwootMessagesDao_3( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeChatwootMessagesDao_3 extends _i1.Fake - implements _i5.ChatwootMessagesDao {} +class _FakeChatwootContact_4 extends _i1.SmartFake + implements _i6.ChatwootContact { + _FakeChatwootContact_4( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeChatwootContact_4 extends _i1.Fake implements _i6.ChatwootContact {} +class _FakeChatwootMessage_5 extends _i1.SmartFake + implements _i7.ChatwootMessage { + _FakeChatwootMessage_5( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeChatwootMessage_5 extends _i1.Fake implements _i7.ChatwootMessage {} +class _FakeCsatSurveyFeedbackResponse_6 extends _i1.SmartFake + implements _i8.CsatSurveyFeedbackResponse { + _FakeCsatSurveyFeedbackResponse_6( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeWebSocketSink_6 extends _i1.Fake implements _i8.WebSocketSink {} +class _FakeWebSocketSink_7 extends _i1.SmartFake implements _i9.WebSocketSink { + _FakeWebSocketSink_7( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeStreamChannel_7 extends _i1.Fake implements _i9.StreamChannel { +class _FakeStreamChannel_8 extends _i1.SmartFake + implements _i10.StreamChannel { + _FakeStreamChannel_8( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); } /// A class which mocks [LocalStorage]. /// /// See the documentation for Mockito's code generation for more information. -class MockLocalStorage extends _i1.Mock implements _i10.LocalStorage { +class MockLocalStorage extends _i1.Mock implements _i11.LocalStorage { MockLocalStorage() { _i1.throwOnMissingStub(this); } @override - _i2.ChatwootUserDao get userDao => - (super.noSuchMethod(Invocation.getter(#userDao), - returnValue: _FakeChatwootUserDao_0()) as _i2.ChatwootUserDao); + _i2.ChatwootUserDao get userDao => (super.noSuchMethod( + Invocation.getter(#userDao), + returnValue: _FakeChatwootUserDao_0( + this, + Invocation.getter(#userDao), + ), + ) as _i2.ChatwootUserDao); + @override - set userDao(_i2.ChatwootUserDao? _userDao) => - super.noSuchMethod(Invocation.setter(#userDao, _userDao), - returnValueForMissingStub: null); + set userDao(_i2.ChatwootUserDao? _userDao) => super.noSuchMethod( + Invocation.setter( + #userDao, + _userDao, + ), + returnValueForMissingStub: null, + ); + @override - _i3.ChatwootConversationDao get conversationDao => - (super.noSuchMethod(Invocation.getter(#conversationDao), - returnValue: _FakeChatwootConversationDao_1()) - as _i3.ChatwootConversationDao); + _i3.ChatwootConversationDao get conversationDao => (super.noSuchMethod( + Invocation.getter(#conversationDao), + returnValue: _FakeChatwootConversationDao_1( + this, + Invocation.getter(#conversationDao), + ), + ) as _i3.ChatwootConversationDao); + @override set conversationDao(_i3.ChatwootConversationDao? _conversationDao) => - super.noSuchMethod(Invocation.setter(#conversationDao, _conversationDao), - returnValueForMissingStub: null); + super.noSuchMethod( + Invocation.setter( + #conversationDao, + _conversationDao, + ), + returnValueForMissingStub: null, + ); + @override - _i4.ChatwootContactDao get contactDao => - (super.noSuchMethod(Invocation.getter(#contactDao), - returnValue: _FakeChatwootContactDao_2()) as _i4.ChatwootContactDao); + _i4.ChatwootContactDao get contactDao => (super.noSuchMethod( + Invocation.getter(#contactDao), + returnValue: _FakeChatwootContactDao_2( + this, + Invocation.getter(#contactDao), + ), + ) as _i4.ChatwootContactDao); + @override - set contactDao(_i4.ChatwootContactDao? _contactDao) => - super.noSuchMethod(Invocation.setter(#contactDao, _contactDao), - returnValueForMissingStub: null); + set contactDao(_i4.ChatwootContactDao? _contactDao) => super.noSuchMethod( + Invocation.setter( + #contactDao, + _contactDao, + ), + returnValueForMissingStub: null, + ); + @override _i5.ChatwootMessagesDao get messagesDao => (super.noSuchMethod( - Invocation.getter(#messagesDao), - returnValue: _FakeChatwootMessagesDao_3()) as _i5.ChatwootMessagesDao); + Invocation.getter(#messagesDao), + returnValue: _FakeChatwootMessagesDao_3( + this, + Invocation.getter(#messagesDao), + ), + ) as _i5.ChatwootMessagesDao); + @override - set messagesDao(_i5.ChatwootMessagesDao? _messagesDao) => - super.noSuchMethod(Invocation.setter(#messagesDao, _messagesDao), - returnValueForMissingStub: null); + set messagesDao(_i5.ChatwootMessagesDao? _messagesDao) => super.noSuchMethod( + Invocation.setter( + #messagesDao, + _messagesDao, + ), + returnValueForMissingStub: null, + ); + @override - _i11.Future clear({bool? clearChatwootUserStorage = true}) => + _i12.Future clear({bool? clearChatwootUserStorage = true}) => (super.noSuchMethod( - Invocation.method(#clear, [], - {#clearChatwootUserStorage: clearChatwootUserStorage}), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) - as _i11.Future); - @override - _i11.Future clearAll() => (super.noSuchMethod( - Invocation.method(#clearAll, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i11.Future); - @override - String toString() => super.toString(); + Invocation.method( + #clear, + [], + {#clearChatwootUserStorage: clearChatwootUserStorage}, + ), + returnValue: _i12.Future.value(), + returnValueForMissingStub: _i12.Future.value(), + ) as _i12.Future); + + @override + _i12.Future clearAll() => (super.noSuchMethod( + Invocation.method( + #clearAll, + [], + ), + returnValue: _i12.Future.value(), + returnValueForMissingStub: _i12.Future.value(), + ) as _i12.Future); } /// A class which mocks [ChatwootClientService]. /// /// See the documentation for Mockito's code generation for more information. class MockChatwootClientService extends _i1.Mock - implements _i12.ChatwootClientService { + implements _i13.ChatwootClientService { MockChatwootClientService() { _i1.throwOnMissingStub(this); } @override - set connection(_i8.WebSocketChannel? _connection) => - super.noSuchMethod(Invocation.setter(#connection, _connection), - returnValueForMissingStub: null); - @override - _i11.Future<_i6.ChatwootContact> updateContact(dynamic update) => - (super.noSuchMethod(Invocation.method(#updateContact, [update]), - returnValue: - Future<_i6.ChatwootContact>.value(_FakeChatwootContact_4())) - as _i11.Future<_i6.ChatwootContact>); - @override - _i11.Future<_i6.ChatwootContact> getContact() => - (super.noSuchMethod(Invocation.method(#getContact, []), - returnValue: - Future<_i6.ChatwootContact>.value(_FakeChatwootContact_4())) - as _i11.Future<_i6.ChatwootContact>); - @override - _i11.Future> getConversations() => - (super.noSuchMethod(Invocation.method(#getConversations, []), - returnValue: Future>.value( - <_i13.ChatwootConversation>[])) - as _i11.Future>); - @override - _i11.Future<_i7.ChatwootMessage> createMessage( - _i14.ChatwootNewMessageRequest? request) => - (super.noSuchMethod(Invocation.method(#createMessage, [request]), - returnValue: - Future<_i7.ChatwootMessage>.value(_FakeChatwootMessage_5())) - as _i11.Future<_i7.ChatwootMessage>); - @override - _i11.Future<_i7.ChatwootMessage> updateMessage( - String? messageIdentifier, dynamic update) => + set connection(_i9.WebSocketChannel? _connection) => super.noSuchMethod( + Invocation.setter( + #connection, + _connection, + ), + returnValueForMissingStub: null, + ); + + @override + _i12.Future<_i6.ChatwootContact> updateContact(dynamic update) => + (super.noSuchMethod( + Invocation.method( + #updateContact, + [update], + ), + returnValue: + _i12.Future<_i6.ChatwootContact>.value(_FakeChatwootContact_4( + this, + Invocation.method( + #updateContact, + [update], + ), + )), + ) as _i12.Future<_i6.ChatwootContact>); + + @override + _i12.Future<_i6.ChatwootContact> getContact() => (super.noSuchMethod( + Invocation.method( + #getContact, + [], + ), + returnValue: + _i12.Future<_i6.ChatwootContact>.value(_FakeChatwootContact_4( + this, + Invocation.method( + #getContact, + [], + ), + )), + ) as _i12.Future<_i6.ChatwootContact>); + + @override + _i12.Future> getConversations() => + (super.noSuchMethod( + Invocation.method( + #getConversations, + [], + ), + returnValue: _i12.Future>.value( + <_i14.ChatwootConversation>[]), + ) as _i12.Future>); + + @override + _i12.Future<_i7.ChatwootMessage> createMessage( + _i15.ChatwootNewMessageRequest? request) => + (super.noSuchMethod( + Invocation.method( + #createMessage, + [request], + ), + returnValue: + _i12.Future<_i7.ChatwootMessage>.value(_FakeChatwootMessage_5( + this, + Invocation.method( + #createMessage, + [request], + ), + )), + ) as _i12.Future<_i7.ChatwootMessage>); + + @override + _i12.Future<_i7.ChatwootMessage> updateMessage( + String? messageIdentifier, + dynamic update, + ) => + (super.noSuchMethod( + Invocation.method( + #updateMessage, + [ + messageIdentifier, + update, + ], + ), + returnValue: + _i12.Future<_i7.ChatwootMessage>.value(_FakeChatwootMessage_5( + this, + Invocation.method( + #updateMessage, + [ + messageIdentifier, + update, + ], + ), + )), + ) as _i12.Future<_i7.ChatwootMessage>); + + @override + _i12.Future<_i8.CsatSurveyFeedbackResponse> sendCsatFeedBack( + String? conversationUuid, + _i16.SendCsatSurveyRequest? request, + ) => (super.noSuchMethod( - Invocation.method(#updateMessage, [messageIdentifier, update]), - returnValue: - Future<_i7.ChatwootMessage>.value(_FakeChatwootMessage_5())) - as _i11.Future<_i7.ChatwootMessage>); - @override - _i11.Future> getAllMessages() => - (super.noSuchMethod(Invocation.method(#getAllMessages, []), - returnValue: Future>.value( - <_i7.ChatwootMessage>[])) - as _i11.Future>); - @override - void startWebSocketConnection(String? contactPubsubToken, - {_i8.WebSocketChannel Function(Uri)? onStartConnection}) => + Invocation.method( + #sendCsatFeedBack, + [ + conversationUuid, + request, + ], + ), + returnValue: _i12.Future<_i8.CsatSurveyFeedbackResponse>.value( + _FakeCsatSurveyFeedbackResponse_6( + this, + Invocation.method( + #sendCsatFeedBack, + [ + conversationUuid, + request, + ], + ), + )), + ) as _i12.Future<_i8.CsatSurveyFeedbackResponse>); + + @override + _i12.Future<_i8.CsatSurveyFeedbackResponse?> getCsatFeedback( + String? conversationUuid) => + (super.noSuchMethod( + Invocation.method( + #getCsatFeedback, + [conversationUuid], + ), + returnValue: _i12.Future<_i8.CsatSurveyFeedbackResponse?>.value(), + ) as _i12.Future<_i8.CsatSurveyFeedbackResponse?>); + + @override + _i12.Future> getAllMessages() => + (super.noSuchMethod( + Invocation.method( + #getAllMessages, + [], + ), + returnValue: _i12.Future>.value( + <_i7.ChatwootMessage>[]), + ) as _i12.Future>); + + @override + void startWebSocketConnection( + String? contactPubsubToken, { + _i9.WebSocketChannel Function(Uri)? onStartConnection, + }) => super.noSuchMethod( - Invocation.method(#startWebSocketConnection, [contactPubsubToken], - {#onStartConnection: onStartConnection}), - returnValueForMissingStub: null); + Invocation.method( + #startWebSocketConnection, + [contactPubsubToken], + {#onStartConnection: onStartConnection}, + ), + returnValueForMissingStub: null, + ); + @override void sendAction( - String? contactPubsubToken, _i15.ChatwootActionType? action) => + String? contactPubsubToken, + _i17.ChatwootActionType? action, + ) => super.noSuchMethod( - Invocation.method(#sendAction, [contactPubsubToken, action]), - returnValueForMissingStub: null); - @override - String toString() => super.toString(); + Invocation.method( + #sendAction, + [ + contactPubsubToken, + action, + ], + ), + returnValueForMissingStub: null, + ); } /// A class which mocks [ChatwootCallbacks]. /// /// See the documentation for Mockito's code generation for more information. -class MockChatwootCallbacks extends _i1.Mock implements _i16.ChatwootCallbacks { +class MockChatwootCallbacks extends _i1.Mock implements _i18.ChatwootCallbacks { MockChatwootCallbacks() { _i1.throwOnMissingStub(this); } @override - set onWelcome(void Function()? _onWelcome) => - super.noSuchMethod(Invocation.setter(#onWelcome, _onWelcome), - returnValueForMissingStub: null); + set onWelcome(void Function()? _onWelcome) => super.noSuchMethod( + Invocation.setter( + #onWelcome, + _onWelcome, + ), + returnValueForMissingStub: null, + ); + @override - set onPing(void Function()? _onPing) => - super.noSuchMethod(Invocation.setter(#onPing, _onPing), - returnValueForMissingStub: null); + set onPing(void Function()? _onPing) => super.noSuchMethod( + Invocation.setter( + #onPing, + _onPing, + ), + returnValueForMissingStub: null, + ); + @override set onConfirmedSubscription(void Function()? _onConfirmedSubscription) => super.noSuchMethod( - Invocation.setter(#onConfirmedSubscription, _onConfirmedSubscription), - returnValueForMissingStub: null); + Invocation.setter( + #onConfirmedSubscription, + _onConfirmedSubscription, + ), + returnValueForMissingStub: null, + ); + @override set onConversationStartedTyping( void Function()? _onConversationStartedTyping) => super.noSuchMethod( - Invocation.setter( - #onConversationStartedTyping, _onConversationStartedTyping), - returnValueForMissingStub: null); + Invocation.setter( + #onConversationStartedTyping, + _onConversationStartedTyping, + ), + returnValueForMissingStub: null, + ); + @override set onConversationIsOnline(void Function()? _onConversationIsOnline) => super.noSuchMethod( - Invocation.setter(#onConversationIsOnline, _onConversationIsOnline), - returnValueForMissingStub: null); + Invocation.setter( + #onConversationIsOnline, + _onConversationIsOnline, + ), + returnValueForMissingStub: null, + ); + @override set onConversationIsOffline(void Function()? _onConversationIsOffline) => super.noSuchMethod( - Invocation.setter(#onConversationIsOffline, _onConversationIsOffline), - returnValueForMissingStub: null); + Invocation.setter( + #onConversationIsOffline, + _onConversationIsOffline, + ), + returnValueForMissingStub: null, + ); + @override set onConversationStoppedTyping( void Function()? _onConversationStoppedTyping) => super.noSuchMethod( - Invocation.setter( - #onConversationStoppedTyping, _onConversationStoppedTyping), - returnValueForMissingStub: null); + Invocation.setter( + #onConversationStoppedTyping, + _onConversationStoppedTyping, + ), + returnValueForMissingStub: null, + ); + @override set onMessageReceived( void Function(_i7.ChatwootMessage)? _onMessageReceived) => super.noSuchMethod( - Invocation.setter(#onMessageReceived, _onMessageReceived), - returnValueForMissingStub: null); + Invocation.setter( + #onMessageReceived, + _onMessageReceived, + ), + returnValueForMissingStub: null, + ); + @override set onMessageUpdated(void Function(_i7.ChatwootMessage)? _onMessageUpdated) => super.noSuchMethod( - Invocation.setter(#onMessageUpdated, _onMessageUpdated), - returnValueForMissingStub: null); + Invocation.setter( + #onMessageUpdated, + _onMessageUpdated, + ), + returnValueForMissingStub: null, + ); + @override set onMessageSent( - void Function(_i7.ChatwootMessage, String)? _onMessageSent) => - super.noSuchMethod(Invocation.setter(#onMessageSent, _onMessageSent), - returnValueForMissingStub: null); + void Function( + _i7.ChatwootMessage, + String, + )? _onMessageSent) => + super.noSuchMethod( + Invocation.setter( + #onMessageSent, + _onMessageSent, + ), + returnValueForMissingStub: null, + ); + @override set onMessageDelivered( - void Function(_i7.ChatwootMessage, String)? _onMessageDelivered) => + void Function( + _i7.ChatwootMessage, + String, + )? _onMessageDelivered) => super.noSuchMethod( - Invocation.setter(#onMessageDelivered, _onMessageDelivered), - returnValueForMissingStub: null); + Invocation.setter( + #onMessageDelivered, + _onMessageDelivered, + ), + returnValueForMissingStub: null, + ); + @override set onPersistedMessagesRetrieved( void Function(List<_i7.ChatwootMessage>)? _onPersistedMessagesRetrieved) => super.noSuchMethod( - Invocation.setter( - #onPersistedMessagesRetrieved, _onPersistedMessagesRetrieved), - returnValueForMissingStub: null); + Invocation.setter( + #onPersistedMessagesRetrieved, + _onPersistedMessagesRetrieved, + ), + returnValueForMissingStub: null, + ); + @override set onMessagesRetrieved( void Function(List<_i7.ChatwootMessage>)? _onMessagesRetrieved) => super.noSuchMethod( - Invocation.setter(#onMessagesRetrieved, _onMessagesRetrieved), - returnValueForMissingStub: null); + Invocation.setter( + #onMessagesRetrieved, + _onMessagesRetrieved, + ), + returnValueForMissingStub: null, + ); + @override - set onConversationResolved(void Function()? _onConversationResolved) => + set onConversationResolved(void Function(String)? _onConversationResolved) => super.noSuchMethod( - Invocation.setter(#onConversationResolved, _onConversationResolved), - returnValueForMissingStub: null); + Invocation.setter( + #onConversationResolved, + _onConversationResolved, + ), + returnValueForMissingStub: null, + ); + @override - set onError(void Function(_i17.ChatwootClientException)? _onError) => - super.noSuchMethod(Invocation.setter(#onError, _onError), - returnValueForMissingStub: null); + set onCsatSurveyResponseRecorded( + void Function(_i8.CsatSurveyFeedbackResponse)? + _onCsatSurveyResponseRecorded) => + super.noSuchMethod( + Invocation.setter( + #onCsatSurveyResponseRecorded, + _onCsatSurveyResponseRecorded, + ), + returnValueForMissingStub: null, + ); + @override - String toString() => super.toString(); + set onError(void Function(_i19.ChatwootClientException)? _onError) => + super.noSuchMethod( + Invocation.setter( + #onError, + _onError, + ), + returnValueForMissingStub: null, + ); } /// A class which mocks [WebSocketChannel]. /// /// See the documentation for Mockito's code generation for more information. -class MockWebSocketChannel extends _i1.Mock implements _i8.WebSocketChannel { +class MockWebSocketChannel extends _i1.Mock implements _i9.WebSocketChannel { MockWebSocketChannel() { _i1.throwOnMissingStub(this); } @override - _i11.Stream get stream => - (super.noSuchMethod(Invocation.getter(#stream), - returnValue: Stream.empty()) as _i11.Stream); + _i12.Future get ready => (super.noSuchMethod( + Invocation.getter(#ready), + returnValue: _i12.Future.value(), + ) as _i12.Future); + @override - _i8.WebSocketSink get sink => (super.noSuchMethod(Invocation.getter(#sink), - returnValue: _FakeWebSocketSink_6()) as _i8.WebSocketSink); + _i9.WebSocketSink get sink => (super.noSuchMethod( + Invocation.getter(#sink), + returnValue: _FakeWebSocketSink_7( + this, + Invocation.getter(#sink), + ), + ) as _i9.WebSocketSink); + @override - void pipe(_i9.StreamChannel? other) => - super.noSuchMethod(Invocation.method(#pipe, [other]), - returnValueForMissingStub: null); + _i12.Stream get stream => (super.noSuchMethod( + Invocation.getter(#stream), + returnValue: _i12.Stream.empty(), + ) as _i12.Stream); + + @override + void pipe(_i10.StreamChannel? other) => super.noSuchMethod( + Invocation.method( + #pipe, + [other], + ), + returnValueForMissingStub: null, + ); + @override - _i9.StreamChannel transform( - _i9.StreamChannelTransformer? transformer) => - (super.noSuchMethod(Invocation.method(#transform, [transformer]), - returnValue: _FakeStreamChannel_7()) as _i9.StreamChannel); + _i10.StreamChannel transform( + _i10.StreamChannelTransformer? transformer) => + (super.noSuchMethod( + Invocation.method( + #transform, + [transformer], + ), + returnValue: _FakeStreamChannel_8( + this, + Invocation.method( + #transform, + [transformer], + ), + ), + ) as _i10.StreamChannel); + @override - _i9.StreamChannel transformStream( - _i11.StreamTransformer? transformer) => - (super.noSuchMethod(Invocation.method(#transformStream, [transformer]), - returnValue: _FakeStreamChannel_7()) - as _i9.StreamChannel); + _i10.StreamChannel transformStream( + _i12.StreamTransformer? transformer) => + (super.noSuchMethod( + Invocation.method( + #transformStream, + [transformer], + ), + returnValue: _FakeStreamChannel_8( + this, + Invocation.method( + #transformStream, + [transformer], + ), + ), + ) as _i10.StreamChannel); + @override - _i9.StreamChannel transformSink( - _i18.StreamSinkTransformer? transformer) => - (super.noSuchMethod(Invocation.method(#transformSink, [transformer]), - returnValue: _FakeStreamChannel_7()) - as _i9.StreamChannel); + _i10.StreamChannel transformSink( + _i20.StreamSinkTransformer? transformer) => + (super.noSuchMethod( + Invocation.method( + #transformSink, + [transformer], + ), + returnValue: _FakeStreamChannel_8( + this, + Invocation.method( + #transformSink, + [transformer], + ), + ), + ) as _i10.StreamChannel); + @override - _i9.StreamChannel changeStream( - _i11.Stream Function(_i11.Stream)? change) => - (super.noSuchMethod(Invocation.method(#changeStream, [change]), - returnValue: _FakeStreamChannel_7()) - as _i9.StreamChannel); + _i10.StreamChannel changeStream( + _i12.Stream Function(_i12.Stream)? change) => + (super.noSuchMethod( + Invocation.method( + #changeStream, + [change], + ), + returnValue: _FakeStreamChannel_8( + this, + Invocation.method( + #changeStream, + [change], + ), + ), + ) as _i10.StreamChannel); + @override - _i9.StreamChannel changeSink( - _i11.StreamSink Function(_i11.StreamSink)? + _i10.StreamChannel changeSink( + _i12.StreamSink Function(_i12.StreamSink)? change) => - (super.noSuchMethod(Invocation.method(#changeSink, [change]), - returnValue: _FakeStreamChannel_7()) - as _i9.StreamChannel); - @override - _i9.StreamChannel cast() => - (super.noSuchMethod(Invocation.method(#cast, []), - returnValue: _FakeStreamChannel_7()) as _i9.StreamChannel); + (super.noSuchMethod( + Invocation.method( + #changeSink, + [change], + ), + returnValue: _FakeStreamChannel_8( + this, + Invocation.method( + #changeSink, + [change], + ), + ), + ) as _i10.StreamChannel); + @override - String toString() => super.toString(); + _i10.StreamChannel cast() => (super.noSuchMethod( + Invocation.method( + #cast, + [], + ), + returnValue: _FakeStreamChannel_8( + this, + Invocation.method( + #cast, + [], + ), + ), + ) as _i10.StreamChannel); } diff --git a/test/data/local/local_storage_test.dart b/test/data/local/local_storage_test.dart index f260f91..70759b4 100644 --- a/test/data/local/local_storage_test.dart +++ b/test/data/local/local_storage_test.dart @@ -43,7 +43,8 @@ void main() { ..registerAdapter(ChatwootContactAdapter()) ..registerAdapter(ChatwootConversationAdapter()) ..registerAdapter(ChatwootMessageAdapter()) - ..registerAdapter(ChatwootUserAdapter()); + ..registerAdapter(ChatwootUserAdapter()) + ..registerAdapter(ChatwootMessageAttachmentAdapter()); localStorage = LocalStorage( userDao: mockUserDao, diff --git a/test/data/local/local_storage_test.mocks.dart b/test/data/local/local_storage_test.mocks.dart index 40a89d9..29ff6f7 100644 --- a/test/data/local/local_storage_test.mocks.dart +++ b/test/data/local/local_storage_test.mocks.dart @@ -1,7 +1,8 @@ -// Mocks generated by Mockito 5.0.15 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in chatwoot_sdk/test/data/local/local_storage_test.dart. // Do not manually edit this file. +// ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i3; import 'package:chatwoot_sdk/data/local/dao/chatwoot_contact_dao.dart' as _i5; @@ -16,13 +17,18 @@ import 'package:chatwoot_sdk/data/local/entity/chatwoot_message.dart' as _i8; import 'package:chatwoot_sdk/data/local/entity/chatwoot_user.dart' as _i10; import 'package:mockito/mockito.dart' as _i1; +// ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class /// A class which mocks [ChatwootConversationDao]. /// @@ -35,26 +41,44 @@ class MockChatwootConversationDao extends _i1.Mock @override _i3.Future saveConversation(_i4.ChatwootConversation? conversation) => - (super.noSuchMethod(Invocation.method(#saveConversation, [conversation]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); - @override - _i3.Future deleteConversation() => - (super.noSuchMethod(Invocation.method(#deleteConversation, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); - @override - _i3.Future onDispose() => - (super.noSuchMethod(Invocation.method(#onDispose, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); - @override - _i3.Future clearAll() => - (super.noSuchMethod(Invocation.method(#clearAll, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); - @override - String toString() => super.toString(); + (super.noSuchMethod( + Invocation.method( + #saveConversation, + [conversation], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future deleteConversation() => (super.noSuchMethod( + Invocation.method( + #deleteConversation, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future onDispose() => (super.noSuchMethod( + Invocation.method( + #onDispose, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future clearAll() => (super.noSuchMethod( + Invocation.method( + #clearAll, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); } /// A class which mocks [ChatwootContactDao]. @@ -68,26 +92,44 @@ class MockChatwootContactDao extends _i1.Mock @override _i3.Future saveContact(_i6.ChatwootContact? contact) => - (super.noSuchMethod(Invocation.method(#saveContact, [contact]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); - @override - _i3.Future deleteContact() => - (super.noSuchMethod(Invocation.method(#deleteContact, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); - @override - _i3.Future onDispose() => - (super.noSuchMethod(Invocation.method(#onDispose, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); - @override - _i3.Future clearAll() => - (super.noSuchMethod(Invocation.method(#clearAll, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); - @override - String toString() => super.toString(); + (super.noSuchMethod( + Invocation.method( + #saveContact, + [contact], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future deleteContact() => (super.noSuchMethod( + Invocation.method( + #deleteContact, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future onDispose() => (super.noSuchMethod( + Invocation.method( + #onDispose, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future clearAll() => (super.noSuchMethod( + Invocation.method( + #clearAll, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); } /// A class which mocks [ChatwootMessagesDao]. @@ -101,43 +143,81 @@ class MockChatwootMessagesDao extends _i1.Mock @override _i3.Future saveMessage(_i8.ChatwootMessage? message) => - (super.noSuchMethod(Invocation.method(#saveMessage, [message]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + (super.noSuchMethod( + Invocation.method( + #saveMessage, + [message], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override _i3.Future saveAllMessages(List<_i8.ChatwootMessage>? messages) => - (super.noSuchMethod(Invocation.method(#saveAllMessages, [messages]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + (super.noSuchMethod( + Invocation.method( + #saveAllMessages, + [messages], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override _i8.ChatwootMessage? getMessage(int? messageId) => - (super.noSuchMethod(Invocation.method(#getMessage, [messageId])) - as _i8.ChatwootMessage?); - @override - List<_i8.ChatwootMessage> getMessages() => - (super.noSuchMethod(Invocation.method(#getMessages, []), - returnValue: <_i8.ChatwootMessage>[]) as List<_i8.ChatwootMessage>); + (super.noSuchMethod(Invocation.method( + #getMessage, + [messageId], + )) as _i8.ChatwootMessage?); + @override - _i3.Future clear() => (super.noSuchMethod(Invocation.method(#clear, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + List<_i8.ChatwootMessage> getMessages() => (super.noSuchMethod( + Invocation.method( + #getMessages, + [], + ), + returnValue: <_i8.ChatwootMessage>[], + ) as List<_i8.ChatwootMessage>); + @override - _i3.Future deleteMessage(int? messageId) => - (super.noSuchMethod(Invocation.method(#deleteMessage, [messageId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future clear() => (super.noSuchMethod( + Invocation.method( + #clear, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - _i3.Future onDispose() => - (super.noSuchMethod(Invocation.method(#onDispose, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future deleteMessage(int? messageId) => (super.noSuchMethod( + Invocation.method( + #deleteMessage, + [messageId], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - _i3.Future clearAll() => - (super.noSuchMethod(Invocation.method(#clearAll, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future onDispose() => (super.noSuchMethod( + Invocation.method( + #onDispose, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - String toString() => super.toString(); + _i3.Future clearAll() => (super.noSuchMethod( + Invocation.method( + #clearAll, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); } /// A class which mocks [PersistedChatwootConversationDao]. @@ -150,27 +230,45 @@ class MockPersistedChatwootConversationDao extends _i1.Mock } @override - _i3.Future deleteConversation() => - (super.noSuchMethod(Invocation.method(#deleteConversation, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future deleteConversation() => (super.noSuchMethod( + Invocation.method( + #deleteConversation, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override _i3.Future saveConversation(_i4.ChatwootConversation? conversation) => - (super.noSuchMethod(Invocation.method(#saveConversation, [conversation]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); - @override - _i3.Future onDispose() => - (super.noSuchMethod(Invocation.method(#onDispose, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + (super.noSuchMethod( + Invocation.method( + #saveConversation, + [conversation], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - _i3.Future clearAll() => - (super.noSuchMethod(Invocation.method(#clearAll, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future onDispose() => (super.noSuchMethod( + Invocation.method( + #onDispose, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - String toString() => super.toString(); + _i3.Future clearAll() => (super.noSuchMethod( + Invocation.method( + #clearAll, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); } /// A class which mocks [PersistedChatwootContactDao]. @@ -183,27 +281,45 @@ class MockPersistedChatwootContactDao extends _i1.Mock } @override - _i3.Future deleteContact() => - (super.noSuchMethod(Invocation.method(#deleteContact, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future deleteContact() => (super.noSuchMethod( + Invocation.method( + #deleteContact, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override _i3.Future saveContact(_i6.ChatwootContact? contact) => - (super.noSuchMethod(Invocation.method(#saveContact, [contact]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); - @override - _i3.Future onDispose() => - (super.noSuchMethod(Invocation.method(#onDispose, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + (super.noSuchMethod( + Invocation.method( + #saveContact, + [contact], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - _i3.Future clearAll() => - (super.noSuchMethod(Invocation.method(#clearAll, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future onDispose() => (super.noSuchMethod( + Invocation.method( + #onDispose, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - String toString() => super.toString(); + _i3.Future clearAll() => (super.noSuchMethod( + Invocation.method( + #clearAll, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); } /// A class which mocks [PersistedChatwootMessagesDao]. @@ -216,44 +332,82 @@ class MockPersistedChatwootMessagesDao extends _i1.Mock } @override - _i3.Future clear() => (super.noSuchMethod(Invocation.method(#clear, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future clear() => (super.noSuchMethod( + Invocation.method( + #clear, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override _i3.Future saveMessage(_i8.ChatwootMessage? message) => - (super.noSuchMethod(Invocation.method(#saveMessage, [message]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + (super.noSuchMethod( + Invocation.method( + #saveMessage, + [message], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override _i3.Future saveAllMessages(List<_i8.ChatwootMessage>? messages) => - (super.noSuchMethod(Invocation.method(#saveAllMessages, [messages]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + (super.noSuchMethod( + Invocation.method( + #saveAllMessages, + [messages], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - List<_i8.ChatwootMessage> getMessages() => - (super.noSuchMethod(Invocation.method(#getMessages, []), - returnValue: <_i8.ChatwootMessage>[]) as List<_i8.ChatwootMessage>); + List<_i8.ChatwootMessage> getMessages() => (super.noSuchMethod( + Invocation.method( + #getMessages, + [], + ), + returnValue: <_i8.ChatwootMessage>[], + ) as List<_i8.ChatwootMessage>); + @override - _i3.Future onDispose() => - (super.noSuchMethod(Invocation.method(#onDispose, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future onDispose() => (super.noSuchMethod( + Invocation.method( + #onDispose, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - _i3.Future deleteMessage(int? messageId) => - (super.noSuchMethod(Invocation.method(#deleteMessage, [messageId]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future deleteMessage(int? messageId) => (super.noSuchMethod( + Invocation.method( + #deleteMessage, + [messageId], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override _i8.ChatwootMessage? getMessage(int? messageId) => - (super.noSuchMethod(Invocation.method(#getMessage, [messageId])) - as _i8.ChatwootMessage?); - @override - _i3.Future clearAll() => - (super.noSuchMethod(Invocation.method(#clearAll, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + (super.noSuchMethod(Invocation.method( + #getMessage, + [messageId], + )) as _i8.ChatwootMessage?); + @override - String toString() => super.toString(); + _i3.Future clearAll() => (super.noSuchMethod( + Invocation.method( + #clearAll, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); } /// A class which mocks [ChatwootUserDao]. @@ -265,27 +419,44 @@ class MockChatwootUserDao extends _i1.Mock implements _i9.ChatwootUserDao { } @override - _i3.Future saveUser(_i10.ChatwootUser? user) => - (super.noSuchMethod(Invocation.method(#saveUser, [user]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); - @override - _i3.Future deleteUser() => - (super.noSuchMethod(Invocation.method(#deleteUser, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future saveUser(_i10.ChatwootUser? user) => (super.noSuchMethod( + Invocation.method( + #saveUser, + [user], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - _i3.Future onDispose() => - (super.noSuchMethod(Invocation.method(#onDispose, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future deleteUser() => (super.noSuchMethod( + Invocation.method( + #deleteUser, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - _i3.Future clearAll() => - (super.noSuchMethod(Invocation.method(#clearAll, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future onDispose() => (super.noSuchMethod( + Invocation.method( + #onDispose, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - String toString() => super.toString(); + _i3.Future clearAll() => (super.noSuchMethod( + Invocation.method( + #clearAll, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); } /// A class which mocks [PersistedChatwootUserDao]. @@ -298,25 +469,42 @@ class MockPersistedChatwootUserDao extends _i1.Mock } @override - _i3.Future deleteUser() => - (super.noSuchMethod(Invocation.method(#deleteUser, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); - @override - _i3.Future saveUser(_i10.ChatwootUser? user) => - (super.noSuchMethod(Invocation.method(#saveUser, [user]), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future deleteUser() => (super.noSuchMethod( + Invocation.method( + #deleteUser, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - _i3.Future onDispose() => - (super.noSuchMethod(Invocation.method(#onDispose, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future saveUser(_i10.ChatwootUser? user) => (super.noSuchMethod( + Invocation.method( + #saveUser, + [user], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - _i3.Future clearAll() => - (super.noSuchMethod(Invocation.method(#clearAll, []), - returnValue: Future.value(), - returnValueForMissingStub: Future.value()) as _i3.Future); + _i3.Future onDispose() => (super.noSuchMethod( + Invocation.method( + #onDispose, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override - String toString() => super.toString(); + _i3.Future clearAll() => (super.noSuchMethod( + Invocation.method( + #clearAll, + [], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); } diff --git a/test/data/remote/chatwoot_client_api_interceptor_test.mocks.dart b/test/data/remote/chatwoot_client_api_interceptor_test.mocks.dart index 87098a9..d0b241d 100644 --- a/test/data/remote/chatwoot_client_api_interceptor_test.mocks.dart +++ b/test/data/remote/chatwoot_client_api_interceptor_test.mocks.dart @@ -1,7 +1,8 @@ -// Mocks generated by Mockito 5.0.15 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in chatwoot_sdk/test/data/remote/chatwoot_client_api_interceptor_test.dart. // Do not manually edit this file. +// ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i7; import 'package:chatwoot_sdk/data/local/entity/chatwoot_contact.dart' as _i4; @@ -12,30 +13,68 @@ import 'package:chatwoot_sdk/data/remote/service/chatwoot_client_auth_service.da as _i11; import 'package:dio/dio.dart' as _i6; import 'package:dio/src/dio.dart' as _i3; -import 'package:dio/src/dio_error.dart' as _i9; +import 'package:dio/src/dio_exception.dart' as _i9; import 'package:dio/src/dio_mixin.dart' as _i2; import 'package:dio/src/options.dart' as _i10; import 'package:dio/src/response.dart' as _i8; import 'package:mockito/mockito.dart' as _i1; import 'package:web_socket_channel/web_socket_channel.dart' as _i12; +// ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class -class _FakeInterceptorState_0 extends _i1.Fake - implements _i2.InterceptorState {} +class _FakeInterceptorState_0 extends _i1.SmartFake + implements _i2.InterceptorState { + _FakeInterceptorState_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeDio_1 extends _i1.Fake implements _i3.Dio {} +class _FakeDio_1 extends _i1.SmartFake implements _i3.Dio { + _FakeDio_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeChatwootContact_2 extends _i1.Fake implements _i4.ChatwootContact {} +class _FakeChatwootContact_2 extends _i1.SmartFake + implements _i4.ChatwootContact { + _FakeChatwootContact_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeChatwootConversation_3 extends _i1.Fake - implements _i5.ChatwootConversation {} +class _FakeChatwootConversation_3 extends _i1.SmartFake + implements _i5.ChatwootConversation { + _FakeChatwootConversation_3( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} /// A class which mocks [ResponseInterceptorHandler]. /// @@ -47,31 +86,54 @@ class MockResponseInterceptorHandler extends _i1.Mock } @override - _i7.Future<_i2.InterceptorState> get future => - (super.noSuchMethod(Invocation.getter(#future), - returnValue: Future<_i2.InterceptorState>.value( - _FakeInterceptorState_0())) - as _i7.Future<_i2.InterceptorState>); + _i7.Future<_i2.InterceptorState> get future => (super.noSuchMethod( + Invocation.getter(#future), + returnValue: _i7.Future<_i2.InterceptorState>.value( + _FakeInterceptorState_0( + this, + Invocation.getter(#future), + )), + ) as _i7.Future<_i2.InterceptorState>); + @override - bool get isCompleted => - (super.noSuchMethod(Invocation.getter(#isCompleted), returnValue: false) - as bool); + bool get isCompleted => (super.noSuchMethod( + Invocation.getter(#isCompleted), + returnValue: false, + ) as bool); + @override - void next(_i8.Response? response) => - super.noSuchMethod(Invocation.method(#next, [response]), - returnValueForMissingStub: null); + void next(_i8.Response? response) => super.noSuchMethod( + Invocation.method( + #next, + [response], + ), + returnValueForMissingStub: null, + ); + @override - void resolve(_i8.Response? response) => - super.noSuchMethod(Invocation.method(#resolve, [response]), - returnValueForMissingStub: null); + void resolve(_i8.Response? response) => super.noSuchMethod( + Invocation.method( + #resolve, + [response], + ), + returnValueForMissingStub: null, + ); + @override - void reject(_i9.DioError? error, - [bool? callFollowingErrorInterceptor = false]) => + void reject( + _i9.DioException? error, [ + bool? callFollowingErrorInterceptor = false, + ]) => super.noSuchMethod( - Invocation.method(#reject, [error, callFollowingErrorInterceptor]), - returnValueForMissingStub: null); - @override - String toString() => super.toString(); + Invocation.method( + #reject, + [ + error, + callFollowingErrorInterceptor, + ], + ), + returnValueForMissingStub: null, + ); } /// A class which mocks [RequestInterceptorHandler]. @@ -84,34 +146,61 @@ class MockRequestInterceptorHandler extends _i1.Mock } @override - _i7.Future<_i2.InterceptorState> get future => - (super.noSuchMethod(Invocation.getter(#future), - returnValue: Future<_i2.InterceptorState>.value( - _FakeInterceptorState_0())) - as _i7.Future<_i2.InterceptorState>); + _i7.Future<_i2.InterceptorState> get future => (super.noSuchMethod( + Invocation.getter(#future), + returnValue: _i7.Future<_i2.InterceptorState>.value( + _FakeInterceptorState_0( + this, + Invocation.getter(#future), + )), + ) as _i7.Future<_i2.InterceptorState>); + @override - bool get isCompleted => - (super.noSuchMethod(Invocation.getter(#isCompleted), returnValue: false) - as bool); + bool get isCompleted => (super.noSuchMethod( + Invocation.getter(#isCompleted), + returnValue: false, + ) as bool); + @override - void next(_i10.RequestOptions? requestOptions) => - super.noSuchMethod(Invocation.method(#next, [requestOptions]), - returnValueForMissingStub: null); + void next(_i10.RequestOptions? requestOptions) => super.noSuchMethod( + Invocation.method( + #next, + [requestOptions], + ), + returnValueForMissingStub: null, + ); + @override - void resolve(_i8.Response? response, - [bool? callFollowingResponseInterceptor = false]) => + void resolve( + _i8.Response? response, [ + bool? callFollowingResponseInterceptor = false, + ]) => super.noSuchMethod( - Invocation.method( - #resolve, [response, callFollowingResponseInterceptor]), - returnValueForMissingStub: null); + Invocation.method( + #resolve, + [ + response, + callFollowingResponseInterceptor, + ], + ), + returnValueForMissingStub: null, + ); + @override - void reject(_i9.DioError? error, - [bool? callFollowingErrorInterceptor = false]) => + void reject( + _i9.DioException? error, [ + bool? callFollowingErrorInterceptor = false, + ]) => super.noSuchMethod( - Invocation.method(#reject, [error, callFollowingErrorInterceptor]), - returnValueForMissingStub: null); - @override - String toString() => super.toString(); + Invocation.method( + #reject, + [ + error, + callFollowingErrorInterceptor, + ], + ), + returnValueForMissingStub: null, + ); } /// A class which mocks [ChatwootClientAuthService]. @@ -124,30 +213,72 @@ class MockChatwootClientAuthService extends _i1.Mock } @override - set connection(_i12.WebSocketChannel? _connection) => - super.noSuchMethod(Invocation.setter(#connection, _connection), - returnValueForMissingStub: null); + set connection(_i12.WebSocketChannel? _connection) => super.noSuchMethod( + Invocation.setter( + #connection, + _connection, + ), + returnValueForMissingStub: null, + ); + @override - _i3.Dio get dio => - (super.noSuchMethod(Invocation.getter(#dio), returnValue: _FakeDio_1()) - as _i3.Dio); + _i3.Dio get dio => (super.noSuchMethod( + Invocation.getter(#dio), + returnValue: _FakeDio_1( + this, + Invocation.getter(#dio), + ), + ) as _i3.Dio); + @override _i7.Future<_i4.ChatwootContact> createNewContact( - String? inboxIdentifier, _i13.ChatwootUser? user) => + String? inboxIdentifier, + _i13.ChatwootUser? user, + ) => (super.noSuchMethod( - Invocation.method(#createNewContact, [inboxIdentifier, user]), - returnValue: - Future<_i4.ChatwootContact>.value(_FakeChatwootContact_2())) - as _i7.Future<_i4.ChatwootContact>); + Invocation.method( + #createNewContact, + [ + inboxIdentifier, + user, + ], + ), + returnValue: + _i7.Future<_i4.ChatwootContact>.value(_FakeChatwootContact_2( + this, + Invocation.method( + #createNewContact, + [ + inboxIdentifier, + user, + ], + ), + )), + ) as _i7.Future<_i4.ChatwootContact>); + @override _i7.Future<_i5.ChatwootConversation> createNewConversation( - String? inboxIdentifier, String? contactIdentifier) => + String? inboxIdentifier, + String? contactIdentifier, + ) => (super.noSuchMethod( - Invocation.method( - #createNewConversation, [inboxIdentifier, contactIdentifier]), - returnValue: Future<_i5.ChatwootConversation>.value( - _FakeChatwootConversation_3())) - as _i7.Future<_i5.ChatwootConversation>); - @override - String toString() => super.toString(); + Invocation.method( + #createNewConversation, + [ + inboxIdentifier, + contactIdentifier, + ], + ), + returnValue: _i7.Future<_i5.ChatwootConversation>.value( + _FakeChatwootConversation_3( + this, + Invocation.method( + #createNewConversation, + [ + inboxIdentifier, + contactIdentifier, + ], + ), + )), + ) as _i7.Future<_i5.ChatwootConversation>); } diff --git a/test/data/remote/chatwoot_client_auth_service_test.dart b/test/data/remote/chatwoot_client_auth_service_test.dart index b747316..d16b935 100644 --- a/test/data/remote/chatwoot_client_auth_service_test.dart +++ b/test/data/remote/chatwoot_client_auth_service_test.dart @@ -86,7 +86,7 @@ void main() { 'Given contact creation fails when createNewContact is called, then throw error', () async { //GIVEN - final testError = DioError(requestOptions: RequestOptions(path: "")); + final testError = DioException(requestOptions: RequestOptions(path: "")); when(mockDio.post(any, data: testUser.toJson())).thenThrow(testError); //WHEN @@ -146,7 +146,7 @@ void main() { 'Given conversation creation fails when createNewConversation is called, then throw error', () async { //GIVEN - final testError = DioError(requestOptions: RequestOptions(path: "")); + final testError = DioException(requestOptions: RequestOptions(path: "")); when(mockDio.post(any)).thenThrow(testError); //WHEN diff --git a/test/data/remote/chatwoot_client_auth_service_test.mocks.dart b/test/data/remote/chatwoot_client_auth_service_test.mocks.dart index 3de2827..d966aca 100644 --- a/test/data/remote/chatwoot_client_auth_service_test.mocks.dart +++ b/test/data/remote/chatwoot_client_auth_service_test.mocks.dart @@ -1,7 +1,8 @@ -// Mocks generated by Mockito 5.0.15 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in chatwoot_sdk/test/data/remote/chatwoot_client_auth_service_test.dart. // Do not manually edit this file. +// ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i8; import 'package:dio/src/adapter.dart' as _i3; @@ -13,24 +14,69 @@ import 'package:dio/src/response.dart' as _i6; import 'package:dio/src/transformer.dart' as _i4; import 'package:mockito/mockito.dart' as _i1; +// ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class -class _FakeBaseOptions_0 extends _i1.Fake implements _i2.BaseOptions {} +class _FakeBaseOptions_0 extends _i1.SmartFake implements _i2.BaseOptions { + _FakeBaseOptions_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeHttpClientAdapter_1 extends _i1.Fake - implements _i3.HttpClientAdapter {} +class _FakeHttpClientAdapter_1 extends _i1.SmartFake + implements _i3.HttpClientAdapter { + _FakeHttpClientAdapter_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeTransformer_2 extends _i1.Fake implements _i4.Transformer {} +class _FakeTransformer_2 extends _i1.SmartFake implements _i4.Transformer { + _FakeTransformer_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeInterceptors_3 extends _i1.Fake implements _i5.Interceptors {} +class _FakeInterceptors_3 extends _i1.SmartFake implements _i5.Interceptors { + _FakeInterceptors_3( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeResponse_4 extends _i1.Fake implements _i6.Response {} +class _FakeResponse_4 extends _i1.SmartFake implements _i6.Response { + _FakeResponse_4( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} /// A class which mocks [Dio]. /// @@ -41,341 +87,700 @@ class MockDio extends _i1.Mock implements _i7.Dio { } @override - _i2.BaseOptions get options => - (super.noSuchMethod(Invocation.getter(#options), - returnValue: _FakeBaseOptions_0()) as _i2.BaseOptions); + _i2.BaseOptions get options => (super.noSuchMethod( + Invocation.getter(#options), + returnValue: _FakeBaseOptions_0( + this, + Invocation.getter(#options), + ), + ) as _i2.BaseOptions); + @override - set options(_i2.BaseOptions? _options) => - super.noSuchMethod(Invocation.setter(#options, _options), - returnValueForMissingStub: null); + set options(_i2.BaseOptions? _options) => super.noSuchMethod( + Invocation.setter( + #options, + _options, + ), + returnValueForMissingStub: null, + ); + @override - _i3.HttpClientAdapter get httpClientAdapter => - (super.noSuchMethod(Invocation.getter(#httpClientAdapter), - returnValue: _FakeHttpClientAdapter_1()) as _i3.HttpClientAdapter); + _i3.HttpClientAdapter get httpClientAdapter => (super.noSuchMethod( + Invocation.getter(#httpClientAdapter), + returnValue: _FakeHttpClientAdapter_1( + this, + Invocation.getter(#httpClientAdapter), + ), + ) as _i3.HttpClientAdapter); + @override - set httpClientAdapter(_i3.HttpClientAdapter? _httpClientAdapter) => super - .noSuchMethod(Invocation.setter(#httpClientAdapter, _httpClientAdapter), - returnValueForMissingStub: null); + set httpClientAdapter(_i3.HttpClientAdapter? _httpClientAdapter) => + super.noSuchMethod( + Invocation.setter( + #httpClientAdapter, + _httpClientAdapter, + ), + returnValueForMissingStub: null, + ); + @override - _i4.Transformer get transformer => - (super.noSuchMethod(Invocation.getter(#transformer), - returnValue: _FakeTransformer_2()) as _i4.Transformer); + _i4.Transformer get transformer => (super.noSuchMethod( + Invocation.getter(#transformer), + returnValue: _FakeTransformer_2( + this, + Invocation.getter(#transformer), + ), + ) as _i4.Transformer); + @override - set transformer(_i4.Transformer? _transformer) => - super.noSuchMethod(Invocation.setter(#transformer, _transformer), - returnValueForMissingStub: null); + set transformer(_i4.Transformer? _transformer) => super.noSuchMethod( + Invocation.setter( + #transformer, + _transformer, + ), + returnValueForMissingStub: null, + ); + @override - _i5.Interceptors get interceptors => - (super.noSuchMethod(Invocation.getter(#interceptors), - returnValue: _FakeInterceptors_3()) as _i5.Interceptors); + _i5.Interceptors get interceptors => (super.noSuchMethod( + Invocation.getter(#interceptors), + returnValue: _FakeInterceptors_3( + this, + Invocation.getter(#interceptors), + ), + ) as _i5.Interceptors); + @override - void close({bool? force = false}) => - super.noSuchMethod(Invocation.method(#close, [], {#force: force}), - returnValueForMissingStub: null); + void close({bool? force = false}) => super.noSuchMethod( + Invocation.method( + #close, + [], + {#force: force}, + ), + returnValueForMissingStub: null, + ); + @override - _i8.Future<_i6.Response> get(String? path, - {Map? queryParameters, - _i2.Options? options, - _i9.CancelToken? cancelToken, - _i2.ProgressCallback? onReceiveProgress}) => + _i8.Future<_i6.Response> head( + String? path, { + Object? data, + Map? queryParameters, + _i2.Options? options, + _i9.CancelToken? cancelToken, + }) => (super.noSuchMethod( - Invocation.method(#get, [ - path - ], { - #queryParameters: queryParameters, - #options: options, - #cancelToken: cancelToken, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #head, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #head, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> getUri(Uri? uri, - {_i2.Options? options, - _i9.CancelToken? cancelToken, - _i2.ProgressCallback? onReceiveProgress}) => + _i8.Future<_i6.Response> headUri( + Uri? uri, { + Object? data, + _i2.Options? options, + _i9.CancelToken? cancelToken, + }) => (super.noSuchMethod( - Invocation.method(#getUri, [ - uri - ], { - #options: options, - #cancelToken: cancelToken, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #headUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #headUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> post(String? path, - {dynamic data, - Map? queryParameters, - _i2.Options? options, - _i9.CancelToken? cancelToken, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + _i8.Future<_i6.Response> get( + String? path, { + Object? data, + Map? queryParameters, + _i2.Options? options, + _i9.CancelToken? cancelToken, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#post, [ - path - ], { - #data: data, - #queryParameters: queryParameters, - #options: options, - #cancelToken: cancelToken, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #get, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #get, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> postUri(Uri? uri, - {dynamic data, - _i2.Options? options, - _i9.CancelToken? cancelToken, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + _i8.Future<_i6.Response> getUri( + Uri? uri, { + Object? data, + _i2.Options? options, + _i9.CancelToken? cancelToken, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#postUri, [ - uri - ], { - #data: data, - #options: options, - #cancelToken: cancelToken, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #getUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #getUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> put(String? path, - {dynamic data, - Map? queryParameters, - _i2.Options? options, - _i9.CancelToken? cancelToken, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + _i8.Future<_i6.Response> post( + String? path, { + Object? data, + Map? queryParameters, + _i2.Options? options, + _i9.CancelToken? cancelToken, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#put, [ - path - ], { - #data: data, - #queryParameters: queryParameters, - #options: options, - #cancelToken: cancelToken, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #post, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #post, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> putUri(Uri? uri, - {dynamic data, - _i2.Options? options, - _i9.CancelToken? cancelToken, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + _i8.Future<_i6.Response> postUri( + Uri? uri, { + Object? data, + _i2.Options? options, + _i9.CancelToken? cancelToken, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#putUri, [ - uri - ], { - #data: data, - #options: options, - #cancelToken: cancelToken, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #postUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #postUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> head(String? path, - {dynamic data, - Map? queryParameters, - _i2.Options? options, - _i9.CancelToken? cancelToken}) => + _i8.Future<_i6.Response> put( + String? path, { + Object? data, + Map? queryParameters, + _i2.Options? options, + _i9.CancelToken? cancelToken, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#head, [ - path - ], { - #data: data, - #queryParameters: queryParameters, - #options: options, - #cancelToken: cancelToken - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #put, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #put, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> headUri(Uri? uri, - {dynamic data, _i2.Options? options, _i9.CancelToken? cancelToken}) => + _i8.Future<_i6.Response> putUri( + Uri? uri, { + Object? data, + _i2.Options? options, + _i9.CancelToken? cancelToken, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#headUri, [uri], - {#data: data, #options: options, #cancelToken: cancelToken}), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #putUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #putUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> delete(String? path, - {dynamic data, - Map? queryParameters, - _i2.Options? options, - _i9.CancelToken? cancelToken}) => + _i8.Future<_i6.Response> patch( + String? path, { + Object? data, + Map? queryParameters, + _i2.Options? options, + _i9.CancelToken? cancelToken, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#delete, [ - path - ], { - #data: data, - #queryParameters: queryParameters, - #options: options, - #cancelToken: cancelToken - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #patch, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #patch, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> deleteUri(Uri? uri, - {dynamic data, _i2.Options? options, _i9.CancelToken? cancelToken}) => + _i8.Future<_i6.Response> patchUri( + Uri? uri, { + Object? data, + _i2.Options? options, + _i9.CancelToken? cancelToken, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#deleteUri, [uri], - {#data: data, #options: options, #cancelToken: cancelToken}), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #patchUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #patchUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> patch(String? path, - {dynamic data, - Map? queryParameters, - _i2.Options? options, - _i9.CancelToken? cancelToken, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + _i8.Future<_i6.Response> delete( + String? path, { + Object? data, + Map? queryParameters, + _i2.Options? options, + _i9.CancelToken? cancelToken, + }) => (super.noSuchMethod( - Invocation.method(#patch, [ - path - ], { - #data: data, - #queryParameters: queryParameters, - #options: options, - #cancelToken: cancelToken, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #delete, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #delete, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> patchUri(Uri? uri, - {dynamic data, - _i2.Options? options, - _i9.CancelToken? cancelToken, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + _i8.Future<_i6.Response> deleteUri( + Uri? uri, { + Object? data, + _i2.Options? options, + _i9.CancelToken? cancelToken, + }) => (super.noSuchMethod( - Invocation.method(#patchUri, [ - uri - ], { - #data: data, - #options: options, - #cancelToken: cancelToken, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); - @override - void lock() => super.noSuchMethod(Invocation.method(#lock, []), - returnValueForMissingStub: null); - @override - void unlock() => super.noSuchMethod(Invocation.method(#unlock, []), - returnValueForMissingStub: null); - @override - void clear() => super.noSuchMethod(Invocation.method(#clear, []), - returnValueForMissingStub: null); + Invocation.method( + #deleteUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #deleteUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> download(String? urlPath, dynamic savePath, - {_i2.ProgressCallback? onReceiveProgress, - Map? queryParameters, - _i9.CancelToken? cancelToken, - bool? deleteOnError = true, - String? lengthHeader = r'content-length', - dynamic data, - _i2.Options? options}) => + _i8.Future<_i6.Response> download( + String? urlPath, + dynamic savePath, { + _i2.ProgressCallback? onReceiveProgress, + Map? queryParameters, + _i9.CancelToken? cancelToken, + bool? deleteOnError = true, + String? lengthHeader = r'content-length', + Object? data, + _i2.Options? options, + }) => (super.noSuchMethod( - Invocation.method(#download, [ - urlPath, - savePath - ], { - #onReceiveProgress: onReceiveProgress, - #queryParameters: queryParameters, - #cancelToken: cancelToken, - #deleteOnError: deleteOnError, - #lengthHeader: lengthHeader, - #data: data, - #options: options - }), - returnValue: Future<_i6.Response>.value( - _FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #download, + [ + urlPath, + savePath, + ], + { + #onReceiveProgress: onReceiveProgress, + #queryParameters: queryParameters, + #cancelToken: cancelToken, + #deleteOnError: deleteOnError, + #lengthHeader: lengthHeader, + #data: data, + #options: options, + }, + ), + returnValue: + _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #download, + [ + urlPath, + savePath, + ], + { + #onReceiveProgress: onReceiveProgress, + #queryParameters: queryParameters, + #cancelToken: cancelToken, + #deleteOnError: deleteOnError, + #lengthHeader: lengthHeader, + #data: data, + #options: options, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> downloadUri(Uri? uri, dynamic savePath, - {_i2.ProgressCallback? onReceiveProgress, - _i9.CancelToken? cancelToken, - bool? deleteOnError = true, - String? lengthHeader = r'content-length', - dynamic data, - _i2.Options? options}) => + _i8.Future<_i6.Response> downloadUri( + Uri? uri, + dynamic savePath, { + _i2.ProgressCallback? onReceiveProgress, + _i9.CancelToken? cancelToken, + bool? deleteOnError = true, + String? lengthHeader = r'content-length', + Object? data, + _i2.Options? options, + }) => (super.noSuchMethod( - Invocation.method(#downloadUri, [ - uri, - savePath - ], { - #onReceiveProgress: onReceiveProgress, - #cancelToken: cancelToken, - #deleteOnError: deleteOnError, - #lengthHeader: lengthHeader, - #data: data, - #options: options - }), - returnValue: Future<_i6.Response>.value( - _FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #downloadUri, + [ + uri, + savePath, + ], + { + #onReceiveProgress: onReceiveProgress, + #cancelToken: cancelToken, + #deleteOnError: deleteOnError, + #lengthHeader: lengthHeader, + #data: data, + #options: options, + }, + ), + returnValue: + _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #downloadUri, + [ + uri, + savePath, + ], + { + #onReceiveProgress: onReceiveProgress, + #cancelToken: cancelToken, + #deleteOnError: deleteOnError, + #lengthHeader: lengthHeader, + #data: data, + #options: options, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> request(String? path, - {dynamic data, - Map? queryParameters, - _i9.CancelToken? cancelToken, - _i2.Options? options, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + _i8.Future<_i6.Response> request( + String? url, { + Object? data, + Map? queryParameters, + _i9.CancelToken? cancelToken, + _i2.Options? options, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#request, [ - path - ], { - #data: data, - #queryParameters: queryParameters, - #cancelToken: cancelToken, - #options: options, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #request, + [url], + { + #data: data, + #queryParameters: queryParameters, + #cancelToken: cancelToken, + #options: options, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #request, + [url], + { + #data: data, + #queryParameters: queryParameters, + #cancelToken: cancelToken, + #options: options, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override - _i8.Future<_i6.Response> requestUri(Uri? uri, - {dynamic data, - _i9.CancelToken? cancelToken, - _i2.Options? options, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + _i8.Future<_i6.Response> requestUri( + Uri? uri, { + Object? data, + _i9.CancelToken? cancelToken, + _i2.Options? options, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#requestUri, [ - uri - ], { - #data: data, - #cancelToken: cancelToken, - #options: options, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); + Invocation.method( + #requestUri, + [uri], + { + #data: data, + #cancelToken: cancelToken, + #options: options, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #requestUri, + [uri], + { + #data: data, + #cancelToken: cancelToken, + #options: options, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i8.Future<_i6.Response>); + @override _i8.Future<_i6.Response> fetch(_i2.RequestOptions? requestOptions) => - (super.noSuchMethod(Invocation.method(#fetch, [requestOptions]), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i8.Future<_i6.Response>); - @override - String toString() => super.toString(); + (super.noSuchMethod( + Invocation.method( + #fetch, + [requestOptions], + ), + returnValue: _i8.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #fetch, + [requestOptions], + ), + )), + ) as _i8.Future<_i6.Response>); } diff --git a/test/data/remote/chatwoot_client_service_test.dart b/test/data/remote/chatwoot_client_service_test.dart index a3e4f20..e8d90bc 100644 --- a/test/data/remote/chatwoot_client_service_test.dart +++ b/test/data/remote/chatwoot_client_service_test.dart @@ -6,6 +6,8 @@ import 'package:chatwoot_sdk/data/local/entity/chatwoot_message.dart'; import 'package:chatwoot_sdk/data/remote/chatwoot_client_exception.dart'; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_action_data.dart'; import 'package:chatwoot_sdk/data/remote/requests/chatwoot_new_message_request.dart'; +import 'package:chatwoot_sdk/data/remote/requests/send_csat_survey_request.dart'; +import 'package:chatwoot_sdk/data/remote/responses/csat_survey_response.dart'; import 'package:chatwoot_sdk/data/remote/service/chatwoot_client_service.dart'; import 'package:dio/dio.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -22,9 +24,10 @@ void main() { late final ChatwootClientService clientService; final testBaseUrl = "https://test.com"; final mockDio = MockDio(); + final unauthenticatedmockDio = MockDio(); setUpAll(() { - clientService = ChatwootClientServiceImpl(testBaseUrl, dio: mockDio); + clientService = ChatwootClientServiceImpl(testBaseUrl, dio: mockDio, uDio: unauthenticatedmockDio); }); _createSuccessResponse(body) { @@ -49,8 +52,16 @@ void main() { await TestResourceUtil.readJsonResource(fileName: "message"); final request = ChatwootNewMessageRequest(content: "test message", echoId: "id"); - when(mockDio.post(any, data: request.toJson())).thenAnswer( - (_) => Future.value(_createSuccessResponse(responseBody))); + when(mockDio.post(any, data: anyNamed("data"))).thenAnswer( + (invocation){ + assert(invocation.namedArguments[Symbol("data")] is FormData); + final form = invocation.namedArguments[Symbol("data")] as FormData; + final messageContent = form.fields.firstWhere((f)=>f.key == "content").value; + final echoId = form.fields.firstWhere((f)=>f.key == "echo_id").value; + expect(messageContent, request.content); + expect(echoId, request.echoId); + return Future.value(_createSuccessResponse(responseBody)); + }); //WHEN final result = await clientService.createMessage(request); @@ -65,7 +76,7 @@ void main() { //GIVEN final request = ChatwootNewMessageRequest(content: "test message", echoId: "id"); - when(mockDio.post(any, data: request.toJson())).thenAnswer( + when(mockDio.post(any, data: anyNamed("data"))).thenAnswer( (_) => Future.value(_createErrorResponse(statusCode: 401, body: {}))); //WHEN @@ -86,10 +97,10 @@ void main() { 'Given sending message fails when createMessage is called, then throw error', () async { //GIVEN - final testError = DioError(requestOptions: RequestOptions(path: "")); + final testError = DioException(requestOptions: RequestOptions(path: "")); final request = ChatwootNewMessageRequest(content: "test message", echoId: "id"); - when(mockDio.post(any, data: request.toJson())).thenThrow(testError); + when(mockDio.post(any, data: anyNamed("data"))).thenThrow(testError); //WHEN ChatwootClientException? chatwootClientException; @@ -148,7 +159,7 @@ void main() { 'Given fetch messages fails when getAllMessages is called, then throw error', () async { //GIVEN - final testError = DioError(requestOptions: RequestOptions(path: "")); + final testError = DioException(requestOptions: RequestOptions(path: "")); when(mockDio.get(any)).thenThrow(testError); //WHEN @@ -206,7 +217,7 @@ void main() { 'Given fetch contact fails when getContact is called, then throw error', () async { //GIVEN - final testError = DioError(requestOptions: RequestOptions(path: "")); + final testError = DioException(requestOptions: RequestOptions(path: "")); when(mockDio.get(any)).thenThrow(testError); //WHEN @@ -266,7 +277,7 @@ void main() { 'Given fetch conversations fails when getConversations is called, then throw error', () async { //GIVEN - final testError = DioError(requestOptions: RequestOptions(path: "")); + final testError = DioException(requestOptions: RequestOptions(path: "")); when(mockDio.get(any)).thenThrow(testError); //WHEN @@ -327,7 +338,7 @@ void main() { () async { //GIVEN final update = {"name": "Updated name"}; - final testError = DioError(requestOptions: RequestOptions(path: "")); + final testError = DioException(requestOptions: RequestOptions(path: "")); when(mockDio.patch(any, data: update)).thenThrow(testError); //WHEN @@ -346,69 +357,156 @@ void main() { test( 'Given message is successfully updated when updateMessage is called, then return updated message', - () async { - //GIVEN - final responseBody = + () async { + //GIVEN + final responseBody = await TestResourceUtil.readJsonResource(fileName: "message"); - final testMessageId = "id"; - final update = {"content": "Updated content"}; - when(mockDio.patch(any, data: update)).thenAnswer( - (_) => Future.value(_createSuccessResponse(responseBody))); + final testMessageId = "id"; + final update = {"content": "Updated content"}; + when(mockDio.patch(any, data: update)).thenAnswer( + (_) => Future.value(_createSuccessResponse(responseBody))); - //WHEN - final result = await clientService.updateMessage(testMessageId, update); + //WHEN + final result = await clientService.updateMessage(testMessageId, update); - //THEN - expect(result, ChatwootMessage.fromJson(responseBody)); - }); + //THEN + expect(result, ChatwootMessage.fromJson(responseBody)); + }); test( 'Given message update returns with error response when updateMessage is called, then throw error', - () async { - //GIVEN - final testMessageId = "id"; - final update = {"content": "Updated content"}; - when(mockDio.patch(any, data: update)).thenAnswer( - (_) => Future.value(_createErrorResponse(statusCode: 401, body: {}))); - - //WHEN - ChatwootClientException? chatwootClientException; - try { - await clientService.updateMessage(testMessageId, update); - } on ChatwootClientException catch (e) { - chatwootClientException = e; - } - - //THEN - verify(mockDio.patch(argThat(contains(testMessageId)), data: update)); - expect(chatwootClientException, isNotNull); - expect(chatwootClientException!.type, - equals(ChatwootClientExceptionType.UPDATE_MESSAGE_FAILED)); - }); + () async { + //GIVEN + final testMessageId = "id"; + final update = {"content": "Updated content"}; + when(mockDio.patch(any, data: update)).thenAnswer( + (_) => Future.value(_createErrorResponse(statusCode: 401, body: {}))); + + //WHEN + ChatwootClientException? chatwootClientException; + try { + await clientService.updateMessage(testMessageId, update); + } on ChatwootClientException catch (e) { + chatwootClientException = e; + } + + //THEN + verify(mockDio.patch(argThat(contains(testMessageId)), data: update)); + expect(chatwootClientException, isNotNull); + expect(chatwootClientException!.type, + equals(ChatwootClientExceptionType.UPDATE_MESSAGE_FAILED)); + }); test( 'Given message update fails when updateMessage is called, then throw error', - () async { - //GIVEN - final testMessageId = "id"; - final update = {"content": "Updated content"}; - final testError = DioError(requestOptions: RequestOptions(path: "")); - when(mockDio.patch(any, data: update)).thenThrow(testError); + () async { + //GIVEN + final testMessageId = "id"; + final update = {"content": "Updated content"}; + final testError = DioException(requestOptions: RequestOptions(path: "")); + when(mockDio.patch(any, data: update)).thenThrow(testError); + + //WHEN + ChatwootClientException? chatwootClientException; + try { + await clientService.updateMessage(testMessageId, update); + } on ChatwootClientException catch (e) { + chatwootClientException = e; + } + + //THEN + verify(mockDio.patch(argThat(contains(testMessageId)), data: update)); + expect(chatwootClientException, isNotNull); + expect(chatwootClientException!.type, + equals(ChatwootClientExceptionType.UPDATE_MESSAGE_FAILED)); + }); - //WHEN - ChatwootClientException? chatwootClientException; - try { - await clientService.updateMessage(testMessageId, update); - } on ChatwootClientException catch (e) { - chatwootClientException = e; - } + test( + 'Given csat survey is successfully sent when sendCsatFeedBack is called, then return feedback response', + () async { + //GIVEN + final responseBody = + await TestResourceUtil.readJsonResource(fileName: "csat_feedback"); + final testConversationUuid = "conversation-uuid"; + final feedbackRequest = SendCsatSurveyRequest(rating: 1, feedbackMessage: "test message"); + final requestBody = { + "message":{ + "submitted_values":{ + "csat_survey_response": feedbackRequest.toJson() + } + } + }; + when(unauthenticatedmockDio.put(any, data: requestBody)).thenAnswer( + (_) => Future.value(_createSuccessResponse(responseBody))); + + //WHEN + final result = await clientService.sendCsatFeedBack(testConversationUuid, feedbackRequest); + + //THEN + expect(result, CsatSurveyFeedbackResponse.fromJson(responseBody)); + }); - //THEN - verify(mockDio.patch(argThat(contains(testMessageId)), data: update)); - expect(chatwootClientException, isNotNull); - expect(chatwootClientException!.type, - equals(ChatwootClientExceptionType.UPDATE_MESSAGE_FAILED)); - }); + test( + 'Given send csat survey returns with error response when sendCsatFeedBack is called, then throw error', + () async { + //GIVEN + final testConversationUuid = "conversation-uuid"; + final feedbackRequest = SendCsatSurveyRequest(rating: 1, feedbackMessage: "test message"); + final requestBody = { + "message":{ + "submitted_values":{ + "csat_survey_response": feedbackRequest.toJson() + } + } + }; + when(unauthenticatedmockDio.put(any, data: requestBody)).thenAnswer( + (_) => Future.value(_createErrorResponse(statusCode: 500, body: {}))); + + //WHEN + ChatwootClientException? chatwootClientException; + try { + await clientService.sendCsatFeedBack(testConversationUuid, feedbackRequest); + } on ChatwootClientException catch (e) { + chatwootClientException = e; + } + + //THEN + verify(unauthenticatedmockDio.put(argThat(contains(testConversationUuid)), data: requestBody)); + expect(chatwootClientException, isNotNull); + expect(chatwootClientException!.type, + equals(ChatwootClientExceptionType.SEND_CSAT_FEEDBACK)); + }); + + test( + 'Given send csat feedback fails when sendCsatFeedBack is called, then throw error', + () async { + //GIVEN + final testConversationUuid = "conversation-uuid"; + final feedbackRequest = SendCsatSurveyRequest(rating: 1, feedbackMessage: "test message"); + final testError = DioException(requestOptions: RequestOptions(path: "")); + final requestBody = { + "message":{ + "submitted_values":{ + "csat_survey_response": feedbackRequest.toJson() + } + } + }; + when(unauthenticatedmockDio.put(any, data: requestBody)).thenThrow(testError); + + //WHEN + ChatwootClientException? chatwootClientException; + try { + await clientService.sendCsatFeedBack(testConversationUuid, feedbackRequest); + } on ChatwootClientException catch (e) { + chatwootClientException = e; + } + + //THEN + verify(unauthenticatedmockDio.put(argThat(contains(testConversationUuid)), data: requestBody)); + expect(chatwootClientException, isNotNull); + expect(chatwootClientException!.type, + equals(ChatwootClientExceptionType.SEND_CSAT_FEEDBACK)); + }); test( 'Given websocket connection is successful when startWebSocketConnection is called, then subscribe for events', diff --git a/test/data/remote/chatwoot_client_service_test.mocks.dart b/test/data/remote/chatwoot_client_service_test.mocks.dart index f7163d1..5fdac38 100644 --- a/test/data/remote/chatwoot_client_service_test.mocks.dart +++ b/test/data/remote/chatwoot_client_service_test.mocks.dart @@ -1,7 +1,8 @@ -// Mocks generated by Mockito 5.0.15 from annotations +// Mocks generated by Mockito 5.4.4 from annotations // in chatwoot_sdk/test/data/remote/chatwoot_client_service_test.dart. // Do not manually edit this file. +// ignore_for_file: no_leading_underscores_for_library_prefixes import 'dart:async' as _i10; import 'package:async/async.dart' as _i12; @@ -16,28 +17,89 @@ import 'package:mockito/mockito.dart' as _i1; import 'package:stream_channel/stream_channel.dart' as _i8; import 'package:web_socket_channel/src/channel.dart' as _i7; +// ignore_for_file: type=lint // ignore_for_file: avoid_redundant_argument_values // ignore_for_file: avoid_setters_without_getters // ignore_for_file: comment_references +// ignore_for_file: deprecated_member_use +// ignore_for_file: deprecated_member_use_from_same_package // ignore_for_file: implementation_imports // ignore_for_file: invalid_use_of_visible_for_testing_member // ignore_for_file: prefer_const_constructors // ignore_for_file: unnecessary_parenthesis +// ignore_for_file: camel_case_types +// ignore_for_file: subtype_of_sealed_class -class _FakeBaseOptions_0 extends _i1.Fake implements _i2.BaseOptions {} +class _FakeBaseOptions_0 extends _i1.SmartFake implements _i2.BaseOptions { + _FakeBaseOptions_0( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeHttpClientAdapter_1 extends _i1.Fake - implements _i3.HttpClientAdapter {} +class _FakeHttpClientAdapter_1 extends _i1.SmartFake + implements _i3.HttpClientAdapter { + _FakeHttpClientAdapter_1( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeTransformer_2 extends _i1.Fake implements _i4.Transformer {} +class _FakeTransformer_2 extends _i1.SmartFake implements _i4.Transformer { + _FakeTransformer_2( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeInterceptors_3 extends _i1.Fake implements _i5.Interceptors {} +class _FakeInterceptors_3 extends _i1.SmartFake implements _i5.Interceptors { + _FakeInterceptors_3( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeResponse_4 extends _i1.Fake implements _i6.Response {} +class _FakeResponse_4 extends _i1.SmartFake implements _i6.Response { + _FakeResponse_4( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeWebSocketSink_5 extends _i1.Fake implements _i7.WebSocketSink {} +class _FakeWebSocketSink_5 extends _i1.SmartFake implements _i7.WebSocketSink { + _FakeWebSocketSink_5( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); +} -class _FakeStreamChannel_6 extends _i1.Fake implements _i8.StreamChannel { +class _FakeStreamChannel_6 extends _i1.SmartFake + implements _i8.StreamChannel { + _FakeStreamChannel_6( + Object parent, + Invocation parentInvocation, + ) : super( + parent, + parentInvocation, + ); } /// A class which mocks [Dio]. @@ -49,347 +111,702 @@ class MockDio extends _i1.Mock implements _i9.Dio { } @override - _i2.BaseOptions get options => - (super.noSuchMethod(Invocation.getter(#options), - returnValue: _FakeBaseOptions_0()) as _i2.BaseOptions); + _i2.BaseOptions get options => (super.noSuchMethod( + Invocation.getter(#options), + returnValue: _FakeBaseOptions_0( + this, + Invocation.getter(#options), + ), + ) as _i2.BaseOptions); + @override - set options(_i2.BaseOptions? _options) => - super.noSuchMethod(Invocation.setter(#options, _options), - returnValueForMissingStub: null); + set options(_i2.BaseOptions? _options) => super.noSuchMethod( + Invocation.setter( + #options, + _options, + ), + returnValueForMissingStub: null, + ); + @override - _i3.HttpClientAdapter get httpClientAdapter => - (super.noSuchMethod(Invocation.getter(#httpClientAdapter), - returnValue: _FakeHttpClientAdapter_1()) as _i3.HttpClientAdapter); + _i3.HttpClientAdapter get httpClientAdapter => (super.noSuchMethod( + Invocation.getter(#httpClientAdapter), + returnValue: _FakeHttpClientAdapter_1( + this, + Invocation.getter(#httpClientAdapter), + ), + ) as _i3.HttpClientAdapter); + @override - set httpClientAdapter(_i3.HttpClientAdapter? _httpClientAdapter) => super - .noSuchMethod(Invocation.setter(#httpClientAdapter, _httpClientAdapter), - returnValueForMissingStub: null); + set httpClientAdapter(_i3.HttpClientAdapter? _httpClientAdapter) => + super.noSuchMethod( + Invocation.setter( + #httpClientAdapter, + _httpClientAdapter, + ), + returnValueForMissingStub: null, + ); + @override - _i4.Transformer get transformer => - (super.noSuchMethod(Invocation.getter(#transformer), - returnValue: _FakeTransformer_2()) as _i4.Transformer); + _i4.Transformer get transformer => (super.noSuchMethod( + Invocation.getter(#transformer), + returnValue: _FakeTransformer_2( + this, + Invocation.getter(#transformer), + ), + ) as _i4.Transformer); + @override - set transformer(_i4.Transformer? _transformer) => - super.noSuchMethod(Invocation.setter(#transformer, _transformer), - returnValueForMissingStub: null); + set transformer(_i4.Transformer? _transformer) => super.noSuchMethod( + Invocation.setter( + #transformer, + _transformer, + ), + returnValueForMissingStub: null, + ); + @override - _i5.Interceptors get interceptors => - (super.noSuchMethod(Invocation.getter(#interceptors), - returnValue: _FakeInterceptors_3()) as _i5.Interceptors); + _i5.Interceptors get interceptors => (super.noSuchMethod( + Invocation.getter(#interceptors), + returnValue: _FakeInterceptors_3( + this, + Invocation.getter(#interceptors), + ), + ) as _i5.Interceptors); + @override - void close({bool? force = false}) => - super.noSuchMethod(Invocation.method(#close, [], {#force: force}), - returnValueForMissingStub: null); + void close({bool? force = false}) => super.noSuchMethod( + Invocation.method( + #close, + [], + {#force: force}, + ), + returnValueForMissingStub: null, + ); + @override - _i10.Future<_i6.Response> get(String? path, - {Map? queryParameters, - _i2.Options? options, - _i11.CancelToken? cancelToken, - _i2.ProgressCallback? onReceiveProgress}) => + _i10.Future<_i6.Response> head( + String? path, { + Object? data, + Map? queryParameters, + _i2.Options? options, + _i11.CancelToken? cancelToken, + }) => (super.noSuchMethod( - Invocation.method(#get, [ - path - ], { - #queryParameters: queryParameters, - #options: options, - #cancelToken: cancelToken, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> getUri(Uri? uri, - {_i2.Options? options, - _i11.CancelToken? cancelToken, - _i2.ProgressCallback? onReceiveProgress}) => + Invocation.method( + #head, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #head, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> headUri( + Uri? uri, { + Object? data, + _i2.Options? options, + _i11.CancelToken? cancelToken, + }) => (super.noSuchMethod( - Invocation.method(#getUri, [ - uri - ], { - #options: options, - #cancelToken: cancelToken, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> post(String? path, - {dynamic data, - Map? queryParameters, - _i2.Options? options, - _i11.CancelToken? cancelToken, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + Invocation.method( + #headUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #headUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> get( + String? path, { + Object? data, + Map? queryParameters, + _i2.Options? options, + _i11.CancelToken? cancelToken, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#post, [ - path - ], { - #data: data, - #queryParameters: queryParameters, - #options: options, - #cancelToken: cancelToken, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> postUri(Uri? uri, - {dynamic data, - _i2.Options? options, - _i11.CancelToken? cancelToken, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + Invocation.method( + #get, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #get, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> getUri( + Uri? uri, { + Object? data, + _i2.Options? options, + _i11.CancelToken? cancelToken, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#postUri, [ - uri - ], { - #data: data, - #options: options, - #cancelToken: cancelToken, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> put(String? path, - {dynamic data, - Map? queryParameters, - _i2.Options? options, - _i11.CancelToken? cancelToken, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + Invocation.method( + #getUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #getUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> post( + String? path, { + Object? data, + Map? queryParameters, + _i2.Options? options, + _i11.CancelToken? cancelToken, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#put, [ - path - ], { - #data: data, - #queryParameters: queryParameters, - #options: options, - #cancelToken: cancelToken, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> putUri(Uri? uri, - {dynamic data, - _i2.Options? options, - _i11.CancelToken? cancelToken, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + Invocation.method( + #post, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #post, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> postUri( + Uri? uri, { + Object? data, + _i2.Options? options, + _i11.CancelToken? cancelToken, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#putUri, [ - uri - ], { - #data: data, - #options: options, - #cancelToken: cancelToken, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> head(String? path, - {dynamic data, - Map? queryParameters, - _i2.Options? options, - _i11.CancelToken? cancelToken}) => + Invocation.method( + #postUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #postUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> put( + String? path, { + Object? data, + Map? queryParameters, + _i2.Options? options, + _i11.CancelToken? cancelToken, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#head, [ - path - ], { - #data: data, - #queryParameters: queryParameters, - #options: options, - #cancelToken: cancelToken - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> headUri(Uri? uri, - {dynamic data, - _i2.Options? options, - _i11.CancelToken? cancelToken}) => + Invocation.method( + #put, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #put, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> putUri( + Uri? uri, { + Object? data, + _i2.Options? options, + _i11.CancelToken? cancelToken, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#headUri, [uri], - {#data: data, #options: options, #cancelToken: cancelToken}), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> delete(String? path, - {dynamic data, - Map? queryParameters, - _i2.Options? options, - _i11.CancelToken? cancelToken}) => + Invocation.method( + #putUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #putUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> patch( + String? path, { + Object? data, + Map? queryParameters, + _i2.Options? options, + _i11.CancelToken? cancelToken, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#delete, [ - path - ], { - #data: data, - #queryParameters: queryParameters, - #options: options, - #cancelToken: cancelToken - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> deleteUri(Uri? uri, - {dynamic data, - _i2.Options? options, - _i11.CancelToken? cancelToken}) => + Invocation.method( + #patch, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #patch, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> patchUri( + Uri? uri, { + Object? data, + _i2.Options? options, + _i11.CancelToken? cancelToken, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#deleteUri, [uri], - {#data: data, #options: options, #cancelToken: cancelToken}), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> patch(String? path, - {dynamic data, - Map? queryParameters, - _i2.Options? options, - _i11.CancelToken? cancelToken, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + Invocation.method( + #patchUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #patchUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> delete( + String? path, { + Object? data, + Map? queryParameters, + _i2.Options? options, + _i11.CancelToken? cancelToken, + }) => (super.noSuchMethod( - Invocation.method(#patch, [ - path - ], { - #data: data, - #queryParameters: queryParameters, - #options: options, - #cancelToken: cancelToken, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> patchUri(Uri? uri, - {dynamic data, - _i2.Options? options, - _i11.CancelToken? cancelToken, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + Invocation.method( + #delete, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #delete, + [path], + { + #data: data, + #queryParameters: queryParameters, + #options: options, + #cancelToken: cancelToken, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> deleteUri( + Uri? uri, { + Object? data, + _i2.Options? options, + _i11.CancelToken? cancelToken, + }) => (super.noSuchMethod( - Invocation.method(#patchUri, [ - uri - ], { - #data: data, - #options: options, - #cancelToken: cancelToken, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - void lock() => super.noSuchMethod(Invocation.method(#lock, []), - returnValueForMissingStub: null); - @override - void unlock() => super.noSuchMethod(Invocation.method(#unlock, []), - returnValueForMissingStub: null); - @override - void clear() => super.noSuchMethod(Invocation.method(#clear, []), - returnValueForMissingStub: null); - @override - _i10.Future<_i6.Response> download(String? urlPath, dynamic savePath, - {_i2.ProgressCallback? onReceiveProgress, - Map? queryParameters, - _i11.CancelToken? cancelToken, - bool? deleteOnError = true, - String? lengthHeader = r'content-length', - dynamic data, - _i2.Options? options}) => + Invocation.method( + #deleteUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #deleteUri, + [uri], + { + #data: data, + #options: options, + #cancelToken: cancelToken, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> download( + String? urlPath, + dynamic savePath, { + _i2.ProgressCallback? onReceiveProgress, + Map? queryParameters, + _i11.CancelToken? cancelToken, + bool? deleteOnError = true, + String? lengthHeader = r'content-length', + Object? data, + _i2.Options? options, + }) => (super.noSuchMethod( - Invocation.method(#download, [ - urlPath, - savePath - ], { - #onReceiveProgress: onReceiveProgress, - #queryParameters: queryParameters, - #cancelToken: cancelToken, - #deleteOnError: deleteOnError, - #lengthHeader: lengthHeader, - #data: data, - #options: options - }), - returnValue: Future<_i6.Response>.value( - _FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> downloadUri(Uri? uri, dynamic savePath, - {_i2.ProgressCallback? onReceiveProgress, - _i11.CancelToken? cancelToken, - bool? deleteOnError = true, - String? lengthHeader = r'content-length', - dynamic data, - _i2.Options? options}) => + Invocation.method( + #download, + [ + urlPath, + savePath, + ], + { + #onReceiveProgress: onReceiveProgress, + #queryParameters: queryParameters, + #cancelToken: cancelToken, + #deleteOnError: deleteOnError, + #lengthHeader: lengthHeader, + #data: data, + #options: options, + }, + ), + returnValue: + _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #download, + [ + urlPath, + savePath, + ], + { + #onReceiveProgress: onReceiveProgress, + #queryParameters: queryParameters, + #cancelToken: cancelToken, + #deleteOnError: deleteOnError, + #lengthHeader: lengthHeader, + #data: data, + #options: options, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> downloadUri( + Uri? uri, + dynamic savePath, { + _i2.ProgressCallback? onReceiveProgress, + _i11.CancelToken? cancelToken, + bool? deleteOnError = true, + String? lengthHeader = r'content-length', + Object? data, + _i2.Options? options, + }) => (super.noSuchMethod( - Invocation.method(#downloadUri, [ - uri, - savePath - ], { - #onReceiveProgress: onReceiveProgress, - #cancelToken: cancelToken, - #deleteOnError: deleteOnError, - #lengthHeader: lengthHeader, - #data: data, - #options: options - }), - returnValue: Future<_i6.Response>.value( - _FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> request(String? path, - {dynamic data, - Map? queryParameters, - _i11.CancelToken? cancelToken, - _i2.Options? options, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + Invocation.method( + #downloadUri, + [ + uri, + savePath, + ], + { + #onReceiveProgress: onReceiveProgress, + #cancelToken: cancelToken, + #deleteOnError: deleteOnError, + #lengthHeader: lengthHeader, + #data: data, + #options: options, + }, + ), + returnValue: + _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #downloadUri, + [ + uri, + savePath, + ], + { + #onReceiveProgress: onReceiveProgress, + #cancelToken: cancelToken, + #deleteOnError: deleteOnError, + #lengthHeader: lengthHeader, + #data: data, + #options: options, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> request( + String? url, { + Object? data, + Map? queryParameters, + _i11.CancelToken? cancelToken, + _i2.Options? options, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#request, [ - path - ], { - #data: data, - #queryParameters: queryParameters, - #cancelToken: cancelToken, - #options: options, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - _i10.Future<_i6.Response> requestUri(Uri? uri, - {dynamic data, - _i11.CancelToken? cancelToken, - _i2.Options? options, - _i2.ProgressCallback? onSendProgress, - _i2.ProgressCallback? onReceiveProgress}) => + Invocation.method( + #request, + [url], + { + #data: data, + #queryParameters: queryParameters, + #cancelToken: cancelToken, + #options: options, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #request, + [url], + { + #data: data, + #queryParameters: queryParameters, + #cancelToken: cancelToken, + #options: options, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + + @override + _i10.Future<_i6.Response> requestUri( + Uri? uri, { + Object? data, + _i11.CancelToken? cancelToken, + _i2.Options? options, + _i2.ProgressCallback? onSendProgress, + _i2.ProgressCallback? onReceiveProgress, + }) => (super.noSuchMethod( - Invocation.method(#requestUri, [ - uri - ], { - #data: data, - #cancelToken: cancelToken, - #options: options, - #onSendProgress: onSendProgress, - #onReceiveProgress: onReceiveProgress - }), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); + Invocation.method( + #requestUri, + [uri], + { + #data: data, + #cancelToken: cancelToken, + #options: options, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #requestUri, + [uri], + { + #data: data, + #cancelToken: cancelToken, + #options: options, + #onSendProgress: onSendProgress, + #onReceiveProgress: onReceiveProgress, + }, + ), + )), + ) as _i10.Future<_i6.Response>); + @override _i10.Future<_i6.Response> fetch(_i2.RequestOptions? requestOptions) => - (super.noSuchMethod(Invocation.method(#fetch, [requestOptions]), - returnValue: Future<_i6.Response>.value(_FakeResponse_4())) - as _i10.Future<_i6.Response>); - @override - String toString() => super.toString(); + (super.noSuchMethod( + Invocation.method( + #fetch, + [requestOptions], + ), + returnValue: _i10.Future<_i6.Response>.value(_FakeResponse_4( + this, + Invocation.method( + #fetch, + [requestOptions], + ), + )), + ) as _i10.Future<_i6.Response>); } /// A class which mocks [WebSocketChannel]. @@ -401,52 +818,135 @@ class MockWebSocketChannel extends _i1.Mock implements _i7.WebSocketChannel { } @override - _i10.Stream get stream => - (super.noSuchMethod(Invocation.getter(#stream), - returnValue: Stream.empty()) as _i10.Stream); + _i10.Future get ready => (super.noSuchMethod( + Invocation.getter(#ready), + returnValue: _i10.Future.value(), + ) as _i10.Future); + @override - _i7.WebSocketSink get sink => (super.noSuchMethod(Invocation.getter(#sink), - returnValue: _FakeWebSocketSink_5()) as _i7.WebSocketSink); + _i7.WebSocketSink get sink => (super.noSuchMethod( + Invocation.getter(#sink), + returnValue: _FakeWebSocketSink_5( + this, + Invocation.getter(#sink), + ), + ) as _i7.WebSocketSink); + @override - void pipe(_i8.StreamChannel? other) => - super.noSuchMethod(Invocation.method(#pipe, [other]), - returnValueForMissingStub: null); + _i10.Stream get stream => (super.noSuchMethod( + Invocation.getter(#stream), + returnValue: _i10.Stream.empty(), + ) as _i10.Stream); + + @override + void pipe(_i8.StreamChannel? other) => super.noSuchMethod( + Invocation.method( + #pipe, + [other], + ), + returnValueForMissingStub: null, + ); + @override _i8.StreamChannel transform( _i8.StreamChannelTransformer? transformer) => - (super.noSuchMethod(Invocation.method(#transform, [transformer]), - returnValue: _FakeStreamChannel_6()) as _i8.StreamChannel); + (super.noSuchMethod( + Invocation.method( + #transform, + [transformer], + ), + returnValue: _FakeStreamChannel_6( + this, + Invocation.method( + #transform, + [transformer], + ), + ), + ) as _i8.StreamChannel); + @override _i8.StreamChannel transformStream( _i10.StreamTransformer? transformer) => - (super.noSuchMethod(Invocation.method(#transformStream, [transformer]), - returnValue: _FakeStreamChannel_6()) - as _i8.StreamChannel); + (super.noSuchMethod( + Invocation.method( + #transformStream, + [transformer], + ), + returnValue: _FakeStreamChannel_6( + this, + Invocation.method( + #transformStream, + [transformer], + ), + ), + ) as _i8.StreamChannel); + @override _i8.StreamChannel transformSink( _i12.StreamSinkTransformer? transformer) => - (super.noSuchMethod(Invocation.method(#transformSink, [transformer]), - returnValue: _FakeStreamChannel_6()) - as _i8.StreamChannel); + (super.noSuchMethod( + Invocation.method( + #transformSink, + [transformer], + ), + returnValue: _FakeStreamChannel_6( + this, + Invocation.method( + #transformSink, + [transformer], + ), + ), + ) as _i8.StreamChannel); + @override _i8.StreamChannel changeStream( _i10.Stream Function(_i10.Stream)? change) => - (super.noSuchMethod(Invocation.method(#changeStream, [change]), - returnValue: _FakeStreamChannel_6()) - as _i8.StreamChannel); + (super.noSuchMethod( + Invocation.method( + #changeStream, + [change], + ), + returnValue: _FakeStreamChannel_6( + this, + Invocation.method( + #changeStream, + [change], + ), + ), + ) as _i8.StreamChannel); + @override _i8.StreamChannel changeSink( _i10.StreamSink Function(_i10.StreamSink)? change) => - (super.noSuchMethod(Invocation.method(#changeSink, [change]), - returnValue: _FakeStreamChannel_6()) - as _i8.StreamChannel); - @override - _i8.StreamChannel cast() => - (super.noSuchMethod(Invocation.method(#cast, []), - returnValue: _FakeStreamChannel_6()) as _i8.StreamChannel); + (super.noSuchMethod( + Invocation.method( + #changeSink, + [change], + ), + returnValue: _FakeStreamChannel_6( + this, + Invocation.method( + #changeSink, + [change], + ), + ), + ) as _i8.StreamChannel); + @override - String toString() => super.toString(); + _i8.StreamChannel cast() => (super.noSuchMethod( + Invocation.method( + #cast, + [], + ), + returnValue: _FakeStreamChannel_6( + this, + Invocation.method( + #cast, + [], + ), + ), + ) as _i8.StreamChannel); } /// A class which mocks [WebSocketSink]. @@ -458,23 +958,59 @@ class MockWebSocketSink extends _i1.Mock implements _i7.WebSocketSink { } @override - _i10.Future get done => (super.noSuchMethod(Invocation.getter(#done), - returnValue: Future.value()) as _i10.Future); + _i10.Future get done => (super.noSuchMethod( + Invocation.getter(#done), + returnValue: _i10.Future.value(), + ) as _i10.Future); + @override - _i10.Future close([int? closeCode, String? closeReason]) => - (super.noSuchMethod(Invocation.method(#close, [closeCode, closeReason]), - returnValue: Future.value()) as _i10.Future); + _i10.Future close([ + int? closeCode, + String? closeReason, + ]) => + (super.noSuchMethod( + Invocation.method( + #close, + [ + closeCode, + closeReason, + ], + ), + returnValue: _i10.Future.value(), + ) as _i10.Future); + @override - void add(dynamic data) => super.noSuchMethod(Invocation.method(#add, [data]), - returnValueForMissingStub: null); + void add(dynamic data) => super.noSuchMethod( + Invocation.method( + #add, + [data], + ), + returnValueForMissingStub: null, + ); + @override - void addError(Object? error, [StackTrace? stackTrace]) => - super.noSuchMethod(Invocation.method(#addError, [error, stackTrace]), - returnValueForMissingStub: null); + void addError( + Object? error, [ + StackTrace? stackTrace, + ]) => + super.noSuchMethod( + Invocation.method( + #addError, + [ + error, + stackTrace, + ], + ), + returnValueForMissingStub: null, + ); + @override _i10.Future addStream(_i10.Stream? stream) => - (super.noSuchMethod(Invocation.method(#addStream, [stream]), - returnValue: Future.value()) as _i10.Future); - @override - String toString() => super.toString(); + (super.noSuchMethod( + Invocation.method( + #addStream, + [stream], + ), + returnValue: _i10.Future.value(), + ) as _i10.Future); } diff --git a/test/di/modules_test.dart b/test/di/modules_test.dart index 88a5448..25b96c2 100644 --- a/test/di/modules_test.dart +++ b/test/di/modules_test.dart @@ -9,6 +9,7 @@ import 'package:chatwoot_sdk/data/local/dao/chatwoot_user_dao.dart'; import 'package:chatwoot_sdk/data/local/entity/chatwoot_contact.dart'; import 'package:chatwoot_sdk/data/local/entity/chatwoot_conversation.dart'; import 'package:chatwoot_sdk/data/remote/responses/chatwoot_event.dart'; +import 'package:chatwoot_sdk/data/remote/service/chatwoot_client_api_interceptor.dart'; import 'package:chatwoot_sdk/di/modules.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:hive_flutter/hive_flutter.dart'; @@ -50,7 +51,8 @@ void main() { //THEN expect(result.options.baseUrl, equals(testChatwootParameters.baseUrl)); - expect(result.interceptors.isEmpty, equals(true)); + final authInterceptorCount = result.interceptors.where((i)=>i is ChatwootClientApiInterceptor).length; + expect(authInterceptorCount, equals(0)); }); test( @@ -61,7 +63,8 @@ void main() { .read(chatwootClientAuthServiceProvider(testChatwootParameters)); //THEN - expect(result.dio.interceptors.length, equals(0)); + final authInterceptorCount = result.dio.interceptors.where((i)=>i is ChatwootClientApiInterceptor).length; + expect(authInterceptorCount, equals(0)); }); test( @@ -73,7 +76,8 @@ void main() { //THEN expect(result.options.baseUrl, equals(testChatwootParameters.baseUrl)); - expect(result.interceptors.length, equals(1)); + final authInterceptorCount = result.interceptors.where((i)=>i is ChatwootClientApiInterceptor).length; + expect(authInterceptorCount, equals(1)); }); test( diff --git a/test/resources/conversation.json b/test/resources/conversation.json index a3bee70..906b711 100644 --- a/test/resources/conversation.json +++ b/test/resources/conversation.json @@ -1,5 +1,6 @@ { "id": 7, + "uuid": "87a6e432-62a7-41c6-9c20-bfcd24d6aa98", "inbox_id": 1, "contact_last_seen_at": 0, "status": "open", diff --git a/test/resources/conversations.json b/test/resources/conversations.json index c04b797..0c550f5 100644 --- a/test/resources/conversations.json +++ b/test/resources/conversations.json @@ -1,6 +1,7 @@ [ { "id": 2, + "uuid": "87a6e432-62a7-41c6-9c20-bfcd24d6aa98", "inbox_id": 1, "contact_last_seen_at": 0, "status": "open", @@ -27,6 +28,7 @@ }, { "id": 9, + "uuid": "ja82nvht-62a7-41c6-9c20-bfcd24d6aa98", "content": "Reply to postman", "message_type": 1, "content_type": null, diff --git a/test/resources/csat_feedback.json b/test/resources/csat_feedback.json new file mode 100644 index 0000000..2485b6e --- /dev/null +++ b/test/resources/csat_feedback.json @@ -0,0 +1,20 @@ +{ + "id": 48, + "csat_survey_response": { + "id": 1, + "account_id": 2, + "conversation_id": 9, + "message_id": 48, + "rating": 5, + "feedback_message": "Great Support", + "contact_id": 8, + "assigned_agent_id": 2, + "created_at": "2024-11-25T11:45:23.473Z", + "updated_at": "2024-11-25T11:45:41.807Z" + }, + "inbox_avatar_url": "", + "inbox_name": "Mobile", + "locale": "en", + "conversation_id": 9, + "created_at": "2024-11-25T11:44:41.937Z" +} \ No newline at end of file