├── .pubignore ├── lib ├── odoochat.dart └── src │ ├── model │ ├── model.dart │ ├── attachment │ │ ├── attachment.dart │ │ ├── attachment.g.dart │ │ └── attachment.freezed.dart │ ├── partner │ │ ├── partner.dart │ │ └── partner.g.dart │ ├── channel │ │ ├── channel.dart │ │ └── channel.g.dart │ ├── message_info │ │ ├── message_info.g.dart │ │ └── message_info.dart │ └── message │ │ ├── message.dart │ │ └── message.g.dart │ ├── api │ ├── responses │ │ ├── responses.dart │ │ ├── poll_result │ │ │ ├── poll_result.g.dart │ │ │ ├── poll_result.dart │ │ │ └── poll_result.freezed.dart │ │ ├── rpc_response │ │ │ ├── rpc_response.dart │ │ │ ├── rpc_response.g.dart │ │ │ └── rpc_response.freezed.dart │ │ ├── init_messaging_result │ │ │ ├── init_messaging_result.dart │ │ │ └── init_messaging_result.g.dart │ │ └── login_result │ │ │ ├── login_result.dart │ │ │ └── login_result.g.dart │ └── odoochat_api.dart │ ├── exceptions │ └── exceptions.dart │ ├── payload │ ├── login_params │ │ ├── login_params.dart │ │ ├── login_params.g.dart │ │ └── login_params.freezed.dart │ ├── payload.dart │ ├── init_messaging_params │ │ ├── init_messaging_params.dart │ │ ├── init_messaging_params.g.dart │ │ └── init_messaging_params.freezed.dart │ ├── get_messages_params │ │ ├── get_messages_params.dart │ │ ├── get_messages_params.g.dart │ │ └── get_messages_params.freezed.dart │ ├── poll_params │ │ ├── poll_params.dart │ │ ├── poll_params.g.dart │ │ └── poll_params.freezed.dart │ ├── upload_attachment_payload │ │ └── upload_attachment_payload.dart │ ├── message_post_params │ │ ├── message_post_params.g.dart │ │ ├── message_post_params.dart │ │ └── message_post_params.freezed.dart │ ├── rpc_payload │ │ ├── rpc_payload.g.dart │ │ └── rpc_payload.dart │ ├── message_fetch_params │ │ ├── message_fetch_params.g.dart │ │ ├── message_fetch_params.dart │ │ └── message_fetch_params.freezed.dart │ └── send_message_params │ │ ├── send_message_params.dart │ │ └── send_message_params.g.dart │ └── odoochat.dart ├── example ├── odoochat_example │ ├── README.md │ ├── ios │ │ ├── Runner │ │ │ ├── Runner-Bridging-Header.h │ │ │ ├── Assets.xcassets │ │ │ │ ├── LaunchImage.imageset │ │ │ │ │ ├── LaunchImage.png │ │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ │ ├── README.md │ │ │ │ │ └── Contents.json │ │ │ │ └── AppIcon.appiconset │ │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ │ └── Contents.json │ │ │ ├── AppDelegate.swift │ │ │ ├── Base.lproj │ │ │ │ ├── Main.storyboard │ │ │ │ └── LaunchScreen.storyboard │ │ │ └── Info.plist │ │ ├── Flutter │ │ │ ├── Debug.xcconfig │ │ │ ├── Release.xcconfig │ │ │ └── AppFrameworkInfo.plist │ │ ├── Runner.xcodeproj │ │ │ ├── project.xcworkspace │ │ │ │ ├── contents.xcworkspacedata │ │ │ │ └── xcshareddata │ │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ │ └── IDEWorkspaceChecks.plist │ │ │ └── xcshareddata │ │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ ├── Runner.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── WorkspaceSettings.xcsettings │ │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── RunnerTests │ │ │ └── RunnerTests.swift │ │ ├── .gitignore │ │ ├── Podfile │ │ └── Podfile.lock │ ├── lib │ │ ├── bloc │ │ │ ├── bloc.dart │ │ │ ├── chat_poll │ │ │ │ ├── chat_poll.dart │ │ │ │ ├── chat_poll_worker.dart │ │ │ │ ├── chat_poll_interface.dart │ │ │ │ └── chat_poll_isolate.dart │ │ │ ├── chat_state.dart │ │ │ └── chat_bloc.dart │ │ ├── main.dart │ │ ├── chat_poll_worker.dart │ │ ├── login.dart │ │ ├── app.dart │ │ └── chat.dart │ ├── android │ │ ├── gradle.properties │ │ ├── app │ │ │ ├── src │ │ │ │ ├── main │ │ │ │ │ ├── res │ │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ │ ├── drawable │ │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ │ ├── drawable-v21 │ │ │ │ │ │ │ └── launch_background.xml │ │ │ │ │ │ ├── values │ │ │ │ │ │ │ └── styles.xml │ │ │ │ │ │ └── values-night │ │ │ │ │ │ │ └── styles.xml │ │ │ │ │ ├── kotlin │ │ │ │ │ │ └── com │ │ │ │ │ │ │ └── luisciber │ │ │ │ │ │ │ └── odoochat_example │ │ │ │ │ │ │ └── MainActivity.kt │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ ├── debug │ │ │ │ │ └── AndroidManifest.xml │ │ │ │ └── profile │ │ │ │ │ └── AndroidManifest.xml │ │ │ └── build.gradle │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ └── gradle-wrapper.properties │ │ ├── .gitignore │ │ ├── build.gradle │ │ └── settings.gradle │ ├── web │ │ ├── favicon.png │ │ ├── icons │ │ │ ├── Icon-192.png │ │ │ ├── Icon-512.png │ │ │ ├── Icon-maskable-192.png │ │ │ └── Icon-maskable-512.png │ │ ├── manifest.json │ │ └── index.html │ ├── analysis_options.yaml │ ├── .vscode │ │ └── launch.json │ ├── pubspec.yaml │ ├── .gitignore │ └── .metadata └── odoochat_example.dart ├── analysis_options.yaml ├── .gitignore ├── CHANGELOG.md ├── pubspec.yaml ├── LICENSE └── README.md /.pubignore: -------------------------------------------------------------------------------- 1 | example/odoochat_example/ -------------------------------------------------------------------------------- /lib/odoochat.dart: -------------------------------------------------------------------------------- 1 | export 'src/odoochat.dart'; 2 | -------------------------------------------------------------------------------- /example/odoochat_example/README.md: -------------------------------------------------------------------------------- 1 | # odoochat_example 2 | 3 | https://pub.dev/packages/odoochat -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Runner-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | #import "GeneratedPluginRegistrant.h" 2 | -------------------------------------------------------------------------------- /example/odoochat_example/lib/bloc/bloc.dart: -------------------------------------------------------------------------------- 1 | export 'chat_bloc.dart'; 2 | export 'chat_poll/chat_poll.dart'; 3 | -------------------------------------------------------------------------------- /example/odoochat_example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx4G 2 | android.useAndroidX=true 3 | android.enableJetifier=true 4 | -------------------------------------------------------------------------------- /example/odoochat_example/web/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/web/favicon.png -------------------------------------------------------------------------------- /example/odoochat_example/web/icons/Icon-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/web/icons/Icon-192.png -------------------------------------------------------------------------------- /example/odoochat_example/web/icons/Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/web/icons/Icon-512.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig" 2 | #include "Generated.xcconfig" 3 | -------------------------------------------------------------------------------- /example/odoochat_example/web/icons/Icon-maskable-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/web/icons/Icon-maskable-192.png -------------------------------------------------------------------------------- /example/odoochat_example/web/icons/Icon-maskable-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/web/icons/Icon-maskable-512.png -------------------------------------------------------------------------------- /example/odoochat_example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:odoochat_example/app.dart'; 3 | 4 | void main() { 5 | runApp(const App()); 6 | } 7 | -------------------------------------------------------------------------------- /example/odoochat_example/analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.yaml 2 | 3 | linter: 4 | rules: 5 | public_member_api_docs: false 6 | flutter_style_todos: false 7 | -------------------------------------------------------------------------------- /example/odoochat_example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/odoochat_example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/odoochat_example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/src/model/model.dart: -------------------------------------------------------------------------------- 1 | export 'attachment/attachment.dart'; 2 | export 'channel/channel.dart'; 3 | export 'message/message.dart'; 4 | export 'message_info/message_info.dart'; 5 | export 'partner/partner.dart'; 6 | -------------------------------------------------------------------------------- /example/odoochat_example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/odoochat_example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /lib/src/api/responses/responses.dart: -------------------------------------------------------------------------------- 1 | export 'init_messaging_result/init_messaging_result.dart'; 2 | export 'login_result/login_result.dart'; 3 | export 'poll_result/poll_result.dart'; 4 | export 'rpc_response/rpc_response.dart'; 5 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/odoochat_example/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "OdooChat", 5 | "type": "dart", 6 | "request": "launch", 7 | "program": "lib/main.dart", 8 | }, 9 | ] 10 | } -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/odoochat_example/android/app/src/main/kotlin/com/luisciber/odoochat_example/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.luisciber.odoochat_example 2 | 3 | import io.flutter.embedding.android.FlutterActivity 4 | 5 | class MainActivity: FlutterActivity() { 6 | } 7 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luiscib3r/odoochat_flutter/HEAD/example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/odoochat_example/lib/bloc/chat_poll/chat_poll.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: always_use_package_imports 2 | 3 | import 'chat_poll_isolate.dart' if (dart.library.html) 'chat_poll_worker.dart' 4 | as chat_poll; 5 | 6 | typedef ChatPoll = chat_poll.ChatPoll; 7 | -------------------------------------------------------------------------------- /example/odoochat_example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip 6 | -------------------------------------------------------------------------------- /lib/src/exceptions/exceptions.dart: -------------------------------------------------------------------------------- 1 | class OdooChatException implements Exception { 2 | OdooChatException({ 3 | required this.code, 4 | required this.message, 5 | this.data, 6 | }); 7 | 8 | final int code; 9 | final String message; 10 | Map? data; 11 | } 12 | -------------------------------------------------------------------------------- /analysis_options.yaml: -------------------------------------------------------------------------------- 1 | include: package:very_good_analysis/analysis_options.yaml 2 | 3 | linter: 4 | rules: 5 | public_member_api_docs: false 6 | flutter_style_todos: false 7 | 8 | analyzer: 9 | errors: 10 | invalid_annotation_target: ignore 11 | exclude: 12 | - lib/**/*.g.dart 13 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/odoochat_example/android/.gitignore: -------------------------------------------------------------------------------- 1 | gradle-wrapper.jar 2 | /.gradle 3 | /captures/ 4 | /gradlew 5 | /gradlew.bat 6 | /local.properties 7 | GeneratedPluginRegistrant.java 8 | 9 | # Remember to never publicly share your keystore. 10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app 11 | key.properties 12 | **/*.keystore 13 | **/*.jks 14 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/RunnerTests/RunnerTests.swift: -------------------------------------------------------------------------------- 1 | import Flutter 2 | import UIKit 3 | import XCTest 4 | 5 | class RunnerTests: XCTestCase { 6 | 7 | func testExample() { 8 | // If you add code to the Runner application, consider adding tests here. 9 | // See https://developer.apple.com/documentation/xctest for more information about using XCTest. 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Files and directories created by pub 2 | .dart_tool/ 3 | .packages 4 | 5 | # Omit commiting pubspec.lock for library packages: 6 | # https://dart.dev/guides/libraries/private-files#pubspeclock 7 | pubspec.lock 8 | 9 | # Conventional directory for build outputs 10 | build/ 11 | 12 | # Directory created by dartdoc 13 | doc/api/ 14 | 15 | bin/ 16 | 17 | json_responses_examples/ 18 | .flutter-plugins 19 | .flutter-plugins-dependencies -------------------------------------------------------------------------------- /example/odoochat_example/android/app/src/debug/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/odoochat_example/android/app/src/profile/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import Flutter 3 | 4 | @UIApplicationMain 5 | @objc class AppDelegate: FlutterAppDelegate { 6 | override func application( 7 | _ application: UIApplication, 8 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 9 | ) -> Bool { 10 | GeneratedPluginRegistrant.register(with: self) 11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/src/payload/login_params/login_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'login_params.freezed.dart'; 4 | part 'login_params.g.dart'; 5 | 6 | @freezed 7 | class LoginParams with _$LoginParams { 8 | const factory LoginParams({ 9 | required String login, 10 | required String password, 11 | required String db, 12 | }) = _LoginParams; 13 | 14 | factory LoginParams.fromJson(Map json) => 15 | _$LoginParamsFromJson(json); 16 | } 17 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 2.1.1 2 | 3 | - **FIX**: fix some nullable fields. 4 | 5 | ## 2.1.0 6 | 7 | - **FEAT**: compatible with odoo 15. 8 | 9 | ## 2.0.0 10 | 11 | - Major refactor of the entire package after 3 years 12 | - Updated dependencies to their latest versions 13 | - Enhanced code readability and maintainability by adopting best practices 14 | - Updated documentation with more examples and use cases 15 | - Improved error handling and reporting 16 | 17 | ## 1.0.0 18 | 19 | - Initial version, created by Stagehand 20 | -------------------------------------------------------------------------------- /lib/src/payload/payload.dart: -------------------------------------------------------------------------------- 1 | export 'get_messages_params/get_messages_params.dart'; 2 | export 'init_messaging_params/init_messaging_params.dart'; 3 | export 'login_params/login_params.dart'; 4 | export 'message_fetch_params/message_fetch_params.dart'; 5 | export 'message_post_params/message_post_params.dart'; 6 | export 'poll_params/poll_params.dart'; 7 | export 'rpc_payload/rpc_payload.dart'; 8 | export 'send_message_params/send_message_params.dart'; 9 | export 'upload_attachment_payload/upload_attachment_payload.dart'; 10 | -------------------------------------------------------------------------------- /lib/src/payload/init_messaging_params/init_messaging_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'init_messaging_params.freezed.dart'; 4 | part 'init_messaging_params.g.dart'; 5 | 6 | @freezed 7 | class InitMessagingParams with _$InitMessagingParams { 8 | const factory InitMessagingParams({ 9 | required Map context, 10 | }) = _InitMessagingParams; 11 | 12 | factory InitMessagingParams.fromJson(Map json) => 13 | _$InitMessagingParamsFromJson(json); 14 | } 15 | -------------------------------------------------------------------------------- /example/odoochat_example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/odoochat_example/android/app/src/main/res/drawable-v21/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /lib/src/model/attachment/attachment.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'attachment.freezed.dart'; 4 | part 'attachment.g.dart'; 5 | 6 | @freezed 7 | class Attachment with _$Attachment { 8 | const factory Attachment({ 9 | required int id, 10 | required String checksum, 11 | required String filename, 12 | required String name, 13 | required String mimetype, 14 | }) = _Attachment; 15 | 16 | factory Attachment.fromJson(Map json) => 17 | _$AttachmentFromJson(json); 18 | } 19 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/src/payload/get_messages_params/get_messages_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'get_messages_params.freezed.dart'; 4 | part 'get_messages_params.g.dart'; 5 | 6 | @freezed 7 | class GetMessagesParams with _$GetMessagesParams { 8 | const factory GetMessagesParams({ 9 | @JsonKey(name: 'channel_id') required int channelId, 10 | required int limit, 11 | }) = _GetMessagesParams; 12 | 13 | factory GetMessagesParams.fromJson(Map json) => 14 | _$GetMessagesParamsFromJson(json); 15 | } 16 | -------------------------------------------------------------------------------- /example/odoochat_example/lib/chat_poll_worker.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_web_libraries_in_flutter 2 | 3 | import 'dart:html'; 4 | import 'dart:js_interop'; 5 | 6 | import 'package:odoochat/odoochat.dart'; 7 | import 'package:odoochat_example/bloc/chat_poll/chat_poll_worker.dart'; 8 | 9 | @JS('self') 10 | external JSObject get _self; 11 | DedicatedWorkerGlobalScope get self => _self as DedicatedWorkerGlobalScope; 12 | 13 | Future main() async { 14 | await ChatPollServiceWorker( 15 | self: self, 16 | odooChat: OdooChat( 17 | serverUrl: 'http://localhost:8069', 18 | databaseName: 'luisciber', 19 | debug: true, 20 | ), 21 | ).run(); 22 | } 23 | -------------------------------------------------------------------------------- /example/odoochat_example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | ext.kotlin_version = '1.7.10' 3 | repositories { 4 | google() 5 | mavenCentral() 6 | } 7 | 8 | dependencies { 9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 10 | } 11 | } 12 | 13 | allprojects { 14 | repositories { 15 | google() 16 | mavenCentral() 17 | } 18 | } 19 | 20 | rootProject.buildDir = '../build' 21 | subprojects { 22 | project.buildDir = "${rootProject.buildDir}/${project.name}" 23 | } 24 | subprojects { 25 | project.evaluationDependsOn(':app') 26 | } 27 | 28 | tasks.register("clean", Delete) { 29 | delete rootProject.buildDir 30 | } 31 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | **/dgph 2 | *.mode1v3 3 | *.mode2v3 4 | *.moved-aside 5 | *.pbxuser 6 | *.perspectivev3 7 | **/*sync/ 8 | .sconsign.dblite 9 | .tags* 10 | **/.vagrant/ 11 | **/DerivedData/ 12 | Icon? 13 | **/Pods/ 14 | **/.symlinks/ 15 | profile 16 | xcuserdata 17 | **/.generated/ 18 | Flutter/App.framework 19 | Flutter/Flutter.framework 20 | Flutter/Flutter.podspec 21 | Flutter/Generated.xcconfig 22 | Flutter/ephemeral/ 23 | Flutter/app.flx 24 | Flutter/app.zip 25 | Flutter/flutter_assets/ 26 | Flutter/flutter_export_environment.sh 27 | ServiceDefinitions.json 28 | Runner/GeneratedPluginRegistrant.* 29 | 30 | # Exceptions to above rules. 31 | !default.mode1v3 32 | !default.mode2v3 33 | !default.pbxuser 34 | !default.perspectivev3 35 | -------------------------------------------------------------------------------- /lib/src/model/partner/partner.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'partner.freezed.dart'; 4 | part 'partner.g.dart'; 5 | 6 | @freezed 7 | class Partner with _$Partner { 8 | const factory Partner({ 9 | required int id, 10 | required String name, 11 | required String email, 12 | required bool active, 13 | @JsonKey(name: 'im_status') required String imStatus, 14 | @JsonKey(name: 'is_internal_user', defaultValue: false) 15 | required bool isInternalUser, 16 | @JsonKey(name: 'user_id') int? userId, 17 | @JsonKey(name: 'display_name') String? displayName, 18 | }) = _Partner; 19 | 20 | factory Partner.fromJson(Map json) => 21 | _$PartnerFromJson(json); 22 | } 23 | -------------------------------------------------------------------------------- /lib/src/payload/init_messaging_params/init_messaging_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'init_messaging_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$InitMessagingParamsImpl _$$InitMessagingParamsImplFromJson( 10 | Map json) => 11 | _$InitMessagingParamsImpl( 12 | context: json['context'] as Map, 13 | ); 14 | 15 | Map _$$InitMessagingParamsImplToJson( 16 | _$InitMessagingParamsImpl instance) => 17 | { 18 | 'context': instance.context, 19 | }; 20 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: odoochat 2 | description: Dart package to connect to Odoo Discuss Module 3 | version: 2.1.1 4 | homepage: https://www.luisciber.com 5 | repository: https://github.com/luiscib3r/odoochat_flutter 6 | issue_tracker: https://github.com/luiscib3r/odoochat_flutter/issues 7 | topics: [odoo, chat, messaging] 8 | 9 | environment: 10 | sdk: ^3.0.0 11 | 12 | dependencies: 13 | cookie_jar: ^4.0.8 14 | dio: ^5.4.0 15 | dio_cookie_manager: ^3.1.1 16 | equatable: ^2.0.5 17 | freezed_annotation: ^2.4.1 18 | json_annotation: ^4.8.1 19 | retrofit: ^4.0.3 20 | 21 | dev_dependencies: 22 | build_runner: ^2.4.8 23 | freezed: ^2.4.6 24 | json_serializable: ^6.7.1 25 | pedantic: ^1.9.0 26 | retrofit_generator: ^8.0.6 27 | very_good_analysis: ^5.1.0 28 | -------------------------------------------------------------------------------- /lib/src/payload/poll_params/poll_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'poll_params.freezed.dart'; 4 | part 'poll_params.g.dart'; 5 | 6 | @freezed 7 | class PollParams with _$PollParams { 8 | factory PollParams({ 9 | required int last, 10 | }) => 11 | PollParams._( 12 | last: last, 13 | channels: ['bundle_changed'], 14 | options: { 15 | 'bus_inactivity': 0, 16 | }, 17 | ); 18 | 19 | const factory PollParams._({ 20 | required int last, 21 | required List channels, 22 | required Map options, 23 | }) = _PollParams; 24 | 25 | factory PollParams.fromJson(Map json) => 26 | _$PollParamsFromJson(json); 27 | } 28 | -------------------------------------------------------------------------------- /lib/src/payload/login_params/login_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'login_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$LoginParamsImpl _$$LoginParamsImplFromJson(Map json) => 10 | _$LoginParamsImpl( 11 | login: json['login'] as String, 12 | password: json['password'] as String, 13 | db: json['db'] as String, 14 | ); 15 | 16 | Map _$$LoginParamsImplToJson(_$LoginParamsImpl instance) => 17 | { 18 | 'login': instance.login, 19 | 'password': instance.password, 20 | 'db': instance.db, 21 | }; 22 | -------------------------------------------------------------------------------- /example/odoochat_example/lib/bloc/chat_state.dart: -------------------------------------------------------------------------------- 1 | part of 'chat_bloc.dart'; 2 | 3 | @freezed 4 | class OdooChatState with _$OdooChatState { 5 | const factory OdooChatState({ 6 | required bool loading, 7 | required List messages, 8 | required List channels, 9 | AppChannel? currentChannel, 10 | User? user, 11 | }) = _OdooChatState; 12 | 13 | factory OdooChatState.initial() => const OdooChatState( 14 | loading: false, 15 | messages: [], 16 | channels: [], 17 | ); 18 | } 19 | 20 | class AppChannel extends Equatable { 21 | const AppChannel({ 22 | required this.id, 23 | required this.name, 24 | }); 25 | 26 | final int id; 27 | final String name; 28 | 29 | @override 30 | List get props => [id, name]; 31 | } 32 | -------------------------------------------------------------------------------- /lib/src/payload/get_messages_params/get_messages_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'get_messages_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$GetMessagesParamsImpl _$$GetMessagesParamsImplFromJson( 10 | Map json) => 11 | _$GetMessagesParamsImpl( 12 | channelId: json['channel_id'] as int, 13 | limit: json['limit'] as int, 14 | ); 15 | 16 | Map _$$GetMessagesParamsImplToJson( 17 | _$GetMessagesParamsImpl instance) => 18 | { 19 | 'channel_id': instance.channelId, 20 | 'limit': instance.limit, 21 | }; 22 | -------------------------------------------------------------------------------- /lib/src/api/responses/poll_result/poll_result.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'poll_result.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$PollResultImpl _$$PollResultImplFromJson(Map json) => 10 | _$PollResultImpl( 11 | id: json['id'] as int, 12 | channel: json['channel'] as List?, 13 | message: PollMessage.fromResult(json['message'] as Map?), 14 | ); 15 | 16 | Map _$$PollResultImplToJson(_$PollResultImpl instance) => 17 | { 18 | 'id': instance.id, 19 | 'channel': instance.channel, 20 | 'message': instance.message?.toJson(), 21 | }; 22 | -------------------------------------------------------------------------------- /example/odoochat_example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: odoochat_example 2 | description: 'Odoo Chat Example' 3 | 4 | publish_to: 'none' 5 | 6 | version: 1.0.0+1 7 | 8 | environment: 9 | sdk: '>=3.2.4 <4.0.0' 10 | 11 | dependencies: 12 | bloc: ^8.1.2 13 | cupertino_icons: ^1.0.2 14 | equatable: ^2.0.5 15 | file_picker: ^5.2.10 16 | flutter: 17 | sdk: flutter 18 | flutter_bloc: ^8.1.3 19 | flutter_chat_types: ^3.6.2 20 | flutter_chat_ui: ^1.6.10 21 | flutter_html: ^2.2.1 22 | flutter_login: ^5.0.0 23 | freezed_annotation: ^2.4.1 24 | intl: ^0.19.0 25 | odoochat: 26 | path: ../.. 27 | open_filex: ^4.3.4 28 | path: ^1.8.3 29 | path_provider: ^2.1.2 30 | 31 | dev_dependencies: 32 | build_runner: ^2.4.8 33 | flutter_test: 34 | sdk: flutter 35 | freezed: ^2.4.6 36 | very_good_analysis: ^5.1.0 37 | 38 | flutter: 39 | uses-material-design: true 40 | -------------------------------------------------------------------------------- /lib/src/payload/poll_params/poll_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'poll_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$PollParamsImpl _$$PollParamsImplFromJson(Map json) => 10 | _$PollParamsImpl( 11 | last: json['last'] as int, 12 | channels: 13 | (json['channels'] as List).map((e) => e as String).toList(), 14 | options: json['options'] as Map, 15 | ); 16 | 17 | Map _$$PollParamsImplToJson(_$PollParamsImpl instance) => 18 | { 19 | 'last': instance.last, 20 | 'channels': instance.channels, 21 | 'options': instance.options, 22 | }; 23 | -------------------------------------------------------------------------------- /example/odoochat_example/lib/login.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_bloc/flutter_bloc.dart'; 3 | import 'package:flutter_login/flutter_login.dart'; 4 | import 'package:odoochat/odoochat.dart'; 5 | import 'package:odoochat_example/chat.dart'; 6 | 7 | class LoginPage extends StatelessWidget { 8 | const LoginPage({super.key}); 9 | 10 | @override 11 | Widget build(BuildContext context) { 12 | final odooChat = context.read(); 13 | 14 | return FlutterLogin( 15 | title: 'OdooChat', 16 | onLogin: (data) async { 17 | await odooChat.login( 18 | username: data.name, 19 | password: data.password, 20 | ); 21 | 22 | return null; 23 | }, 24 | onSubmitAnimationCompleted: () => ChatPage.open(context), 25 | onRecoverPassword: (_) => null, 26 | ); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /example/odoochat_example/.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | migrate_working_dir/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # The .vscode folder contains launch configuration and tasks you configure in 20 | # VS Code which you may wish to be included in version control, so this line 21 | # is commented out by default. 22 | #.vscode/ 23 | 24 | # Flutter/Dart/Pub related 25 | **/doc/api/ 26 | **/ios/Flutter/.last_build_id 27 | .dart_tool/ 28 | .flutter-plugins 29 | .flutter-plugins-dependencies 30 | .pub-cache/ 31 | .pub/ 32 | /build/ 33 | 34 | # Symbolication related 35 | app.*.symbols 36 | 37 | # Obfuscation related 38 | app.*.map.json 39 | 40 | # Android Studio will place build artifacts here 41 | /android/app/debug 42 | /android/app/profile 43 | /android/app/release 44 | -------------------------------------------------------------------------------- /lib/src/payload/upload_attachment_payload/upload_attachment_payload.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:dio/dio.dart'; 4 | import 'package:equatable/equatable.dart'; 5 | 6 | class UploadAttachmentPayload extends Equatable { 7 | const UploadAttachmentPayload({ 8 | required this.file, 9 | required this.fileName, 10 | required this.token, 11 | }); 12 | 13 | final String token; 14 | final Uint8List file; 15 | final String fileName; 16 | 17 | FormData get payload => FormData.fromMap({ 18 | 'id': 0, 19 | 'csrf_token': token, 20 | 'model': 'mail.compose.message', 21 | 'ufile': MultipartFile.fromBytes( 22 | file, 23 | filename: fileName, 24 | ), 25 | 'callback': '', 26 | }); 27 | 28 | @override 29 | List get props => [ 30 | token, 31 | file, 32 | fileName, 33 | ]; 34 | } 35 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 12.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /lib/src/model/attachment/attachment.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'attachment.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$AttachmentImpl _$$AttachmentImplFromJson(Map json) => 10 | _$AttachmentImpl( 11 | id: json['id'] as int, 12 | checksum: json['checksum'] as String, 13 | filename: json['filename'] as String, 14 | name: json['name'] as String, 15 | mimetype: json['mimetype'] as String, 16 | ); 17 | 18 | Map _$$AttachmentImplToJson(_$AttachmentImpl instance) => 19 | { 20 | 'id': instance.id, 21 | 'checksum': instance.checksum, 22 | 'filename': instance.filename, 23 | 'name': instance.name, 24 | 'mimetype': instance.mimetype, 25 | }; 26 | -------------------------------------------------------------------------------- /example/odoochat_example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | def flutterSdkPath = { 3 | def properties = new Properties() 4 | file("local.properties").withInputStream { properties.load(it) } 5 | def flutterSdkPath = properties.getProperty("flutter.sdk") 6 | assert flutterSdkPath != null, "flutter.sdk not set in local.properties" 7 | return flutterSdkPath 8 | } 9 | settings.ext.flutterSdkPath = flutterSdkPath() 10 | 11 | includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") 12 | 13 | repositories { 14 | google() 15 | mavenCentral() 16 | gradlePluginPortal() 17 | } 18 | 19 | plugins { 20 | id "dev.flutter.flutter-gradle-plugin" version "1.0.0" apply false 21 | } 22 | } 23 | 24 | plugins { 25 | id "dev.flutter.flutter-plugin-loader" version "1.0.0" 26 | id "com.android.application" version "7.3.0" apply false 27 | } 28 | 29 | include ":app" 30 | -------------------------------------------------------------------------------- /lib/src/payload/message_post_params/message_post_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'message_post_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$MessagePostParamsImpl _$$MessagePostParamsImplFromJson( 10 | Map json) => 11 | _$MessagePostParamsImpl( 12 | args: json['args'] as List, 13 | kwargs: json['kwargs'] as Map, 14 | method: json['method'] as String, 15 | model: json['model'] as String, 16 | ); 17 | 18 | Map _$$MessagePostParamsImplToJson( 19 | _$MessagePostParamsImpl instance) => 20 | { 21 | 'args': instance.args, 22 | 'kwargs': instance.kwargs, 23 | 'method': instance.method, 24 | 'model': instance.model, 25 | }; 26 | -------------------------------------------------------------------------------- /lib/src/payload/rpc_payload/rpc_payload.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'rpc_payload.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | RpcPayload _$RpcPayloadFromJson( 10 | Map json, 11 | T Function(Object? json) fromJsonT, 12 | ) => 13 | RpcPayload( 14 | id: json['id'] as int, 15 | jsonrpc: json['jsonrpc'] as String, 16 | method: json['method'] as String, 17 | params: fromJsonT(json['params']), 18 | ); 19 | 20 | Map _$RpcPayloadToJson( 21 | RpcPayload instance, 22 | Object? Function(T value) toJsonT, 23 | ) => 24 | { 25 | 'id': instance.id, 26 | 'jsonrpc': instance.jsonrpc, 27 | 'method': instance.method, 28 | 'params': toJsonT(instance.params), 29 | }; 30 | -------------------------------------------------------------------------------- /lib/src/payload/message_fetch_params/message_fetch_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'message_fetch_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$MessageFetchParamsImpl _$$MessageFetchParamsImplFromJson( 10 | Map json) => 11 | _$MessageFetchParamsImpl( 12 | args: json['args'] as List, 13 | kwargs: json['kwargs'] as Map, 14 | method: json['method'] as String, 15 | model: json['model'] as String, 16 | ); 17 | 18 | Map _$$MessageFetchParamsImplToJson( 19 | _$MessageFetchParamsImpl instance) => 20 | { 21 | 'args': instance.args, 22 | 'kwargs': instance.kwargs, 23 | 'method': instance.method, 24 | 'model': instance.model, 25 | }; 26 | -------------------------------------------------------------------------------- /example/odoochat_example/web/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "odoochat_example", 3 | "short_name": "odoochat_example", 4 | "start_url": ".", 5 | "display": "standalone", 6 | "background_color": "#0175C2", 7 | "theme_color": "#0175C2", 8 | "description": "A new Flutter project.", 9 | "orientation": "portrait-primary", 10 | "prefer_related_applications": false, 11 | "icons": [ 12 | { 13 | "src": "icons/Icon-192.png", 14 | "sizes": "192x192", 15 | "type": "image/png" 16 | }, 17 | { 18 | "src": "icons/Icon-512.png", 19 | "sizes": "512x512", 20 | "type": "image/png" 21 | }, 22 | { 23 | "src": "icons/Icon-maskable-192.png", 24 | "sizes": "192x192", 25 | "type": "image/png", 26 | "purpose": "maskable" 27 | }, 28 | { 29 | "src": "icons/Icon-maskable-512.png", 30 | "sizes": "512x512", 31 | "type": "image/png", 32 | "purpose": "maskable" 33 | } 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /example/odoochat_example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /example/odoochat_example/android/app/src/main/res/values-night/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 15 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Luis Antonio Correa Leyva 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/src/payload/message_fetch_params/message_fetch_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'message_fetch_params.freezed.dart'; 4 | part 'message_fetch_params.g.dart'; 5 | 6 | @freezed 7 | class MessageFetchParams with _$MessageFetchParams { 8 | factory MessageFetchParams({ 9 | required Map context, 10 | required int channelId, 11 | int limit = 30, 12 | }) => 13 | MessageFetchParams._( 14 | args: [], 15 | kwargs: { 16 | 'context': context, 17 | 'limit': limit, 18 | 'domain': [ 19 | [ 20 | 'channel_ids', 21 | 'in', 22 | [channelId], 23 | ] 24 | ], 25 | }, 26 | method: 'message_fetch', 27 | model: 'mail.message', 28 | ); 29 | 30 | const factory MessageFetchParams._({ 31 | required List args, 32 | required Map kwargs, 33 | required String method, 34 | required String model, 35 | }) = _MessageFetchParams; 36 | 37 | factory MessageFetchParams.fromJson(Map json) => 38 | _$MessageFetchParamsFromJson(json); 39 | } 40 | -------------------------------------------------------------------------------- /example/odoochat_example/lib/app.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | import 'package:flutter_bloc/flutter_bloc.dart'; 4 | import 'package:odoochat/odoochat.dart'; 5 | import 'package:odoochat_example/login.dart'; 6 | 7 | class App extends StatelessWidget { 8 | const App({super.key}); 9 | 10 | static const odooColor = Color(0xFFA34689); 11 | 12 | @override 13 | Widget build(BuildContext context) { 14 | return RepositoryProvider( 15 | create: (context) => OdooChat( 16 | // For Android Emulator 17 | // serverUrl: 'http://10.0.2.2:8069', 18 | // For iOS Emulator 19 | serverUrl: 'http://localhost:8069', 20 | databaseName: 'luisciber', 21 | debug: kDebugMode, 22 | ), 23 | child: MaterialApp( 24 | theme: ThemeData( 25 | primaryColor: odooColor, 26 | colorScheme: ColorScheme.fromSeed( 27 | seedColor: odooColor, 28 | primary: odooColor, 29 | ), 30 | ), 31 | title: 'Odoo Chat', 32 | home: const LoginPage(), 33 | debugShowCheckedModeBanner: false, 34 | ), 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/src/model/partner/partner.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'partner.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$PartnerImpl _$$PartnerImplFromJson(Map json) => 10 | _$PartnerImpl( 11 | id: json['id'] as int, 12 | name: json['name'] as String, 13 | email: json['email'] as String, 14 | active: json['active'] as bool, 15 | imStatus: json['im_status'] as String, 16 | isInternalUser: json['is_internal_user'] as bool? ?? false, 17 | userId: json['user_id'] as int?, 18 | displayName: json['display_name'] as String?, 19 | ); 20 | 21 | Map _$$PartnerImplToJson(_$PartnerImpl instance) => 22 | { 23 | 'id': instance.id, 24 | 'name': instance.name, 25 | 'email': instance.email, 26 | 'active': instance.active, 27 | 'im_status': instance.imStatus, 28 | 'is_internal_user': instance.isInternalUser, 29 | 'user_id': instance.userId, 30 | 'display_name': instance.displayName, 31 | }; 32 | -------------------------------------------------------------------------------- /lib/src/model/channel/channel.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'channel.freezed.dart'; 4 | part 'channel.g.dart'; 5 | 6 | @freezed 7 | class Channel with _$Channel { 8 | const factory Channel({ 9 | required int id, 10 | required String name, 11 | required String uuid, 12 | required String state, 13 | @JsonKey(name: 'is_minimized') required bool isMinimized, 14 | @JsonKey(name: 'channel_type') required String channelType, 15 | @JsonKey(name: 'group_based_subscription') 16 | required bool groupBasedSubscription, 17 | @JsonKey(name: 'create_uid') required int createUid, 18 | @JsonKey(name: 'message_needaction_counter') 19 | required int messageNeedactionCounter, 20 | @JsonKey(name: 'message_unread_counter') required int messageUnreadCounter, 21 | @JsonKey(name: 'is_pinned') required bool isPinned, 22 | @JsonKey(name: 'last_message_id', fromJson: Channel.parseIntNullable) 23 | int? lastMessageId, 24 | @JsonKey(name: 'seen_message_id', fromJson: Channel.parseIntNullable) 25 | int? seenMessageId, 26 | }) = _Channel; 27 | 28 | factory Channel.fromJson(Map json) => 29 | _$ChannelFromJson(json); 30 | 31 | static int? parseIntNullable(dynamic value) => 32 | value is bool ? null : value as int?; 33 | } 34 | -------------------------------------------------------------------------------- /lib/src/payload/rpc_payload/rpc_payload.dart: -------------------------------------------------------------------------------- 1 | import 'dart:math'; 2 | 3 | import 'package:equatable/equatable.dart'; 4 | import 'package:freezed_annotation/freezed_annotation.dart'; 5 | 6 | part 'rpc_payload.g.dart'; 7 | 8 | @JsonSerializable(genericArgumentFactories: true) 9 | class RpcPayload extends Equatable { 10 | const RpcPayload({ 11 | required this.id, 12 | required this.jsonrpc, 13 | required this.method, 14 | required this.params, 15 | }); 16 | 17 | factory RpcPayload.from({ 18 | required T params, 19 | }) => 20 | RpcPayload( 21 | id: Random().nextInt(999999999), 22 | jsonrpc: '2.0', 23 | method: 'call', 24 | params: params, 25 | ); 26 | 27 | factory RpcPayload.fromJson( 28 | Map json, 29 | T Function(Object? json) fromJsonT, 30 | ) => 31 | _$RpcPayloadFromJson(json, fromJsonT); 32 | 33 | final int id; 34 | final String jsonrpc; 35 | final String method; 36 | final T params; 37 | 38 | Map toJson( 39 | Object? Function(T value) toJsonT, 40 | ) => 41 | _$RpcPayloadToJson( 42 | this, 43 | toJsonT, 44 | ); 45 | 46 | @override 47 | List get props => [ 48 | id, 49 | jsonrpc, 50 | method, 51 | params, 52 | ]; 53 | } 54 | -------------------------------------------------------------------------------- /lib/src/payload/message_post_params/message_post_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'message_post_params.freezed.dart'; 4 | part 'message_post_params.g.dart'; 5 | 6 | @freezed 7 | class MessagePostParams with _$MessagePostParams { 8 | factory MessagePostParams({ 9 | required int channelId, 10 | required String body, 11 | required Map context, 12 | List attachmentIds = const [], 13 | }) => 14 | MessagePostParams._( 15 | args: [channelId], 16 | kwargs: { 17 | 'attachment_ids': attachmentIds, 18 | 'body': body, 19 | 'context': context, 20 | 'channel_ids': const [], 21 | 'message_type': 'comment', 22 | 'partner_ids': const [], 23 | 'subtype_xmlid': 'mail.mt_comment', 24 | 'subtype_id': 'mail.mt_comment', 25 | }, 26 | method: 'message_post', 27 | model: 'mail.channel', 28 | ); 29 | 30 | const factory MessagePostParams._({ 31 | required List args, 32 | required Map kwargs, 33 | required String method, 34 | required String model, 35 | }) = _MessagePostParams; 36 | 37 | factory MessagePostParams.fromJson(Map json) => 38 | _$MessagePostParamsFromJson(json); 39 | } 40 | -------------------------------------------------------------------------------- /example/odoochat_example/lib/bloc/chat_poll/chat_poll_worker.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_web_libraries_in_flutter 2 | 3 | import 'dart:convert'; 4 | import 'dart:html'; 5 | 6 | import 'package:odoochat/odoochat.dart'; 7 | import 'package:odoochat_example/bloc/chat_poll/chat_poll_interface.dart'; 8 | 9 | typedef ChatPoll = ChatPollWorker; 10 | typedef ChatPollService = ChatPollServiceWorker; 11 | 12 | class ChatPollWorker extends ChatPollInterface { 13 | ChatPollWorker({required super.odooChat}); 14 | 15 | late final Worker _worker; 16 | 17 | @override 18 | Stream> get serviceStream => _worker.onMessage.map((event) { 19 | final data = json.decode(event as String); 20 | return (data as List) 21 | .map((e) => PollResult.fromJson(e as Map)) 22 | .toList(); 23 | }); 24 | 25 | @override 26 | Future startService() async { 27 | _worker = Worker('chat_poll_worker.dart.js'); 28 | } 29 | } 30 | 31 | class ChatPollServiceWorker extends ChatPollServiceInterface { 32 | ChatPollServiceWorker({ 33 | required this.self, 34 | required super.odooChat, 35 | }); 36 | 37 | final DedicatedWorkerGlobalScope self; 38 | 39 | @override 40 | void emitState(List state) => self.postMessage( 41 | json.encode(state.map((e) => e.toJson()).toList()), 42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /example/odoochat_example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: "ef1af02aead6fe2414f3aafa5a61087b610e1332" 8 | channel: "stable" 9 | 10 | project_type: app 11 | 12 | # Tracks metadata for the flutter migrate command 13 | migration: 14 | platforms: 15 | - platform: root 16 | create_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332 17 | base_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332 18 | - platform: android 19 | create_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332 20 | base_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332 21 | - platform: ios 22 | create_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332 23 | base_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332 24 | - platform: web 25 | create_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332 26 | base_revision: ef1af02aead6fe2414f3aafa5a61087b610e1332 27 | 28 | # User provided section 29 | 30 | # List of Local paths (relative to this file) that should be 31 | # ignored by the migrate tool. 32 | # 33 | # Files that are not part of the templates will be ignored by default. 34 | unmanaged_files: 35 | - 'lib/main.dart' 36 | - 'ios/Runner.xcodeproj/project.pbxproj' 37 | -------------------------------------------------------------------------------- /lib/src/api/responses/rpc_response/rpc_response.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | 4 | part 'rpc_response.freezed.dart'; 5 | part 'rpc_response.g.dart'; 6 | 7 | @JsonSerializable(genericArgumentFactories: true) 8 | class RpcResponse extends Equatable { 9 | const RpcResponse({ 10 | required this.jsonrpc, 11 | required this.id, 12 | required this.result, 13 | this.error, 14 | }); 15 | 16 | factory RpcResponse.fromJson( 17 | Map json, 18 | T Function(Object? json) fromJsonT, 19 | ) => 20 | _$RpcResponseFromJson(json, fromJsonT); 21 | 22 | final String jsonrpc; 23 | final int id; 24 | final T? result; 25 | final RpcError? error; 26 | 27 | Map toJson( 28 | Object? Function(T value) toJsonT, 29 | ) => 30 | _$RpcResponseToJson( 31 | this, 32 | toJsonT, 33 | ); 34 | 35 | @override 36 | List get props => [ 37 | jsonrpc, 38 | id, 39 | result, 40 | error, 41 | ]; 42 | } 43 | 44 | @freezed 45 | class RpcError with _$RpcError { 46 | const factory RpcError({ 47 | required int code, 48 | required String message, 49 | required Map data, 50 | }) = _RpcError; 51 | 52 | factory RpcError.fromJson(Map json) => 53 | _$RpcErrorFromJson(json); 54 | } 55 | -------------------------------------------------------------------------------- /lib/src/model/message_info/message_info.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'message_info.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | MessageInfoTyping _$MessageInfoTypingFromJson(Map json) => 10 | MessageInfoTyping( 11 | isTyping: json['is_typing'] as bool, 12 | partnerId: json['partner_id'] as int, 13 | partnerName: json['partner_name'] as String, 14 | channelId: json['channel_id'] as int?, 15 | ); 16 | 17 | Map _$MessageInfoTypingToJson(MessageInfoTyping instance) => 18 | { 19 | 'is_typing': instance.isTyping, 20 | 'partner_id': instance.partnerId, 21 | 'partner_name': instance.partnerName, 22 | 'channel_id': instance.channelId, 23 | }; 24 | 25 | MessageInfoTransient _$MessageInfoTransientFromJson( 26 | Map json) => 27 | MessageInfoTransient( 28 | body: json['body'] as String, 29 | channelIds: 30 | (json['channel_ids'] as List).map((e) => e as int).toList(), 31 | ); 32 | 33 | Map _$MessageInfoTransientToJson( 34 | MessageInfoTransient instance) => 35 | { 36 | 'body': instance.body, 37 | 'channel_ids': instance.channelIds, 38 | }; 39 | -------------------------------------------------------------------------------- /example/odoochat_example/lib/bloc/chat_poll/chat_poll_interface.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | 3 | import 'package:bloc/bloc.dart'; 4 | import 'package:odoochat/odoochat.dart'; 5 | 6 | abstract class ChatPollInterface extends Cubit> { 7 | ChatPollInterface({ 8 | required this.odooChat, 9 | }) : super([]); 10 | 11 | final OdooChat odooChat; 12 | Stream> get serviceStream; 13 | late final StreamSubscription> _serviceSubscription; 14 | 15 | Future run() async { 16 | await startService(); 17 | 18 | _serviceSubscription = serviceStream.listen(emit); 19 | } 20 | 21 | Future startService(); 22 | 23 | @override 24 | Future close() async { 25 | await _serviceSubscription.cancel(); 26 | return super.close(); 27 | } 28 | } 29 | 30 | abstract class ChatPollServiceInterface extends Cubit> { 31 | ChatPollServiceInterface({ 32 | required this.odooChat, 33 | }) : super([]) { 34 | run(); 35 | } 36 | 37 | final OdooChat odooChat; 38 | 39 | Future run() async { 40 | while (true) { 41 | final result = await odooChat.poll(); 42 | emit(result); 43 | await Future.delayed(const Duration(milliseconds: 300)); 44 | } 45 | } 46 | 47 | void emitState(List state); 48 | 49 | @override 50 | void onChange(Change> change) { 51 | super.onChange(change); 52 | final state = change.nextState; 53 | emitState(state); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/src/api/odoochat_api.dart: -------------------------------------------------------------------------------- 1 | import 'package:dio/dio.dart'; 2 | import 'package:odoochat/odoochat.dart'; 3 | import 'package:retrofit/retrofit.dart'; 4 | 5 | export 'responses/responses.dart'; 6 | 7 | part 'odoochat_api.g.dart'; 8 | 9 | @RestApi() 10 | abstract class OdooChatApi { 11 | factory OdooChatApi( 12 | Dio dio, { 13 | required String baseUrl, 14 | }) = _OdooChatApi; 15 | 16 | @POST('/web/session/authenticate') 17 | Future> login( 18 | @Body() RpcPayload payload, 19 | ); 20 | 21 | @POST('/mail/init_messaging') 22 | Future> initMessaging( 23 | @Body() RpcPayload payload, 24 | ); 25 | 26 | @POST('/web/dataset/call_kw/mail.message/message_fetch') 27 | Future>> messageFetch( 28 | @Body() RpcPayload payload, 29 | ); 30 | 31 | @POST('/mail/channel/messages') 32 | Future>> getMessages( 33 | @Body() RpcPayload payload, 34 | ); 35 | 36 | @POST('/web/dataset/call_kw/mail.channel/message_post') 37 | Future> messagePost( 38 | @Body() RpcPayload payload, 39 | ); 40 | 41 | @POST('/mail/message/post') 42 | Future> sendMessage( 43 | @Body() RpcPayload payload, 44 | ); 45 | 46 | @POST('/longpolling/poll') 47 | Future>> poll( 48 | @Body() RpcPayload payload, 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '12.0' 3 | 4 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency. 5 | ENV['COCOAPODS_DISABLE_STATS'] = 'true' 6 | 7 | project 'Runner', { 8 | 'Debug' => :debug, 9 | 'Profile' => :release, 10 | 'Release' => :release, 11 | } 12 | 13 | def flutter_root 14 | generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__) 15 | unless File.exist?(generated_xcode_build_settings_path) 16 | raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first" 17 | end 18 | 19 | File.foreach(generated_xcode_build_settings_path) do |line| 20 | matches = line.match(/FLUTTER_ROOT\=(.*)/) 21 | return matches[1].strip if matches 22 | end 23 | raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get" 24 | end 25 | 26 | require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root) 27 | 28 | flutter_ios_podfile_setup 29 | 30 | target 'Runner' do 31 | use_frameworks! 32 | use_modular_headers! 33 | 34 | flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) 35 | target 'RunnerTests' do 36 | inherit! :search_paths 37 | end 38 | end 39 | 40 | post_install do |installer| 41 | installer.pods_project.targets.each do |target| 42 | flutter_additional_ios_build_settings(target) 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/odoochat_example/lib/bloc/chat_poll/chat_poll_isolate.dart: -------------------------------------------------------------------------------- 1 | import 'dart:async'; 2 | import 'dart:isolate'; 3 | 4 | import 'package:odoochat/odoochat.dart'; 5 | import 'package:odoochat_example/bloc/chat_poll/chat_poll_interface.dart'; 6 | 7 | typedef ChatPoll = ChatPollIsolate; 8 | typedef ChatPollService = ChatPollServiceIsolate; 9 | 10 | class ChatPollIsolate extends ChatPollInterface { 11 | ChatPollIsolate({ 12 | required super.odooChat, 13 | }); 14 | 15 | late final Isolate _isolate; 16 | 17 | @override 18 | Stream> get serviceStream => _controller.stream; 19 | 20 | final StreamController> _controller = 21 | StreamController>.broadcast(); 22 | 23 | late final StreamSubscription _isolateSubscription; 24 | 25 | @override 26 | Future startService() async { 27 | final receivePort = ReceivePort(); 28 | 29 | _isolate = await Isolate.spawn(_start, [receivePort.sendPort]); 30 | 31 | _isolateSubscription = receivePort.listen((message) { 32 | _controller.add(message as List); 33 | }); 34 | } 35 | 36 | Future _start(List params) async { 37 | await ChatPollServiceIsolate( 38 | sendPort: params[0] as SendPort, 39 | odooChat: odooChat, 40 | ).run(); 41 | } 42 | 43 | @override 44 | Future close() async { 45 | await _isolateSubscription.cancel(); 46 | _isolate.kill(); 47 | return super.close(); 48 | } 49 | } 50 | 51 | class ChatPollServiceIsolate extends ChatPollServiceInterface { 52 | ChatPollServiceIsolate({ 53 | required SendPort sendPort, 54 | required super.odooChat, 55 | }) : _sendPort = sendPort; 56 | 57 | final SendPort _sendPort; 58 | 59 | @override 60 | void emitState(List state) => _sendPort.send(state); 61 | } 62 | -------------------------------------------------------------------------------- /lib/src/api/responses/init_messaging_result/init_messaging_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:odoochat/odoochat.dart'; 3 | 4 | part 'init_messaging_result.freezed.dart'; 5 | part 'init_messaging_result.g.dart'; 6 | 7 | @freezed 8 | class InitMessagingResult with _$InitMessagingResult { 9 | const factory InitMessagingResult({ 10 | @JsonKey(name: 'needaction_inbox_counter') 11 | required int needactionInboxCounter, 12 | @JsonKey(name: 'starred_counter') required int starredCounter, 13 | @JsonKey(name: 'current_partner') required Partner currentPartner, 14 | @JsonKey(name: 'current_user_id') required int currentUserId, 15 | @JsonKey(name: 'channel_slots') ChannelSlots? channelSlots, 16 | @JsonKey(name: 'channels') List? channels_, 17 | }) = _InitMessagingResult; 18 | 19 | factory InitMessagingResult.fromJson(Map json) => 20 | _$InitMessagingResultFromJson(json); 21 | } 22 | 23 | extension InitMessagingResultExtension on InitMessagingResult { 24 | List get channels { 25 | if (channelSlots != null) { 26 | return [ 27 | ...channelSlots!.channels, 28 | ...channelSlots!.privateGroups, 29 | ...channelSlots!.directMessages, 30 | ]; 31 | } 32 | 33 | return channels_ ?? []; 34 | } 35 | } 36 | 37 | @freezed 38 | class ChannelSlots with _$ChannelSlots { 39 | const factory ChannelSlots({ 40 | @JsonKey(name: 'channel_channel') required List channels, 41 | @JsonKey(name: 'channel_direct_message') 42 | required List directMessages, 43 | @JsonKey(name: 'channel_private_group') 44 | required List privateGroups, 45 | }) = _ChannelSlots; 46 | 47 | factory ChannelSlots.fromJson(Map json) => 48 | _$ChannelSlotsFromJson(json); 49 | } 50 | -------------------------------------------------------------------------------- /example/odoochat_example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 15 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 30 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | Odoochat Example 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | odoochat_example 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(FLUTTER_BUILD_NAME) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(FLUTTER_BUILD_NUMBER) 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | CADisableMinimumFrameDurationOnPhone 45 | 46 | UIApplicationSupportsIndirectInputEvents 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /lib/src/model/channel/channel.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'channel.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$ChannelImpl _$$ChannelImplFromJson(Map json) => 10 | _$ChannelImpl( 11 | id: json['id'] as int, 12 | name: json['name'] as String, 13 | uuid: json['uuid'] as String, 14 | state: json['state'] as String, 15 | isMinimized: json['is_minimized'] as bool, 16 | channelType: json['channel_type'] as String, 17 | groupBasedSubscription: json['group_based_subscription'] as bool, 18 | createUid: json['create_uid'] as int, 19 | messageNeedactionCounter: json['message_needaction_counter'] as int, 20 | messageUnreadCounter: json['message_unread_counter'] as int, 21 | isPinned: json['is_pinned'] as bool, 22 | lastMessageId: Channel.parseIntNullable(json['last_message_id']), 23 | seenMessageId: Channel.parseIntNullable(json['seen_message_id']), 24 | ); 25 | 26 | Map _$$ChannelImplToJson(_$ChannelImpl instance) => 27 | { 28 | 'id': instance.id, 29 | 'name': instance.name, 30 | 'uuid': instance.uuid, 31 | 'state': instance.state, 32 | 'is_minimized': instance.isMinimized, 33 | 'channel_type': instance.channelType, 34 | 'group_based_subscription': instance.groupBasedSubscription, 35 | 'create_uid': instance.createUid, 36 | 'message_needaction_counter': instance.messageNeedactionCounter, 37 | 'message_unread_counter': instance.messageUnreadCounter, 38 | 'is_pinned': instance.isPinned, 39 | 'last_message_id': instance.lastMessageId, 40 | 'seen_message_id': instance.seenMessageId, 41 | }; 42 | -------------------------------------------------------------------------------- /lib/src/api/responses/login_result/login_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'login_result.freezed.dart'; 4 | part 'login_result.g.dart'; 5 | 6 | @freezed 7 | class LoginResult with _$LoginResult { 8 | const factory LoginResult({ 9 | required int uid, 10 | @JsonKey(name: 'is_system') required bool isSystem, 11 | @JsonKey(name: 'is_admin') required bool isAdmin, 12 | @JsonKey(name: 'user_context') required Map userContext, 13 | required String db, 14 | @JsonKey(name: 'server_version') required String serverVersion, 15 | @JsonKey(name: 'server_version_info') 16 | required List serverVersionInfo, 17 | required String name, 18 | required String username, 19 | @JsonKey(name: 'partner_display_name') required String partnerDisplayName, 20 | @JsonKey(name: 'partner_id') required int partnerId, 21 | @JsonKey(name: 'web.base.url') required String webBaseUrl, 22 | @JsonKey(name: 'active_ids_limit') required int activeIdsLimit, 23 | @JsonKey(name: 'max_file_upload_size') required int maxFileUploadSize, 24 | @JsonKey(name: 'user_companies') 25 | required Map userCompanies, 26 | required Map currencies, 27 | @JsonKey(name: 'display_switch_company_menu') 28 | required bool displaySwitchCompanyMenu, 29 | @JsonKey(name: 'cache_hashes') required Map cacheHashes, 30 | @JsonKey(name: 'user_id') required List userId, 31 | @JsonKey(name: 'web_tours') required List webTours, 32 | @JsonKey(name: 'notification_type') required String notificationType, 33 | @JsonKey(name: 'odoobot_initialized') required bool odoobotInitialized, 34 | @JsonKey(name: 'company_id') int? companyId, 35 | }) = _LoginResult; 36 | 37 | factory LoginResult.fromJson(Map json) => 38 | _$LoginResultFromJson(json); 39 | } 40 | -------------------------------------------------------------------------------- /lib/src/api/responses/rpc_response/rpc_response.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'rpc_response.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | RpcResponse _$RpcResponseFromJson( 10 | Map json, 11 | T Function(Object? json) fromJsonT, 12 | ) => 13 | RpcResponse( 14 | jsonrpc: json['jsonrpc'] as String, 15 | id: json['id'] as int, 16 | result: _$nullableGenericFromJson(json['result'], fromJsonT), 17 | error: json['error'] == null 18 | ? null 19 | : RpcError.fromJson(json['error'] as Map), 20 | ); 21 | 22 | Map _$RpcResponseToJson( 23 | RpcResponse instance, 24 | Object? Function(T value) toJsonT, 25 | ) => 26 | { 27 | 'jsonrpc': instance.jsonrpc, 28 | 'id': instance.id, 29 | 'result': _$nullableGenericToJson(instance.result, toJsonT), 30 | 'error': instance.error?.toJson(), 31 | }; 32 | 33 | T? _$nullableGenericFromJson( 34 | Object? input, 35 | T Function(Object? json) fromJson, 36 | ) => 37 | input == null ? null : fromJson(input); 38 | 39 | Object? _$nullableGenericToJson( 40 | T? input, 41 | Object? Function(T value) toJson, 42 | ) => 43 | input == null ? null : toJson(input); 44 | 45 | _$RpcErrorImpl _$$RpcErrorImplFromJson(Map json) => 46 | _$RpcErrorImpl( 47 | code: json['code'] as int, 48 | message: json['message'] as String, 49 | data: json['data'] as Map, 50 | ); 51 | 52 | Map _$$RpcErrorImplToJson(_$RpcErrorImpl instance) => 53 | { 54 | 'code': instance.code, 55 | 'message': instance.message, 56 | 'data': instance.data, 57 | }; 58 | -------------------------------------------------------------------------------- /lib/src/payload/send_message_params/send_message_params.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | 3 | part 'send_message_params.freezed.dart'; 4 | part 'send_message_params.g.dart'; 5 | 6 | @freezed 7 | class SendMessageParams with _$SendMessageParams { 8 | factory SendMessageParams({ 9 | required int channelId, 10 | required String body, 11 | required Map context, 12 | List attachmentIds = const [], 13 | }) => 14 | SendMessageParams._( 15 | context: context, 16 | postData: SendMessagePostData( 17 | attachmentIds: attachmentIds, 18 | attachmentTokens: [], 19 | body: body, 20 | messageType: 'comment', 21 | partnerIds: [], 22 | subtypeXmlid: 'mail.mt_comment', 23 | ), 24 | threadId: channelId, 25 | threadModel: 'mail.channel', 26 | ); 27 | 28 | const factory SendMessageParams._({ 29 | required Map context, 30 | @JsonKey(name: 'post_data') required SendMessagePostData postData, 31 | @JsonKey(name: 'thread_id') required int threadId, 32 | @JsonKey(name: 'thread_model') required String threadModel, 33 | }) = _SendMessageParams; 34 | 35 | factory SendMessageParams.fromJson(Map json) => 36 | _$SendMessageParamsFromJson(json); 37 | } 38 | 39 | @freezed 40 | class SendMessagePostData with _$SendMessagePostData { 41 | const factory SendMessagePostData({ 42 | @JsonKey(name: 'attachment_ids') required List attachmentIds, 43 | @JsonKey(name: 'attachment_tokens') required List attachmentTokens, 44 | required String body, 45 | @JsonKey(name: 'message_type') required String messageType, 46 | @JsonKey(name: 'partner_ids') required List partnerIds, 47 | @JsonKey(name: 'subtype_xmlid') required String subtypeXmlid, 48 | }) = _SendMessagePostData; 49 | 50 | factory SendMessagePostData.fromJson(Map json) => 51 | _$SendMessagePostDataFromJson(json); 52 | } 53 | -------------------------------------------------------------------------------- /example/odoochat_example/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | odoochat_example 33 | 34 | 35 | 39 | 40 | 41 | 42 | 43 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /lib/src/payload/send_message_params/send_message_params.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'send_message_params.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$SendMessageParamsImpl _$$SendMessageParamsImplFromJson( 10 | Map json) => 11 | _$SendMessageParamsImpl( 12 | context: json['context'] as Map, 13 | postData: SendMessagePostData.fromJson( 14 | json['post_data'] as Map), 15 | threadId: json['thread_id'] as int, 16 | threadModel: json['thread_model'] as String, 17 | ); 18 | 19 | Map _$$SendMessageParamsImplToJson( 20 | _$SendMessageParamsImpl instance) => 21 | { 22 | 'context': instance.context, 23 | 'post_data': instance.postData.toJson(), 24 | 'thread_id': instance.threadId, 25 | 'thread_model': instance.threadModel, 26 | }; 27 | 28 | _$SendMessagePostDataImpl _$$SendMessagePostDataImplFromJson( 29 | Map json) => 30 | _$SendMessagePostDataImpl( 31 | attachmentIds: (json['attachment_ids'] as List) 32 | .map((e) => e as int) 33 | .toList(), 34 | attachmentTokens: (json['attachment_tokens'] as List) 35 | .map((e) => e as int) 36 | .toList(), 37 | body: json['body'] as String, 38 | messageType: json['message_type'] as String, 39 | partnerIds: 40 | (json['partner_ids'] as List).map((e) => e as int).toList(), 41 | subtypeXmlid: json['subtype_xmlid'] as String, 42 | ); 43 | 44 | Map _$$SendMessagePostDataImplToJson( 45 | _$SendMessagePostDataImpl instance) => 46 | { 47 | 'attachment_ids': instance.attachmentIds, 48 | 'attachment_tokens': instance.attachmentTokens, 49 | 'body': instance.body, 50 | 'message_type': instance.messageType, 51 | 'partner_ids': instance.partnerIds, 52 | 'subtype_xmlid': instance.subtypeXmlid, 53 | }; 54 | -------------------------------------------------------------------------------- /example/odoochat_example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "com.android.application" 3 | id "kotlin-android" 4 | id "dev.flutter.flutter-gradle-plugin" 5 | } 6 | 7 | def localProperties = new Properties() 8 | def localPropertiesFile = rootProject.file('local.properties') 9 | if (localPropertiesFile.exists()) { 10 | localPropertiesFile.withReader('UTF-8') { reader -> 11 | localProperties.load(reader) 12 | } 13 | } 14 | 15 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 16 | if (flutterVersionCode == null) { 17 | flutterVersionCode = '1' 18 | } 19 | 20 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 21 | if (flutterVersionName == null) { 22 | flutterVersionName = '1.0' 23 | } 24 | 25 | android { 26 | namespace "com.luisciber.odoochat_example" 27 | compileSdkVersion flutter.compileSdkVersion 28 | ndkVersion flutter.ndkVersion 29 | 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | 35 | kotlinOptions { 36 | jvmTarget = '1.8' 37 | } 38 | 39 | sourceSets { 40 | main.java.srcDirs += 'src/main/kotlin' 41 | } 42 | 43 | defaultConfig { 44 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 45 | applicationId "com.luisciber.odoochat_example" 46 | // You can update the following values to match your application needs. 47 | // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. 48 | minSdkVersion 21 49 | targetSdkVersion flutter.targetSdkVersion 50 | versionCode flutterVersionCode.toInteger() 51 | versionName flutterVersionName 52 | } 53 | 54 | buildTypes { 55 | release { 56 | // TODO: Add your own signing config for the release build. 57 | // Signing with the debug keys for now, so `flutter run --release` works. 58 | signingConfig signingConfigs.debug 59 | } 60 | } 61 | } 62 | 63 | flutter { 64 | source '../..' 65 | } 66 | 67 | dependencies {} 68 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /lib/src/api/responses/init_messaging_result/init_messaging_result.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'init_messaging_result.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$InitMessagingResultImpl _$$InitMessagingResultImplFromJson( 10 | Map json) => 11 | _$InitMessagingResultImpl( 12 | needactionInboxCounter: json['needaction_inbox_counter'] as int, 13 | starredCounter: json['starred_counter'] as int, 14 | currentPartner: 15 | Partner.fromJson(json['current_partner'] as Map), 16 | currentUserId: json['current_user_id'] as int, 17 | channelSlots: json['channel_slots'] == null 18 | ? null 19 | : ChannelSlots.fromJson( 20 | json['channel_slots'] as Map), 21 | channels_: (json['channels'] as List?) 22 | ?.map((e) => Channel.fromJson(e as Map)) 23 | .toList(), 24 | ); 25 | 26 | Map _$$InitMessagingResultImplToJson( 27 | _$InitMessagingResultImpl instance) => 28 | { 29 | 'needaction_inbox_counter': instance.needactionInboxCounter, 30 | 'starred_counter': instance.starredCounter, 31 | 'current_partner': instance.currentPartner.toJson(), 32 | 'current_user_id': instance.currentUserId, 33 | 'channel_slots': instance.channelSlots?.toJson(), 34 | 'channels': instance.channels_?.map((e) => e.toJson()).toList(), 35 | }; 36 | 37 | _$ChannelSlotsImpl _$$ChannelSlotsImplFromJson(Map json) => 38 | _$ChannelSlotsImpl( 39 | channels: (json['channel_channel'] as List) 40 | .map((e) => Channel.fromJson(e as Map)) 41 | .toList(), 42 | directMessages: (json['channel_direct_message'] as List) 43 | .map((e) => Channel.fromJson(e as Map)) 44 | .toList(), 45 | privateGroups: (json['channel_private_group'] as List) 46 | .map((e) => Channel.fromJson(e as Map)) 47 | .toList(), 48 | ); 49 | 50 | Map _$$ChannelSlotsImplToJson(_$ChannelSlotsImpl instance) => 51 | { 52 | 'channel_channel': instance.channels.map((e) => e.toJson()).toList(), 53 | 'channel_direct_message': 54 | instance.directMessages.map((e) => e.toJson()).toList(), 55 | 'channel_private_group': 56 | instance.privateGroups.map((e) => e.toJson()).toList(), 57 | }; 58 | -------------------------------------------------------------------------------- /example/odoochat_example.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: avoid_print 2 | 3 | import 'package:odoochat/odoochat.dart'; 4 | 5 | Future main(List args) async { 6 | // Init 7 | final odooChat = OdooChat( 8 | serverUrl: 'http://localhost:8069', 9 | databaseName: 'luisciber', 10 | debug: true, 11 | ); 12 | 13 | // Login 14 | final loginResult = await odooChat.login( 15 | username: 'youruser@odoo.com', 16 | password: '12345678', 17 | ); 18 | 19 | print(loginResult); 20 | 21 | // Init messaging 22 | final messagingResult = await odooChat.initMessaging(); 23 | 24 | print('Current Partner: '); 25 | print(messagingResult.currentPartner); 26 | 27 | print('Channels, Private Messages, Groups: '); 28 | print(messagingResult.channels); 29 | 30 | if (messagingResult.channels.isEmpty) { 31 | print('No channels found'); 32 | return; 33 | } 34 | 35 | // Fetch messages 36 | final messages = await odooChat.fetchMessages( 37 | messagingResult.channels.first.id, 38 | ); 39 | 40 | print('Messages: '); 41 | for (final message in messages.reversed) { 42 | print(message.emailFrom); 43 | print(message.author); 44 | print(message.body); 45 | print(message.date); 46 | print('\n'); 47 | } 48 | 49 | // Send message 50 | final newMessageId = await odooChat.sendMessage( 51 | channelId: messagingResult.channels.first.id, 52 | message: 'Test message from OdooChat Flutter', 53 | ); 54 | 55 | print('New message id: $newMessageId'); 56 | 57 | // Poll 58 | while (await Future.delayed(const Duration(seconds: 3), () => true)) { 59 | final results = await odooChat.poll(); 60 | 61 | for (final result in results) { 62 | print('\n'); 63 | switch (result.message) { 64 | case PollMessageMessage(data: final Message data): 65 | print('Is a message'); 66 | print(data); 67 | case PollMessageChannel(data: final Channel data): 68 | print('Is a new channel notification'); 69 | print(data); 70 | case PollMessageInfo(data: final MessageInfo data): 71 | print('Is an info message'); // ex: typing, or bot messages 72 | switch (data) { 73 | case MessageInfoTyping( 74 | isTyping: final bool isTyping, 75 | partnerId: final int partnerId, 76 | partnerName: final String partnerName, 77 | ): 78 | print('Partner id: $partnerId'); 79 | print('Partner name: $partnerName'); 80 | print('Is typing: $isTyping'); 81 | 82 | case MessageInfoTransient( 83 | body: final String body, 84 | ): 85 | print('Transient message: $body'); 86 | } 87 | case null: 88 | print('Empty poll result'); 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /lib/src/model/message/message.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:odoochat/src/model/attachment/attachment.dart'; 3 | 4 | part 'message.freezed.dart'; 5 | part 'message.g.dart'; 6 | 7 | @freezed 8 | class Message with _$Message { 9 | const factory Message({ 10 | required int id, 11 | required String body, 12 | required String date, 13 | @JsonKey(name: 'author_id', fromJson: MessageAuthor.fromList) 14 | required MessageAuthor author, 15 | @JsonKey(name: 'email_from') required String emailFrom, 16 | @JsonKey(name: 'message_type') required String messageType, 17 | @JsonKey(name: 'subtype_id') required List subtypeId, 18 | required String model, 19 | @JsonKey(name: 'res_id') required int resId, 20 | @JsonKey(name: 'record_name') required String recordName, 21 | @JsonKey(name: 'partner_ids') required List partnerIds, 22 | @JsonKey(name: 'starred_partner_ids') required List starredPartnerIds, 23 | @JsonKey(name: 'moderation_status', fromJson: Message.parseModerationStatus) 24 | required String? moderationStatus, 25 | required List notifications, 26 | @JsonKey(name: 'attachment_ids') required List atachments, 27 | @JsonKey(name: 'tracking_value_ids') required List trackingValueIds, 28 | @JsonKey(name: 'needaction_partner_ids') 29 | required List needactionPartnerIds, 30 | @JsonKey(name: 'history_partner_ids') required List historyPartnerIds, 31 | @JsonKey(name: 'is_note') required bool isNote, 32 | @JsonKey(name: 'is_discussion') required bool isDiscussion, 33 | @JsonKey(name: 'subtype_description') required bool subtypeDescription, 34 | @JsonKey(name: 'is_notification') required bool isNotification, 35 | @JsonKey(name: 'module_icon') required String moduleIcon, 36 | @JsonKey(name: 'sms_ids') required List smsIds, 37 | }) = _Message; 38 | 39 | factory Message.fromJson(Map json) => 40 | _$MessageFromJson(json); 41 | 42 | static String? parseModerationStatus(dynamic value) => 43 | value is bool ? null : value as String?; 44 | } 45 | 46 | @freezed 47 | class MessageAuthor with _$MessageAuthor { 48 | const factory MessageAuthor({ 49 | required int id, 50 | required String name, 51 | String? company, 52 | }) = _MessageAuthor; 53 | 54 | factory MessageAuthor.fromList(List authorId) { 55 | final displayName = (authorId[1] as String).split(','); 56 | return MessageAuthor( 57 | id: authorId[0] as int, 58 | name: displayName.length > 1 59 | ? displayName[1].trim() 60 | : displayName[0].trim(), 61 | company: displayName.length > 1 ? displayName[0].trim() : null, 62 | ); 63 | } 64 | 65 | factory MessageAuthor.fromJson(Map json) => 66 | _$MessageAuthorFromJson(json); 67 | } 68 | -------------------------------------------------------------------------------- /lib/src/api/responses/login_result/login_result.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'login_result.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$LoginResultImpl _$$LoginResultImplFromJson(Map json) => 10 | _$LoginResultImpl( 11 | uid: json['uid'] as int, 12 | isSystem: json['is_system'] as bool, 13 | isAdmin: json['is_admin'] as bool, 14 | userContext: json['user_context'] as Map, 15 | db: json['db'] as String, 16 | serverVersion: json['server_version'] as String, 17 | serverVersionInfo: json['server_version_info'] as List, 18 | name: json['name'] as String, 19 | username: json['username'] as String, 20 | partnerDisplayName: json['partner_display_name'] as String, 21 | partnerId: json['partner_id'] as int, 22 | webBaseUrl: json['web.base.url'] as String, 23 | activeIdsLimit: json['active_ids_limit'] as int, 24 | maxFileUploadSize: json['max_file_upload_size'] as int, 25 | userCompanies: json['user_companies'] as Map, 26 | currencies: json['currencies'] as Map, 27 | displaySwitchCompanyMenu: json['display_switch_company_menu'] as bool, 28 | cacheHashes: json['cache_hashes'] as Map, 29 | userId: (json['user_id'] as List).map((e) => e as int).toList(), 30 | webTours: json['web_tours'] as List, 31 | notificationType: json['notification_type'] as String, 32 | odoobotInitialized: json['odoobot_initialized'] as bool, 33 | companyId: json['company_id'] as int?, 34 | ); 35 | 36 | Map _$$LoginResultImplToJson(_$LoginResultImpl instance) => 37 | { 38 | 'uid': instance.uid, 39 | 'is_system': instance.isSystem, 40 | 'is_admin': instance.isAdmin, 41 | 'user_context': instance.userContext, 42 | 'db': instance.db, 43 | 'server_version': instance.serverVersion, 44 | 'server_version_info': instance.serverVersionInfo, 45 | 'name': instance.name, 46 | 'username': instance.username, 47 | 'partner_display_name': instance.partnerDisplayName, 48 | 'partner_id': instance.partnerId, 49 | 'web.base.url': instance.webBaseUrl, 50 | 'active_ids_limit': instance.activeIdsLimit, 51 | 'max_file_upload_size': instance.maxFileUploadSize, 52 | 'user_companies': instance.userCompanies, 53 | 'currencies': instance.currencies, 54 | 'display_switch_company_menu': instance.displaySwitchCompanyMenu, 55 | 'cache_hashes': instance.cacheHashes, 56 | 'user_id': instance.userId, 57 | 'web_tours': instance.webTours, 58 | 'notification_type': instance.notificationType, 59 | 'odoobot_initialized': instance.odoobotInitialized, 60 | 'company_id': instance.companyId, 61 | }; 62 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /lib/src/model/message_info/message_info.dart: -------------------------------------------------------------------------------- 1 | import 'package:equatable/equatable.dart'; 2 | import 'package:freezed_annotation/freezed_annotation.dart'; 3 | 4 | part 'message_info.g.dart'; 5 | 6 | enum InfoType { 7 | typingStatus('typing_status'), 8 | transientMessage('transient_message'); 9 | 10 | const InfoType(this.value); 11 | 12 | factory InfoType.fromJson(String value) { 13 | switch (value) { 14 | case 'typing_status': 15 | return InfoType.typingStatus; 16 | case 'transient_message': 17 | return InfoType.transientMessage; 18 | default: 19 | throw Exception('Unknown InfoType: $value'); 20 | } 21 | } 22 | 23 | String toJson() => value; 24 | 25 | final String value; 26 | } 27 | 28 | sealed class MessageInfo extends Equatable { 29 | const MessageInfo(); 30 | 31 | static MessageInfo fromJson(Map json) { 32 | final type = InfoType.fromJson(json['info'] as String); 33 | return switch (type) { 34 | InfoType.typingStatus => MessageInfoTyping.fromJson(json), 35 | InfoType.transientMessage => MessageInfoTransient.fromJson(json), 36 | }; 37 | } 38 | 39 | Map toJson() => switch (this) { 40 | MessageInfoTyping() => (this as MessageInfoTyping).toJson(), 41 | MessageInfoTransient() => (this as MessageInfoTransient).toJson(), 42 | }; 43 | 44 | @override 45 | String toString() => switch (this) { 46 | MessageInfoTyping() => (this as MessageInfoTyping).toString(), 47 | MessageInfoTransient() => (this as MessageInfoTransient).toString(), 48 | }; 49 | } 50 | 51 | @JsonSerializable() 52 | class MessageInfoTyping extends MessageInfo { 53 | const MessageInfoTyping({ 54 | required this.isTyping, 55 | required this.partnerId, 56 | required this.partnerName, 57 | this.channelId, 58 | }); 59 | 60 | factory MessageInfoTyping.fromJson(Map json) => 61 | _$MessageInfoTypingFromJson(json); 62 | 63 | @override 64 | Map toJson() => _$MessageInfoTypingToJson(this); 65 | 66 | @JsonKey(name: 'is_typing') 67 | final bool isTyping; 68 | @JsonKey(name: 'partner_id') 69 | final int partnerId; 70 | @JsonKey(name: 'partner_name') 71 | final String partnerName; 72 | @JsonKey(name: 'channel_id') 73 | final int? channelId; 74 | 75 | @override 76 | List get props => [ 77 | isTyping, 78 | partnerId, 79 | partnerName, 80 | channelId, 81 | ]; 82 | 83 | @override 84 | String toString() => 85 | // ignore: lines_longer_than_80_chars 86 | 'MessageInfoTyping(isTyping: $isTyping, partnerId: $partnerId, parnerName: $partnerName)'; 87 | } 88 | 89 | @JsonSerializable() 90 | class MessageInfoTransient extends MessageInfo { 91 | const MessageInfoTransient({ 92 | required this.body, 93 | required this.channelIds, 94 | }); 95 | 96 | factory MessageInfoTransient.fromJson(Map json) => 97 | _$MessageInfoTransientFromJson(json); 98 | 99 | @override 100 | Map toJson() => _$MessageInfoTransientToJson(this); 101 | 102 | final String body; 103 | @JsonKey(name: 'channel_ids') 104 | final List channelIds; 105 | 106 | @override 107 | List get props => [body, channelIds]; 108 | 109 | @override 110 | String toString() => 111 | 'MessageInfoTransient(body: $body, channelIds: $channelIds)'; 112 | } 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## OdooChat. 2 | 3 | ### Example 4 | 5 | ```dart 6 | // ignore_for_file: avoid_print 7 | 8 | import 'package:odoochat/odoochat.dart'; 9 | 10 | Future main(List args) async { 11 | // Init 12 | final odooChat = OdooChat( 13 | serverUrl: 'http://localhost:8069', 14 | databaseName: 'luisciber', 15 | debug: true, 16 | ); 17 | 18 | // Login 19 | final loginResult = await odooChat.login( 20 | username: 'youruser@odoo.com', 21 | password: '12345678', 22 | ); 23 | 24 | print(loginResult); 25 | 26 | // Init messaging 27 | final messagingResult = await odooChat.initMessaging(); 28 | 29 | print('Current Partner: '); 30 | print(messagingResult.currentPartner); 31 | 32 | print('Channels, Private Messages, Groups: '); 33 | print(messagingResult.channels); 34 | 35 | if (messagingResult.channels.isEmpty) { 36 | print('No channels found'); 37 | return; 38 | } 39 | 40 | // Fetch messages 41 | final messages = await odooChat.fetchMessages( 42 | messagingResult.channels.first.id, 43 | ); 44 | 45 | print('Messages: '); 46 | for (final message in messages.reversed) { 47 | print(message.emailFrom); 48 | print(message.author); 49 | print(message.body); 50 | print(message.date); 51 | print('\n'); 52 | } 53 | 54 | // Send message 55 | final newMessageId = await odooChat.sendMessage( 56 | channelId: messagingResult.channels.first.id, 57 | message: 'Test message from OdooChat Flutter', 58 | ); 59 | 60 | print('New message id: $newMessageId'); 61 | 62 | // Poll 63 | while (await Future.delayed(const Duration(seconds: 3), () => true)) { 64 | final results = await odooChat.poll(); 65 | 66 | for (final result in results) { 67 | print('\n'); 68 | switch (result.message) { 69 | case PollMessageMessage(data: final Message data): 70 | print('Is a message'); 71 | print(data); 72 | case PollMessageChannel(data: final Channel data): 73 | print('Is a new channel notification'); 74 | print(data); 75 | case PollMessageInfo(data: final MessageInfo data): 76 | print('Is an info message'); // ex: typing, or bot messages 77 | switch (data) { 78 | case MessageInfoTyping( 79 | isTyping: final bool isTyping, 80 | partnerId: final int partnerId, 81 | partnerName: final String partnerName, 82 | ): 83 | print('Partner id: $partnerId'); 84 | print('Partner name: $partnerName'); 85 | print('Is typing: $isTyping'); 86 | 87 | case MessageInfoTransient( 88 | body: final String body, 89 | ): 90 | print('Transient message: $body'); 91 | } 92 | case null: 93 | print('Empty poll result'); 94 | } 95 | } 96 | } 97 | } 98 | ``` 99 | ### Download attachments 100 | 101 | ```dart 102 | // Get attachment in bytes 103 | final bytes = odooChat.getAttachment(attachmentId) 104 | ``` 105 | 106 | ### Note 107 | 108 | It is recommended to use isolates to run the chat poll. 109 | 110 | Review an [application example](https://github.com/luiscib3r/odoochat_flutter/tree/main/example/odoochat_example). 111 | 112 | ### Flutter Web 113 | 114 | Please note that currently, this package does not support Flutter Web. However, work is in progress to make it compatible with web as well. -------------------------------------------------------------------------------- /lib/src/model/message/message.g.dart: -------------------------------------------------------------------------------- 1 | // GENERATED CODE - DO NOT MODIFY BY HAND 2 | 3 | part of 'message.dart'; 4 | 5 | // ************************************************************************** 6 | // JsonSerializableGenerator 7 | // ************************************************************************** 8 | 9 | _$MessageImpl _$$MessageImplFromJson(Map json) => 10 | _$MessageImpl( 11 | id: json['id'] as int, 12 | body: json['body'] as String, 13 | date: json['date'] as String, 14 | author: MessageAuthor.fromList(json['author_id'] as List), 15 | emailFrom: json['email_from'] as String, 16 | messageType: json['message_type'] as String, 17 | subtypeId: json['subtype_id'] as List, 18 | model: json['model'] as String, 19 | resId: json['res_id'] as int, 20 | recordName: json['record_name'] as String, 21 | partnerIds: 22 | (json['partner_ids'] as List).map((e) => e as int).toList(), 23 | starredPartnerIds: (json['starred_partner_ids'] as List) 24 | .map((e) => e as int) 25 | .toList(), 26 | moderationStatus: 27 | Message.parseModerationStatus(json['moderation_status']), 28 | notifications: (json['notifications'] as List) 29 | .map((e) => e as int) 30 | .toList(), 31 | atachments: (json['attachment_ids'] as List) 32 | .map((e) => Attachment.fromJson(e as Map)) 33 | .toList(), 34 | trackingValueIds: (json['tracking_value_ids'] as List) 35 | .map((e) => e as int) 36 | .toList(), 37 | needactionPartnerIds: (json['needaction_partner_ids'] as List) 38 | .map((e) => e as int) 39 | .toList(), 40 | historyPartnerIds: (json['history_partner_ids'] as List) 41 | .map((e) => e as int) 42 | .toList(), 43 | isNote: json['is_note'] as bool, 44 | isDiscussion: json['is_discussion'] as bool, 45 | subtypeDescription: json['subtype_description'] as bool, 46 | isNotification: json['is_notification'] as bool, 47 | moduleIcon: json['module_icon'] as String, 48 | smsIds: (json['sms_ids'] as List).map((e) => e as int).toList(), 49 | ); 50 | 51 | Map _$$MessageImplToJson(_$MessageImpl instance) => 52 | { 53 | 'id': instance.id, 54 | 'body': instance.body, 55 | 'date': instance.date, 56 | 'author_id': instance.author.toJson(), 57 | 'email_from': instance.emailFrom, 58 | 'message_type': instance.messageType, 59 | 'subtype_id': instance.subtypeId, 60 | 'model': instance.model, 61 | 'res_id': instance.resId, 62 | 'record_name': instance.recordName, 63 | 'partner_ids': instance.partnerIds, 64 | 'starred_partner_ids': instance.starredPartnerIds, 65 | 'moderation_status': instance.moderationStatus, 66 | 'notifications': instance.notifications, 67 | 'attachment_ids': instance.atachments.map((e) => e.toJson()).toList(), 68 | 'tracking_value_ids': instance.trackingValueIds, 69 | 'needaction_partner_ids': instance.needactionPartnerIds, 70 | 'history_partner_ids': instance.historyPartnerIds, 71 | 'is_note': instance.isNote, 72 | 'is_discussion': instance.isDiscussion, 73 | 'subtype_description': instance.subtypeDescription, 74 | 'is_notification': instance.isNotification, 75 | 'module_icon': instance.moduleIcon, 76 | 'sms_ids': instance.smsIds, 77 | }; 78 | 79 | _$MessageAuthorImpl _$$MessageAuthorImplFromJson(Map json) => 80 | _$MessageAuthorImpl( 81 | id: json['id'] as int, 82 | name: json['name'] as String, 83 | company: json['company'] as String?, 84 | ); 85 | 86 | Map _$$MessageAuthorImplToJson(_$MessageAuthorImpl instance) => 87 | { 88 | 'id': instance.id, 89 | 'name': instance.name, 90 | 'company': instance.company, 91 | }; 92 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 37 | 38 | 39 | 40 | 43 | 49 | 50 | 51 | 52 | 53 | 63 | 65 | 71 | 72 | 73 | 74 | 80 | 82 | 88 | 89 | 90 | 91 | 93 | 94 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /lib/src/api/responses/poll_result/poll_result.dart: -------------------------------------------------------------------------------- 1 | import 'package:freezed_annotation/freezed_annotation.dart'; 2 | import 'package:odoochat/odoochat.dart'; 3 | 4 | part 'poll_result.freezed.dart'; 5 | part 'poll_result.g.dart'; 6 | 7 | @freezed 8 | class PollResult with _$PollResult { 9 | const factory PollResult({ 10 | required int id, 11 | List? channel, 12 | @JsonKey(fromJson: PollMessage.fromResult) PollMessage? message, 13 | }) = _PollResult; 14 | 15 | factory PollResult.fromJson(Map json) => 16 | _$PollResultFromJson(json); 17 | } 18 | 19 | extension PollResultExtension on PollResult { 20 | int? get channelId => 21 | (channel?.last as int?) ?? 22 | message?.payload?['channel_id'] as int? ?? 23 | message?.payload?['id'] as int?; 24 | } 25 | 26 | sealed class PollMessage { 27 | const PollMessage({ 28 | required this.data, 29 | this.payload, 30 | }); 31 | 32 | static PollMessage? fromResult(Map? json) { 33 | if (json == null) { 34 | return null; 35 | } 36 | 37 | // Odoo 15 38 | if (json['type'] == 'mail.channel.partner/typing_status') { 39 | return PollMessageInfo( 40 | data: MessageInfoTyping.fromJson( 41 | json['payload'] as Map, 42 | ), 43 | payload: json['payload'] as Map, 44 | ); 45 | } 46 | 47 | if (json['type'] == 'mail.channel/new_message') { 48 | final payload = json['payload'] as Map; 49 | return PollMessageMessage( 50 | data: Message.fromJson(payload['message'] as Map), 51 | payload: json['payload'] as Map, 52 | ); 53 | } 54 | 55 | // Odoo 14 56 | if (json['message_type'] != null) { 57 | return PollMessageMessage.fromJson(json); 58 | } 59 | 60 | if (json['channel_type'] != null) { 61 | return PollMessageChannel.fromJson(json); 62 | } 63 | 64 | if (json['info'] != null) { 65 | return PollMessageInfo.fromJson(json); 66 | } 67 | 68 | return null; 69 | } 70 | 71 | Map toJson() => switch (T) { 72 | Message => (data as Message).toJson(), 73 | Channel => (data as Channel).toJson(), 74 | MessageInfo => (data as MessageInfo).toJson(), 75 | Type() => throw OdooChatException( 76 | code: 422, 77 | message: '$runtimeType reported unknown type $T', 78 | ), 79 | }; 80 | 81 | @override 82 | String toString() => switch (T) { 83 | Message => (data as Message).toString(), 84 | Channel => (data as Channel).toString(), 85 | MessageInfo => (data as MessageInfo).toString(), 86 | Type() => throw OdooChatException( 87 | code: 422, 88 | message: '$runtimeType reported unknown type $T', 89 | ), 90 | }; 91 | 92 | final T data; 93 | final Map? payload; 94 | } 95 | 96 | class PollMessageMessage extends PollMessage { 97 | const PollMessageMessage({ 98 | required super.data, 99 | super.payload, 100 | }); 101 | 102 | factory PollMessageMessage.fromJson(Map json) => 103 | PollMessageMessage( 104 | data: Message.fromJson(json), 105 | payload: json, 106 | ); 107 | } 108 | 109 | class PollMessageChannel extends PollMessage { 110 | const PollMessageChannel({ 111 | required super.data, 112 | super.payload, 113 | }); 114 | 115 | factory PollMessageChannel.fromJson(Map json) => 116 | PollMessageChannel( 117 | data: Channel.fromJson(json), 118 | payload: json, 119 | ); 120 | } 121 | 122 | class PollMessageInfo extends PollMessage { 123 | const PollMessageInfo({ 124 | required super.data, 125 | super.payload, 126 | }); 127 | 128 | factory PollMessageInfo.fromJson(Map json) => 129 | PollMessageInfo( 130 | data: MessageInfo.fromJson(json), 131 | payload: json, 132 | ); 133 | } 134 | -------------------------------------------------------------------------------- /example/odoochat_example/lib/chat.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | 3 | import 'package:file_picker/file_picker.dart'; 4 | import 'package:flutter/cupertino.dart'; 5 | import 'package:flutter/material.dart'; 6 | import 'package:flutter_bloc/flutter_bloc.dart'; 7 | import 'package:flutter_chat_types/flutter_chat_types.dart' as types; 8 | import 'package:flutter_chat_ui/flutter_chat_ui.dart'; 9 | import 'package:odoochat_example/bloc/bloc.dart'; 10 | import 'package:open_filex/open_filex.dart'; 11 | 12 | class ChatPage extends StatelessWidget { 13 | const ChatPage({super.key}); 14 | 15 | @override 16 | Widget build(BuildContext context) { 17 | return BlocProvider( 18 | create: (context) => ChatBloc( 19 | odooChat: context.read(), 20 | ), 21 | child: const ChatView(), 22 | ); 23 | } 24 | 25 | static Future open(BuildContext context) => Navigator.of(context) 26 | .pushReplacement(CupertinoPageRoute(builder: (_) => const ChatPage())); 27 | } 28 | 29 | class ChatView extends StatefulWidget { 30 | const ChatView({super.key}); 31 | 32 | @override 33 | State createState() => _ChatViewState(); 34 | } 35 | 36 | class _ChatViewState extends State { 37 | late final bloc = context.read(); 38 | 39 | @override 40 | Widget build(BuildContext context) { 41 | final channelName = context.select( 42 | (ChatBloc bloc) => bloc.state.currentChannel?.name, 43 | ); 44 | 45 | return Scaffold( 46 | appBar: AppBar( 47 | title: channelName != null ? Text(channelName) : const Text('Channels'), 48 | actions: [ 49 | if (channelName != null) 50 | IconButton( 51 | icon: const Icon(Icons.logout), 52 | onPressed: bloc.exitChannel, 53 | ), 54 | ], 55 | ), 56 | body: BlocBuilder( 57 | builder: (context, state) { 58 | if (state.user == null) { 59 | return const Center( 60 | child: CircularProgressIndicator(), 61 | ); 62 | } 63 | 64 | if (state.currentChannel == null) { 65 | return ListView.builder( 66 | itemCount: state.channels.length, 67 | itemBuilder: (context, index) { 68 | final channel = state.channels[index]; 69 | 70 | return Container( 71 | margin: const EdgeInsets.symmetric( 72 | horizontal: 16, 73 | vertical: 8, 74 | ), 75 | decoration: BoxDecoration( 76 | borderRadius: BorderRadius.circular(4), 77 | color: Colors.grey[200], 78 | ), 79 | child: ListTile( 80 | title: Text( 81 | '${channel.id} ${channel.name}', 82 | style: const TextStyle(fontSize: 16), 83 | ), 84 | onTap: () => bloc.setChannel(channel), 85 | ), 86 | ); 87 | }, 88 | ); 89 | } 90 | 91 | return Stack( 92 | fit: StackFit.expand, 93 | children: [ 94 | Chat( 95 | isAttachmentUploading: state.loading, 96 | messages: state.messages, 97 | user: state.user!, 98 | onSendPressed: bloc.sendMessage, 99 | onPreviewDataFetched: bloc.handlePreviewDataFetched, 100 | theme: DefaultChatTheme( 101 | primaryColor: Theme.of(context).primaryColor, 102 | ), 103 | onMessageTap: handleMessageTap, 104 | onAttachmentPressed: handleFileSelection, 105 | ), 106 | ], 107 | ); 108 | }, 109 | ), 110 | ); 111 | } 112 | 113 | Future handleFileSelection() async { 114 | final result = await FilePicker.platform.pickFiles(); 115 | 116 | if (result != null && result.files.single.path != null) { 117 | final file = result.files.single; 118 | 119 | final filename = result.files.single.name; 120 | final bytes = await File(file.path!).readAsBytes(); 121 | 122 | await bloc.sendAttachment(filename: filename, bytes: bytes); 123 | } 124 | } 125 | 126 | Future handleMessageTap(BuildContext _, types.Message message) async { 127 | if (message is types.FileMessage) { 128 | await OpenFilex.open(message.uri); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /example/odoochat_example/ios/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - DKImagePickerController/Core (4.3.4): 3 | - DKImagePickerController/ImageDataManager 4 | - DKImagePickerController/Resource 5 | - DKImagePickerController/ImageDataManager (4.3.4) 6 | - DKImagePickerController/PhotoGallery (4.3.4): 7 | - DKImagePickerController/Core 8 | - DKPhotoGallery 9 | - DKImagePickerController/Resource (4.3.4) 10 | - DKPhotoGallery (0.0.17): 11 | - DKPhotoGallery/Core (= 0.0.17) 12 | - DKPhotoGallery/Model (= 0.0.17) 13 | - DKPhotoGallery/Preview (= 0.0.17) 14 | - DKPhotoGallery/Resource (= 0.0.17) 15 | - SDWebImage 16 | - SwiftyGif 17 | - DKPhotoGallery/Core (0.0.17): 18 | - DKPhotoGallery/Model 19 | - DKPhotoGallery/Preview 20 | - SDWebImage 21 | - SwiftyGif 22 | - DKPhotoGallery/Model (0.0.17): 23 | - SDWebImage 24 | - SwiftyGif 25 | - DKPhotoGallery/Preview (0.0.17): 26 | - DKPhotoGallery/Model 27 | - DKPhotoGallery/Resource 28 | - SDWebImage 29 | - SwiftyGif 30 | - DKPhotoGallery/Resource (0.0.17): 31 | - SDWebImage 32 | - SwiftyGif 33 | - file_picker (0.0.1): 34 | - DKImagePickerController/PhotoGallery 35 | - Flutter 36 | - Flutter (1.0.0) 37 | - libphonenumber_plugin (0.0.1): 38 | - Flutter 39 | - PhoneNumberKit 40 | - open_filex (0.0.2): 41 | - Flutter 42 | - path_provider_foundation (0.0.1): 43 | - Flutter 44 | - FlutterMacOS 45 | - PhoneNumberKit (3.7.6): 46 | - PhoneNumberKit/PhoneNumberKitCore (= 3.7.6) 47 | - PhoneNumberKit/UIKit (= 3.7.6) 48 | - PhoneNumberKit/PhoneNumberKitCore (3.7.6) 49 | - PhoneNumberKit/UIKit (3.7.6): 50 | - PhoneNumberKit/PhoneNumberKitCore 51 | - SDWebImage (5.18.10): 52 | - SDWebImage/Core (= 5.18.10) 53 | - SDWebImage/Core (5.18.10) 54 | - SwiftyGif (5.4.4) 55 | - url_launcher_ios (0.0.1): 56 | - Flutter 57 | - video_player_avfoundation (0.0.1): 58 | - Flutter 59 | - FlutterMacOS 60 | - wakelock (0.0.1): 61 | - Flutter 62 | - webview_flutter_wkwebview (0.0.1): 63 | - Flutter 64 | 65 | DEPENDENCIES: 66 | - file_picker (from `.symlinks/plugins/file_picker/ios`) 67 | - Flutter (from `Flutter`) 68 | - libphonenumber_plugin (from `.symlinks/plugins/libphonenumber_plugin/ios`) 69 | - open_filex (from `.symlinks/plugins/open_filex/ios`) 70 | - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) 71 | - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) 72 | - video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`) 73 | - wakelock (from `.symlinks/plugins/wakelock/ios`) 74 | - webview_flutter_wkwebview (from `.symlinks/plugins/webview_flutter_wkwebview/ios`) 75 | 76 | SPEC REPOS: 77 | trunk: 78 | - DKImagePickerController 79 | - DKPhotoGallery 80 | - PhoneNumberKit 81 | - SDWebImage 82 | - SwiftyGif 83 | 84 | EXTERNAL SOURCES: 85 | file_picker: 86 | :path: ".symlinks/plugins/file_picker/ios" 87 | Flutter: 88 | :path: Flutter 89 | libphonenumber_plugin: 90 | :path: ".symlinks/plugins/libphonenumber_plugin/ios" 91 | open_filex: 92 | :path: ".symlinks/plugins/open_filex/ios" 93 | path_provider_foundation: 94 | :path: ".symlinks/plugins/path_provider_foundation/darwin" 95 | url_launcher_ios: 96 | :path: ".symlinks/plugins/url_launcher_ios/ios" 97 | video_player_avfoundation: 98 | :path: ".symlinks/plugins/video_player_avfoundation/darwin" 99 | wakelock: 100 | :path: ".symlinks/plugins/wakelock/ios" 101 | webview_flutter_wkwebview: 102 | :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" 103 | 104 | SPEC CHECKSUMS: 105 | DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac 106 | DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 107 | file_picker: ce3938a0df3cc1ef404671531facef740d03f920 108 | Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 109 | libphonenumber_plugin: 48bf4078546377eedaab4aa54978cd0f6fa23072 110 | open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4 111 | path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c 112 | PhoneNumberKit: 3c68a822bad955ffcefc72a52df72b6596498555 113 | SDWebImage: fc8f2d48bbfd72ef39d70e981bd24a3f3be53fec 114 | SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f 115 | url_launcher_ios: bbd758c6e7f9fd7b5b1d4cde34d2b95fcce5e812 116 | video_player_avfoundation: 02011213dab73ae3687df27ce441fbbcc82b5579 117 | wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f 118 | webview_flutter_wkwebview: b7e70ef1ddded7e69c796c7390ee74180182971f 119 | 120 | PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 121 | 122 | COCOAPODS: 1.14.3 123 | -------------------------------------------------------------------------------- /lib/src/payload/init_messaging_params/init_messaging_params.freezed.dart: -------------------------------------------------------------------------------- 1 | // coverage:ignore-file 2 | // GENERATED CODE - DO NOT MODIFY BY HAND 3 | // ignore_for_file: type=lint 4 | // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark 5 | 6 | part of 'init_messaging_params.dart'; 7 | 8 | // ************************************************************************** 9 | // FreezedGenerator 10 | // ************************************************************************** 11 | 12 | T _$identity(T value) => value; 13 | 14 | final _privateConstructorUsedError = UnsupportedError( 15 | 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 16 | 17 | InitMessagingParams _$InitMessagingParamsFromJson(Map json) { 18 | return _InitMessagingParams.fromJson(json); 19 | } 20 | 21 | /// @nodoc 22 | mixin _$InitMessagingParams { 23 | Map get context => throw _privateConstructorUsedError; 24 | 25 | Map toJson() => throw _privateConstructorUsedError; 26 | @JsonKey(ignore: true) 27 | $InitMessagingParamsCopyWith get copyWith => 28 | throw _privateConstructorUsedError; 29 | } 30 | 31 | /// @nodoc 32 | abstract class $InitMessagingParamsCopyWith<$Res> { 33 | factory $InitMessagingParamsCopyWith( 34 | InitMessagingParams value, $Res Function(InitMessagingParams) then) = 35 | _$InitMessagingParamsCopyWithImpl<$Res, InitMessagingParams>; 36 | @useResult 37 | $Res call({Map context}); 38 | } 39 | 40 | /// @nodoc 41 | class _$InitMessagingParamsCopyWithImpl<$Res, $Val extends InitMessagingParams> 42 | implements $InitMessagingParamsCopyWith<$Res> { 43 | _$InitMessagingParamsCopyWithImpl(this._value, this._then); 44 | 45 | // ignore: unused_field 46 | final $Val _value; 47 | // ignore: unused_field 48 | final $Res Function($Val) _then; 49 | 50 | @pragma('vm:prefer-inline') 51 | @override 52 | $Res call({ 53 | Object? context = null, 54 | }) { 55 | return _then(_value.copyWith( 56 | context: null == context 57 | ? _value.context 58 | : context // ignore: cast_nullable_to_non_nullable 59 | as Map, 60 | ) as $Val); 61 | } 62 | } 63 | 64 | /// @nodoc 65 | abstract class _$$InitMessagingParamsImplCopyWith<$Res> 66 | implements $InitMessagingParamsCopyWith<$Res> { 67 | factory _$$InitMessagingParamsImplCopyWith(_$InitMessagingParamsImpl value, 68 | $Res Function(_$InitMessagingParamsImpl) then) = 69 | __$$InitMessagingParamsImplCopyWithImpl<$Res>; 70 | @override 71 | @useResult 72 | $Res call({Map context}); 73 | } 74 | 75 | /// @nodoc 76 | class __$$InitMessagingParamsImplCopyWithImpl<$Res> 77 | extends _$InitMessagingParamsCopyWithImpl<$Res, _$InitMessagingParamsImpl> 78 | implements _$$InitMessagingParamsImplCopyWith<$Res> { 79 | __$$InitMessagingParamsImplCopyWithImpl(_$InitMessagingParamsImpl _value, 80 | $Res Function(_$InitMessagingParamsImpl) _then) 81 | : super(_value, _then); 82 | 83 | @pragma('vm:prefer-inline') 84 | @override 85 | $Res call({ 86 | Object? context = null, 87 | }) { 88 | return _then(_$InitMessagingParamsImpl( 89 | context: null == context 90 | ? _value._context 91 | : context // ignore: cast_nullable_to_non_nullable 92 | as Map, 93 | )); 94 | } 95 | } 96 | 97 | /// @nodoc 98 | @JsonSerializable() 99 | class _$InitMessagingParamsImpl implements _InitMessagingParams { 100 | const _$InitMessagingParamsImpl({required final Map context}) 101 | : _context = context; 102 | 103 | factory _$InitMessagingParamsImpl.fromJson(Map json) => 104 | _$$InitMessagingParamsImplFromJson(json); 105 | 106 | final Map _context; 107 | @override 108 | Map get context { 109 | if (_context is EqualUnmodifiableMapView) return _context; 110 | // ignore: implicit_dynamic_type 111 | return EqualUnmodifiableMapView(_context); 112 | } 113 | 114 | @override 115 | String toString() { 116 | return 'InitMessagingParams(context: $context)'; 117 | } 118 | 119 | @override 120 | bool operator ==(Object other) { 121 | return identical(this, other) || 122 | (other.runtimeType == runtimeType && 123 | other is _$InitMessagingParamsImpl && 124 | const DeepCollectionEquality().equals(other._context, _context)); 125 | } 126 | 127 | @JsonKey(ignore: true) 128 | @override 129 | int get hashCode => 130 | Object.hash(runtimeType, const DeepCollectionEquality().hash(_context)); 131 | 132 | @JsonKey(ignore: true) 133 | @override 134 | @pragma('vm:prefer-inline') 135 | _$$InitMessagingParamsImplCopyWith<_$InitMessagingParamsImpl> get copyWith => 136 | __$$InitMessagingParamsImplCopyWithImpl<_$InitMessagingParamsImpl>( 137 | this, _$identity); 138 | 139 | @override 140 | Map toJson() { 141 | return _$$InitMessagingParamsImplToJson( 142 | this, 143 | ); 144 | } 145 | } 146 | 147 | abstract class _InitMessagingParams implements InitMessagingParams { 148 | const factory _InitMessagingParams( 149 | {required final Map context}) = 150 | _$InitMessagingParamsImpl; 151 | 152 | factory _InitMessagingParams.fromJson(Map json) = 153 | _$InitMessagingParamsImpl.fromJson; 154 | 155 | @override 156 | Map get context; 157 | @override 158 | @JsonKey(ignore: true) 159 | _$$InitMessagingParamsImplCopyWith<_$InitMessagingParamsImpl> get copyWith => 160 | throw _privateConstructorUsedError; 161 | } 162 | -------------------------------------------------------------------------------- /lib/src/payload/get_messages_params/get_messages_params.freezed.dart: -------------------------------------------------------------------------------- 1 | // coverage:ignore-file 2 | // GENERATED CODE - DO NOT MODIFY BY HAND 3 | // ignore_for_file: type=lint 4 | // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark 5 | 6 | part of 'get_messages_params.dart'; 7 | 8 | // ************************************************************************** 9 | // FreezedGenerator 10 | // ************************************************************************** 11 | 12 | T _$identity(T value) => value; 13 | 14 | final _privateConstructorUsedError = UnsupportedError( 15 | 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 16 | 17 | GetMessagesParams _$GetMessagesParamsFromJson(Map json) { 18 | return _GetMessagesParams.fromJson(json); 19 | } 20 | 21 | /// @nodoc 22 | mixin _$GetMessagesParams { 23 | @JsonKey(name: 'channel_id') 24 | int get channelId => throw _privateConstructorUsedError; 25 | int get limit => throw _privateConstructorUsedError; 26 | 27 | Map toJson() => throw _privateConstructorUsedError; 28 | @JsonKey(ignore: true) 29 | $GetMessagesParamsCopyWith get copyWith => 30 | throw _privateConstructorUsedError; 31 | } 32 | 33 | /// @nodoc 34 | abstract class $GetMessagesParamsCopyWith<$Res> { 35 | factory $GetMessagesParamsCopyWith( 36 | GetMessagesParams value, $Res Function(GetMessagesParams) then) = 37 | _$GetMessagesParamsCopyWithImpl<$Res, GetMessagesParams>; 38 | @useResult 39 | $Res call({@JsonKey(name: 'channel_id') int channelId, int limit}); 40 | } 41 | 42 | /// @nodoc 43 | class _$GetMessagesParamsCopyWithImpl<$Res, $Val extends GetMessagesParams> 44 | implements $GetMessagesParamsCopyWith<$Res> { 45 | _$GetMessagesParamsCopyWithImpl(this._value, this._then); 46 | 47 | // ignore: unused_field 48 | final $Val _value; 49 | // ignore: unused_field 50 | final $Res Function($Val) _then; 51 | 52 | @pragma('vm:prefer-inline') 53 | @override 54 | $Res call({ 55 | Object? channelId = null, 56 | Object? limit = null, 57 | }) { 58 | return _then(_value.copyWith( 59 | channelId: null == channelId 60 | ? _value.channelId 61 | : channelId // ignore: cast_nullable_to_non_nullable 62 | as int, 63 | limit: null == limit 64 | ? _value.limit 65 | : limit // ignore: cast_nullable_to_non_nullable 66 | as int, 67 | ) as $Val); 68 | } 69 | } 70 | 71 | /// @nodoc 72 | abstract class _$$GetMessagesParamsImplCopyWith<$Res> 73 | implements $GetMessagesParamsCopyWith<$Res> { 74 | factory _$$GetMessagesParamsImplCopyWith(_$GetMessagesParamsImpl value, 75 | $Res Function(_$GetMessagesParamsImpl) then) = 76 | __$$GetMessagesParamsImplCopyWithImpl<$Res>; 77 | @override 78 | @useResult 79 | $Res call({@JsonKey(name: 'channel_id') int channelId, int limit}); 80 | } 81 | 82 | /// @nodoc 83 | class __$$GetMessagesParamsImplCopyWithImpl<$Res> 84 | extends _$GetMessagesParamsCopyWithImpl<$Res, _$GetMessagesParamsImpl> 85 | implements _$$GetMessagesParamsImplCopyWith<$Res> { 86 | __$$GetMessagesParamsImplCopyWithImpl(_$GetMessagesParamsImpl _value, 87 | $Res Function(_$GetMessagesParamsImpl) _then) 88 | : super(_value, _then); 89 | 90 | @pragma('vm:prefer-inline') 91 | @override 92 | $Res call({ 93 | Object? channelId = null, 94 | Object? limit = null, 95 | }) { 96 | return _then(_$GetMessagesParamsImpl( 97 | channelId: null == channelId 98 | ? _value.channelId 99 | : channelId // ignore: cast_nullable_to_non_nullable 100 | as int, 101 | limit: null == limit 102 | ? _value.limit 103 | : limit // ignore: cast_nullable_to_non_nullable 104 | as int, 105 | )); 106 | } 107 | } 108 | 109 | /// @nodoc 110 | @JsonSerializable() 111 | class _$GetMessagesParamsImpl implements _GetMessagesParams { 112 | const _$GetMessagesParamsImpl( 113 | {@JsonKey(name: 'channel_id') required this.channelId, 114 | required this.limit}); 115 | 116 | factory _$GetMessagesParamsImpl.fromJson(Map json) => 117 | _$$GetMessagesParamsImplFromJson(json); 118 | 119 | @override 120 | @JsonKey(name: 'channel_id') 121 | final int channelId; 122 | @override 123 | final int limit; 124 | 125 | @override 126 | String toString() { 127 | return 'GetMessagesParams(channelId: $channelId, limit: $limit)'; 128 | } 129 | 130 | @override 131 | bool operator ==(Object other) { 132 | return identical(this, other) || 133 | (other.runtimeType == runtimeType && 134 | other is _$GetMessagesParamsImpl && 135 | (identical(other.channelId, channelId) || 136 | other.channelId == channelId) && 137 | (identical(other.limit, limit) || other.limit == limit)); 138 | } 139 | 140 | @JsonKey(ignore: true) 141 | @override 142 | int get hashCode => Object.hash(runtimeType, channelId, limit); 143 | 144 | @JsonKey(ignore: true) 145 | @override 146 | @pragma('vm:prefer-inline') 147 | _$$GetMessagesParamsImplCopyWith<_$GetMessagesParamsImpl> get copyWith => 148 | __$$GetMessagesParamsImplCopyWithImpl<_$GetMessagesParamsImpl>( 149 | this, _$identity); 150 | 151 | @override 152 | Map toJson() { 153 | return _$$GetMessagesParamsImplToJson( 154 | this, 155 | ); 156 | } 157 | } 158 | 159 | abstract class _GetMessagesParams implements GetMessagesParams { 160 | const factory _GetMessagesParams( 161 | {@JsonKey(name: 'channel_id') required final int channelId, 162 | required final int limit}) = _$GetMessagesParamsImpl; 163 | 164 | factory _GetMessagesParams.fromJson(Map json) = 165 | _$GetMessagesParamsImpl.fromJson; 166 | 167 | @override 168 | @JsonKey(name: 'channel_id') 169 | int get channelId; 170 | @override 171 | int get limit; 172 | @override 173 | @JsonKey(ignore: true) 174 | _$$GetMessagesParamsImplCopyWith<_$GetMessagesParamsImpl> get copyWith => 175 | throw _privateConstructorUsedError; 176 | } 177 | -------------------------------------------------------------------------------- /lib/src/payload/login_params/login_params.freezed.dart: -------------------------------------------------------------------------------- 1 | // coverage:ignore-file 2 | // GENERATED CODE - DO NOT MODIFY BY HAND 3 | // ignore_for_file: type=lint 4 | // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark 5 | 6 | part of 'login_params.dart'; 7 | 8 | // ************************************************************************** 9 | // FreezedGenerator 10 | // ************************************************************************** 11 | 12 | T _$identity(T value) => value; 13 | 14 | final _privateConstructorUsedError = UnsupportedError( 15 | 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 16 | 17 | LoginParams _$LoginParamsFromJson(Map json) { 18 | return _LoginParams.fromJson(json); 19 | } 20 | 21 | /// @nodoc 22 | mixin _$LoginParams { 23 | String get login => throw _privateConstructorUsedError; 24 | String get password => throw _privateConstructorUsedError; 25 | String get db => throw _privateConstructorUsedError; 26 | 27 | Map toJson() => throw _privateConstructorUsedError; 28 | @JsonKey(ignore: true) 29 | $LoginParamsCopyWith get copyWith => 30 | throw _privateConstructorUsedError; 31 | } 32 | 33 | /// @nodoc 34 | abstract class $LoginParamsCopyWith<$Res> { 35 | factory $LoginParamsCopyWith( 36 | LoginParams value, $Res Function(LoginParams) then) = 37 | _$LoginParamsCopyWithImpl<$Res, LoginParams>; 38 | @useResult 39 | $Res call({String login, String password, String db}); 40 | } 41 | 42 | /// @nodoc 43 | class _$LoginParamsCopyWithImpl<$Res, $Val extends LoginParams> 44 | implements $LoginParamsCopyWith<$Res> { 45 | _$LoginParamsCopyWithImpl(this._value, this._then); 46 | 47 | // ignore: unused_field 48 | final $Val _value; 49 | // ignore: unused_field 50 | final $Res Function($Val) _then; 51 | 52 | @pragma('vm:prefer-inline') 53 | @override 54 | $Res call({ 55 | Object? login = null, 56 | Object? password = null, 57 | Object? db = null, 58 | }) { 59 | return _then(_value.copyWith( 60 | login: null == login 61 | ? _value.login 62 | : login // ignore: cast_nullable_to_non_nullable 63 | as String, 64 | password: null == password 65 | ? _value.password 66 | : password // ignore: cast_nullable_to_non_nullable 67 | as String, 68 | db: null == db 69 | ? _value.db 70 | : db // ignore: cast_nullable_to_non_nullable 71 | as String, 72 | ) as $Val); 73 | } 74 | } 75 | 76 | /// @nodoc 77 | abstract class _$$LoginParamsImplCopyWith<$Res> 78 | implements $LoginParamsCopyWith<$Res> { 79 | factory _$$LoginParamsImplCopyWith( 80 | _$LoginParamsImpl value, $Res Function(_$LoginParamsImpl) then) = 81 | __$$LoginParamsImplCopyWithImpl<$Res>; 82 | @override 83 | @useResult 84 | $Res call({String login, String password, String db}); 85 | } 86 | 87 | /// @nodoc 88 | class __$$LoginParamsImplCopyWithImpl<$Res> 89 | extends _$LoginParamsCopyWithImpl<$Res, _$LoginParamsImpl> 90 | implements _$$LoginParamsImplCopyWith<$Res> { 91 | __$$LoginParamsImplCopyWithImpl( 92 | _$LoginParamsImpl _value, $Res Function(_$LoginParamsImpl) _then) 93 | : super(_value, _then); 94 | 95 | @pragma('vm:prefer-inline') 96 | @override 97 | $Res call({ 98 | Object? login = null, 99 | Object? password = null, 100 | Object? db = null, 101 | }) { 102 | return _then(_$LoginParamsImpl( 103 | login: null == login 104 | ? _value.login 105 | : login // ignore: cast_nullable_to_non_nullable 106 | as String, 107 | password: null == password 108 | ? _value.password 109 | : password // ignore: cast_nullable_to_non_nullable 110 | as String, 111 | db: null == db 112 | ? _value.db 113 | : db // ignore: cast_nullable_to_non_nullable 114 | as String, 115 | )); 116 | } 117 | } 118 | 119 | /// @nodoc 120 | @JsonSerializable() 121 | class _$LoginParamsImpl implements _LoginParams { 122 | const _$LoginParamsImpl( 123 | {required this.login, required this.password, required this.db}); 124 | 125 | factory _$LoginParamsImpl.fromJson(Map json) => 126 | _$$LoginParamsImplFromJson(json); 127 | 128 | @override 129 | final String login; 130 | @override 131 | final String password; 132 | @override 133 | final String db; 134 | 135 | @override 136 | String toString() { 137 | return 'LoginParams(login: $login, password: $password, db: $db)'; 138 | } 139 | 140 | @override 141 | bool operator ==(Object other) { 142 | return identical(this, other) || 143 | (other.runtimeType == runtimeType && 144 | other is _$LoginParamsImpl && 145 | (identical(other.login, login) || other.login == login) && 146 | (identical(other.password, password) || 147 | other.password == password) && 148 | (identical(other.db, db) || other.db == db)); 149 | } 150 | 151 | @JsonKey(ignore: true) 152 | @override 153 | int get hashCode => Object.hash(runtimeType, login, password, db); 154 | 155 | @JsonKey(ignore: true) 156 | @override 157 | @pragma('vm:prefer-inline') 158 | _$$LoginParamsImplCopyWith<_$LoginParamsImpl> get copyWith => 159 | __$$LoginParamsImplCopyWithImpl<_$LoginParamsImpl>(this, _$identity); 160 | 161 | @override 162 | Map toJson() { 163 | return _$$LoginParamsImplToJson( 164 | this, 165 | ); 166 | } 167 | } 168 | 169 | abstract class _LoginParams implements LoginParams { 170 | const factory _LoginParams( 171 | {required final String login, 172 | required final String password, 173 | required final String db}) = _$LoginParamsImpl; 174 | 175 | factory _LoginParams.fromJson(Map json) = 176 | _$LoginParamsImpl.fromJson; 177 | 178 | @override 179 | String get login; 180 | @override 181 | String get password; 182 | @override 183 | String get db; 184 | @override 185 | @JsonKey(ignore: true) 186 | _$$LoginParamsImplCopyWith<_$LoginParamsImpl> get copyWith => 187 | throw _privateConstructorUsedError; 188 | } 189 | -------------------------------------------------------------------------------- /lib/src/api/responses/rpc_response/rpc_response.freezed.dart: -------------------------------------------------------------------------------- 1 | // coverage:ignore-file 2 | // GENERATED CODE - DO NOT MODIFY BY HAND 3 | // ignore_for_file: type=lint 4 | // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark 5 | 6 | part of 'rpc_response.dart'; 7 | 8 | // ************************************************************************** 9 | // FreezedGenerator 10 | // ************************************************************************** 11 | 12 | T _$identity(T value) => value; 13 | 14 | final _privateConstructorUsedError = UnsupportedError( 15 | 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 16 | 17 | RpcError _$RpcErrorFromJson(Map json) { 18 | return _RpcError.fromJson(json); 19 | } 20 | 21 | /// @nodoc 22 | mixin _$RpcError { 23 | int get code => throw _privateConstructorUsedError; 24 | String get message => throw _privateConstructorUsedError; 25 | Map get data => throw _privateConstructorUsedError; 26 | 27 | Map toJson() => throw _privateConstructorUsedError; 28 | @JsonKey(ignore: true) 29 | $RpcErrorCopyWith get copyWith => 30 | throw _privateConstructorUsedError; 31 | } 32 | 33 | /// @nodoc 34 | abstract class $RpcErrorCopyWith<$Res> { 35 | factory $RpcErrorCopyWith(RpcError value, $Res Function(RpcError) then) = 36 | _$RpcErrorCopyWithImpl<$Res, RpcError>; 37 | @useResult 38 | $Res call({int code, String message, Map data}); 39 | } 40 | 41 | /// @nodoc 42 | class _$RpcErrorCopyWithImpl<$Res, $Val extends RpcError> 43 | implements $RpcErrorCopyWith<$Res> { 44 | _$RpcErrorCopyWithImpl(this._value, this._then); 45 | 46 | // ignore: unused_field 47 | final $Val _value; 48 | // ignore: unused_field 49 | final $Res Function($Val) _then; 50 | 51 | @pragma('vm:prefer-inline') 52 | @override 53 | $Res call({ 54 | Object? code = null, 55 | Object? message = null, 56 | Object? data = null, 57 | }) { 58 | return _then(_value.copyWith( 59 | code: null == code 60 | ? _value.code 61 | : code // ignore: cast_nullable_to_non_nullable 62 | as int, 63 | message: null == message 64 | ? _value.message 65 | : message // ignore: cast_nullable_to_non_nullable 66 | as String, 67 | data: null == data 68 | ? _value.data 69 | : data // ignore: cast_nullable_to_non_nullable 70 | as Map, 71 | ) as $Val); 72 | } 73 | } 74 | 75 | /// @nodoc 76 | abstract class _$$RpcErrorImplCopyWith<$Res> 77 | implements $RpcErrorCopyWith<$Res> { 78 | factory _$$RpcErrorImplCopyWith( 79 | _$RpcErrorImpl value, $Res Function(_$RpcErrorImpl) then) = 80 | __$$RpcErrorImplCopyWithImpl<$Res>; 81 | @override 82 | @useResult 83 | $Res call({int code, String message, Map data}); 84 | } 85 | 86 | /// @nodoc 87 | class __$$RpcErrorImplCopyWithImpl<$Res> 88 | extends _$RpcErrorCopyWithImpl<$Res, _$RpcErrorImpl> 89 | implements _$$RpcErrorImplCopyWith<$Res> { 90 | __$$RpcErrorImplCopyWithImpl( 91 | _$RpcErrorImpl _value, $Res Function(_$RpcErrorImpl) _then) 92 | : super(_value, _then); 93 | 94 | @pragma('vm:prefer-inline') 95 | @override 96 | $Res call({ 97 | Object? code = null, 98 | Object? message = null, 99 | Object? data = null, 100 | }) { 101 | return _then(_$RpcErrorImpl( 102 | code: null == code 103 | ? _value.code 104 | : code // ignore: cast_nullable_to_non_nullable 105 | as int, 106 | message: null == message 107 | ? _value.message 108 | : message // ignore: cast_nullable_to_non_nullable 109 | as String, 110 | data: null == data 111 | ? _value._data 112 | : data // ignore: cast_nullable_to_non_nullable 113 | as Map, 114 | )); 115 | } 116 | } 117 | 118 | /// @nodoc 119 | @JsonSerializable() 120 | class _$RpcErrorImpl implements _RpcError { 121 | const _$RpcErrorImpl( 122 | {required this.code, 123 | required this.message, 124 | required final Map data}) 125 | : _data = data; 126 | 127 | factory _$RpcErrorImpl.fromJson(Map json) => 128 | _$$RpcErrorImplFromJson(json); 129 | 130 | @override 131 | final int code; 132 | @override 133 | final String message; 134 | final Map _data; 135 | @override 136 | Map get data { 137 | if (_data is EqualUnmodifiableMapView) return _data; 138 | // ignore: implicit_dynamic_type 139 | return EqualUnmodifiableMapView(_data); 140 | } 141 | 142 | @override 143 | String toString() { 144 | return 'RpcError(code: $code, message: $message, data: $data)'; 145 | } 146 | 147 | @override 148 | bool operator ==(Object other) { 149 | return identical(this, other) || 150 | (other.runtimeType == runtimeType && 151 | other is _$RpcErrorImpl && 152 | (identical(other.code, code) || other.code == code) && 153 | (identical(other.message, message) || other.message == message) && 154 | const DeepCollectionEquality().equals(other._data, _data)); 155 | } 156 | 157 | @JsonKey(ignore: true) 158 | @override 159 | int get hashCode => Object.hash( 160 | runtimeType, code, message, const DeepCollectionEquality().hash(_data)); 161 | 162 | @JsonKey(ignore: true) 163 | @override 164 | @pragma('vm:prefer-inline') 165 | _$$RpcErrorImplCopyWith<_$RpcErrorImpl> get copyWith => 166 | __$$RpcErrorImplCopyWithImpl<_$RpcErrorImpl>(this, _$identity); 167 | 168 | @override 169 | Map toJson() { 170 | return _$$RpcErrorImplToJson( 171 | this, 172 | ); 173 | } 174 | } 175 | 176 | abstract class _RpcError implements RpcError { 177 | const factory _RpcError( 178 | {required final int code, 179 | required final String message, 180 | required final Map data}) = _$RpcErrorImpl; 181 | 182 | factory _RpcError.fromJson(Map json) = 183 | _$RpcErrorImpl.fromJson; 184 | 185 | @override 186 | int get code; 187 | @override 188 | String get message; 189 | @override 190 | Map get data; 191 | @override 192 | @JsonKey(ignore: true) 193 | _$$RpcErrorImplCopyWith<_$RpcErrorImpl> get copyWith => 194 | throw _privateConstructorUsedError; 195 | } 196 | -------------------------------------------------------------------------------- /lib/src/payload/poll_params/poll_params.freezed.dart: -------------------------------------------------------------------------------- 1 | // coverage:ignore-file 2 | // GENERATED CODE - DO NOT MODIFY BY HAND 3 | // ignore_for_file: type=lint 4 | // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark 5 | 6 | part of 'poll_params.dart'; 7 | 8 | // ************************************************************************** 9 | // FreezedGenerator 10 | // ************************************************************************** 11 | 12 | T _$identity(T value) => value; 13 | 14 | final _privateConstructorUsedError = UnsupportedError( 15 | 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 16 | 17 | PollParams _$PollParamsFromJson(Map json) { 18 | return _PollParams.fromJson(json); 19 | } 20 | 21 | /// @nodoc 22 | mixin _$PollParams { 23 | int get last => throw _privateConstructorUsedError; 24 | List get channels => throw _privateConstructorUsedError; 25 | Map get options => throw _privateConstructorUsedError; 26 | 27 | Map toJson() => throw _privateConstructorUsedError; 28 | @JsonKey(ignore: true) 29 | $PollParamsCopyWith get copyWith => 30 | throw _privateConstructorUsedError; 31 | } 32 | 33 | /// @nodoc 34 | abstract class $PollParamsCopyWith<$Res> { 35 | factory $PollParamsCopyWith( 36 | PollParams value, $Res Function(PollParams) then) = 37 | _$PollParamsCopyWithImpl<$Res, PollParams>; 38 | @useResult 39 | $Res call({int last, List channels, Map options}); 40 | } 41 | 42 | /// @nodoc 43 | class _$PollParamsCopyWithImpl<$Res, $Val extends PollParams> 44 | implements $PollParamsCopyWith<$Res> { 45 | _$PollParamsCopyWithImpl(this._value, this._then); 46 | 47 | // ignore: unused_field 48 | final $Val _value; 49 | // ignore: unused_field 50 | final $Res Function($Val) _then; 51 | 52 | @pragma('vm:prefer-inline') 53 | @override 54 | $Res call({ 55 | Object? last = null, 56 | Object? channels = null, 57 | Object? options = null, 58 | }) { 59 | return _then(_value.copyWith( 60 | last: null == last 61 | ? _value.last 62 | : last // ignore: cast_nullable_to_non_nullable 63 | as int, 64 | channels: null == channels 65 | ? _value.channels 66 | : channels // ignore: cast_nullable_to_non_nullable 67 | as List, 68 | options: null == options 69 | ? _value.options 70 | : options // ignore: cast_nullable_to_non_nullable 71 | as Map, 72 | ) as $Val); 73 | } 74 | } 75 | 76 | /// @nodoc 77 | abstract class _$$PollParamsImplCopyWith<$Res> 78 | implements $PollParamsCopyWith<$Res> { 79 | factory _$$PollParamsImplCopyWith( 80 | _$PollParamsImpl value, $Res Function(_$PollParamsImpl) then) = 81 | __$$PollParamsImplCopyWithImpl<$Res>; 82 | @override 83 | @useResult 84 | $Res call({int last, List channels, Map options}); 85 | } 86 | 87 | /// @nodoc 88 | class __$$PollParamsImplCopyWithImpl<$Res> 89 | extends _$PollParamsCopyWithImpl<$Res, _$PollParamsImpl> 90 | implements _$$PollParamsImplCopyWith<$Res> { 91 | __$$PollParamsImplCopyWithImpl( 92 | _$PollParamsImpl _value, $Res Function(_$PollParamsImpl) _then) 93 | : super(_value, _then); 94 | 95 | @pragma('vm:prefer-inline') 96 | @override 97 | $Res call({ 98 | Object? last = null, 99 | Object? channels = null, 100 | Object? options = null, 101 | }) { 102 | return _then(_$PollParamsImpl( 103 | last: null == last 104 | ? _value.last 105 | : last // ignore: cast_nullable_to_non_nullable 106 | as int, 107 | channels: null == channels 108 | ? _value._channels 109 | : channels // ignore: cast_nullable_to_non_nullable 110 | as List, 111 | options: null == options 112 | ? _value._options 113 | : options // ignore: cast_nullable_to_non_nullable 114 | as Map, 115 | )); 116 | } 117 | } 118 | 119 | /// @nodoc 120 | @JsonSerializable() 121 | class _$PollParamsImpl implements _PollParams { 122 | const _$PollParamsImpl( 123 | {required this.last, 124 | required final List channels, 125 | required final Map options}) 126 | : _channels = channels, 127 | _options = options; 128 | 129 | factory _$PollParamsImpl.fromJson(Map json) => 130 | _$$PollParamsImplFromJson(json); 131 | 132 | @override 133 | final int last; 134 | final List _channels; 135 | @override 136 | List get channels { 137 | if (_channels is EqualUnmodifiableListView) return _channels; 138 | // ignore: implicit_dynamic_type 139 | return EqualUnmodifiableListView(_channels); 140 | } 141 | 142 | final Map _options; 143 | @override 144 | Map get options { 145 | if (_options is EqualUnmodifiableMapView) return _options; 146 | // ignore: implicit_dynamic_type 147 | return EqualUnmodifiableMapView(_options); 148 | } 149 | 150 | @override 151 | String toString() { 152 | return 'PollParams._(last: $last, channels: $channels, options: $options)'; 153 | } 154 | 155 | @override 156 | bool operator ==(Object other) { 157 | return identical(this, other) || 158 | (other.runtimeType == runtimeType && 159 | other is _$PollParamsImpl && 160 | (identical(other.last, last) || other.last == last) && 161 | const DeepCollectionEquality().equals(other._channels, _channels) && 162 | const DeepCollectionEquality().equals(other._options, _options)); 163 | } 164 | 165 | @JsonKey(ignore: true) 166 | @override 167 | int get hashCode => Object.hash( 168 | runtimeType, 169 | last, 170 | const DeepCollectionEquality().hash(_channels), 171 | const DeepCollectionEquality().hash(_options)); 172 | 173 | @JsonKey(ignore: true) 174 | @override 175 | @pragma('vm:prefer-inline') 176 | _$$PollParamsImplCopyWith<_$PollParamsImpl> get copyWith => 177 | __$$PollParamsImplCopyWithImpl<_$PollParamsImpl>(this, _$identity); 178 | 179 | @override 180 | Map toJson() { 181 | return _$$PollParamsImplToJson( 182 | this, 183 | ); 184 | } 185 | } 186 | 187 | abstract class _PollParams implements PollParams { 188 | const factory _PollParams( 189 | {required final int last, 190 | required final List channels, 191 | required final Map options}) = _$PollParamsImpl; 192 | 193 | factory _PollParams.fromJson(Map json) = 194 | _$PollParamsImpl.fromJson; 195 | 196 | @override 197 | int get last; 198 | @override 199 | List get channels; 200 | @override 201 | Map get options; 202 | @override 203 | @JsonKey(ignore: true) 204 | _$$PollParamsImplCopyWith<_$PollParamsImpl> get copyWith => 205 | throw _privateConstructorUsedError; 206 | } 207 | -------------------------------------------------------------------------------- /lib/src/api/responses/poll_result/poll_result.freezed.dart: -------------------------------------------------------------------------------- 1 | // coverage:ignore-file 2 | // GENERATED CODE - DO NOT MODIFY BY HAND 3 | // ignore_for_file: type=lint 4 | // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark 5 | 6 | part of 'poll_result.dart'; 7 | 8 | // ************************************************************************** 9 | // FreezedGenerator 10 | // ************************************************************************** 11 | 12 | T _$identity(T value) => value; 13 | 14 | final _privateConstructorUsedError = UnsupportedError( 15 | 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 16 | 17 | PollResult _$PollResultFromJson(Map json) { 18 | return _PollResult.fromJson(json); 19 | } 20 | 21 | /// @nodoc 22 | mixin _$PollResult { 23 | int get id => throw _privateConstructorUsedError; 24 | List? get channel => throw _privateConstructorUsedError; 25 | @JsonKey(fromJson: PollMessage.fromResult) 26 | PollMessage? get message => throw _privateConstructorUsedError; 27 | 28 | Map toJson() => throw _privateConstructorUsedError; 29 | @JsonKey(ignore: true) 30 | $PollResultCopyWith get copyWith => 31 | throw _privateConstructorUsedError; 32 | } 33 | 34 | /// @nodoc 35 | abstract class $PollResultCopyWith<$Res> { 36 | factory $PollResultCopyWith( 37 | PollResult value, $Res Function(PollResult) then) = 38 | _$PollResultCopyWithImpl<$Res, PollResult>; 39 | @useResult 40 | $Res call( 41 | {int id, 42 | List? channel, 43 | @JsonKey(fromJson: PollMessage.fromResult) 44 | PollMessage? message}); 45 | } 46 | 47 | /// @nodoc 48 | class _$PollResultCopyWithImpl<$Res, $Val extends PollResult> 49 | implements $PollResultCopyWith<$Res> { 50 | _$PollResultCopyWithImpl(this._value, this._then); 51 | 52 | // ignore: unused_field 53 | final $Val _value; 54 | // ignore: unused_field 55 | final $Res Function($Val) _then; 56 | 57 | @pragma('vm:prefer-inline') 58 | @override 59 | $Res call({ 60 | Object? id = null, 61 | Object? channel = freezed, 62 | Object? message = freezed, 63 | }) { 64 | return _then(_value.copyWith( 65 | id: null == id 66 | ? _value.id 67 | : id // ignore: cast_nullable_to_non_nullable 68 | as int, 69 | channel: freezed == channel 70 | ? _value.channel 71 | : channel // ignore: cast_nullable_to_non_nullable 72 | as List?, 73 | message: freezed == message 74 | ? _value.message 75 | : message // ignore: cast_nullable_to_non_nullable 76 | as PollMessage?, 77 | ) as $Val); 78 | } 79 | } 80 | 81 | /// @nodoc 82 | abstract class _$$PollResultImplCopyWith<$Res> 83 | implements $PollResultCopyWith<$Res> { 84 | factory _$$PollResultImplCopyWith( 85 | _$PollResultImpl value, $Res Function(_$PollResultImpl) then) = 86 | __$$PollResultImplCopyWithImpl<$Res>; 87 | @override 88 | @useResult 89 | $Res call( 90 | {int id, 91 | List? channel, 92 | @JsonKey(fromJson: PollMessage.fromResult) 93 | PollMessage? message}); 94 | } 95 | 96 | /// @nodoc 97 | class __$$PollResultImplCopyWithImpl<$Res> 98 | extends _$PollResultCopyWithImpl<$Res, _$PollResultImpl> 99 | implements _$$PollResultImplCopyWith<$Res> { 100 | __$$PollResultImplCopyWithImpl( 101 | _$PollResultImpl _value, $Res Function(_$PollResultImpl) _then) 102 | : super(_value, _then); 103 | 104 | @pragma('vm:prefer-inline') 105 | @override 106 | $Res call({ 107 | Object? id = null, 108 | Object? channel = freezed, 109 | Object? message = freezed, 110 | }) { 111 | return _then(_$PollResultImpl( 112 | id: null == id 113 | ? _value.id 114 | : id // ignore: cast_nullable_to_non_nullable 115 | as int, 116 | channel: freezed == channel 117 | ? _value._channel 118 | : channel // ignore: cast_nullable_to_non_nullable 119 | as List?, 120 | message: freezed == message 121 | ? _value.message 122 | : message // ignore: cast_nullable_to_non_nullable 123 | as PollMessage?, 124 | )); 125 | } 126 | } 127 | 128 | /// @nodoc 129 | @JsonSerializable() 130 | class _$PollResultImpl implements _PollResult { 131 | const _$PollResultImpl( 132 | {required this.id, 133 | final List? channel, 134 | @JsonKey(fromJson: PollMessage.fromResult) this.message}) 135 | : _channel = channel; 136 | 137 | factory _$PollResultImpl.fromJson(Map json) => 138 | _$$PollResultImplFromJson(json); 139 | 140 | @override 141 | final int id; 142 | final List? _channel; 143 | @override 144 | List? get channel { 145 | final value = _channel; 146 | if (value == null) return null; 147 | if (_channel is EqualUnmodifiableListView) return _channel; 148 | // ignore: implicit_dynamic_type 149 | return EqualUnmodifiableListView(value); 150 | } 151 | 152 | @override 153 | @JsonKey(fromJson: PollMessage.fromResult) 154 | final PollMessage? message; 155 | 156 | @override 157 | String toString() { 158 | return 'PollResult(id: $id, channel: $channel, message: $message)'; 159 | } 160 | 161 | @override 162 | bool operator ==(Object other) { 163 | return identical(this, other) || 164 | (other.runtimeType == runtimeType && 165 | other is _$PollResultImpl && 166 | (identical(other.id, id) || other.id == id) && 167 | const DeepCollectionEquality().equals(other._channel, _channel) && 168 | (identical(other.message, message) || other.message == message)); 169 | } 170 | 171 | @JsonKey(ignore: true) 172 | @override 173 | int get hashCode => Object.hash( 174 | runtimeType, id, const DeepCollectionEquality().hash(_channel), message); 175 | 176 | @JsonKey(ignore: true) 177 | @override 178 | @pragma('vm:prefer-inline') 179 | _$$PollResultImplCopyWith<_$PollResultImpl> get copyWith => 180 | __$$PollResultImplCopyWithImpl<_$PollResultImpl>(this, _$identity); 181 | 182 | @override 183 | Map toJson() { 184 | return _$$PollResultImplToJson( 185 | this, 186 | ); 187 | } 188 | } 189 | 190 | abstract class _PollResult implements PollResult { 191 | const factory _PollResult( 192 | {required final int id, 193 | final List? channel, 194 | @JsonKey(fromJson: PollMessage.fromResult) 195 | final PollMessage? message}) = _$PollResultImpl; 196 | 197 | factory _PollResult.fromJson(Map json) = 198 | _$PollResultImpl.fromJson; 199 | 200 | @override 201 | int get id; 202 | @override 203 | List? get channel; 204 | @override 205 | @JsonKey(fromJson: PollMessage.fromResult) 206 | PollMessage? get message; 207 | @override 208 | @JsonKey(ignore: true) 209 | _$$PollResultImplCopyWith<_$PollResultImpl> get copyWith => 210 | throw _privateConstructorUsedError; 211 | } 212 | -------------------------------------------------------------------------------- /lib/src/odoochat.dart: -------------------------------------------------------------------------------- 1 | import 'dart:io'; 2 | import 'dart:typed_data'; 3 | 4 | import 'package:cookie_jar/cookie_jar.dart'; 5 | import 'package:dio/dio.dart'; 6 | import 'package:dio_cookie_manager/dio_cookie_manager.dart'; 7 | import 'package:odoochat/odoochat.dart'; 8 | import 'package:odoochat/src/debug/odoo_dio_logger.dart'; 9 | 10 | export 'api/odoochat_api.dart'; 11 | export 'exceptions/exceptions.dart'; 12 | export 'model/model.dart'; 13 | export 'payload/payload.dart'; 14 | 15 | class OdooChat { 16 | OdooChat({ 17 | required String serverUrl, 18 | required String databaseName, 19 | bool debug = false, 20 | }) : _databaseName = databaseName, 21 | _debugMode = debug { 22 | _dio = Dio( 23 | BaseOptions( 24 | baseUrl: serverUrl, 25 | contentType: 'application/json', 26 | ), 27 | )..interceptors.addAll( 28 | [ 29 | CookieManager( 30 | CookieJar(), 31 | ), 32 | if (debug) OdooDioLogger(), 33 | ], 34 | ); 35 | 36 | _api = OdooChatApi( 37 | _dio, 38 | baseUrl: serverUrl, 39 | ); 40 | } 41 | 42 | late final Dio _dio; 43 | late final OdooChatApi _api; 44 | final String _databaseName; 45 | final bool _debugMode; 46 | 47 | LoginResult? get loginResult => _loginResult; 48 | LoginResult? _loginResult; 49 | int? _odooVersion; 50 | 51 | Future login({ 52 | required String username, 53 | required String password, 54 | }) async { 55 | final response = await _api.login( 56 | RpcPayload.from( 57 | params: LoginParams( 58 | login: username, 59 | password: password, 60 | db: _databaseName, 61 | ), 62 | ), 63 | ); 64 | 65 | if (response.error != null) { 66 | if (_debugMode) { 67 | // ignore: avoid_print 68 | print(response.error); 69 | } 70 | throw OdooChatException( 71 | code: response.error!.code, 72 | message: response.error!.message, 73 | data: response.error!.data, 74 | ); 75 | } 76 | 77 | _loginResult = response.result; 78 | _odooVersion = _loginResult?.serverVersionInfo.first as int?; 79 | 80 | return response.result!; 81 | } 82 | 83 | Future _proccess({ 84 | required Future> Function() action, 85 | }) async { 86 | if (_loginResult == null) { 87 | throw OdooChatException( 88 | code: 403, 89 | message: 'You must login first. Please call login method.', 90 | ); 91 | } 92 | 93 | final response = await action(); 94 | 95 | if (response.error != null) { 96 | if (_debugMode) { 97 | // ignore: avoid_print 98 | print(response.error); 99 | } 100 | throw OdooChatException( 101 | code: response.error!.code, 102 | message: response.error!.message, 103 | ); 104 | } 105 | 106 | return response.result!; 107 | } 108 | 109 | Future initMessaging() => _proccess( 110 | action: () => _api.initMessaging( 111 | RpcPayload.from( 112 | params: InitMessagingParams( 113 | context: _loginResult!.userContext, 114 | ), 115 | ), 116 | ), 117 | ); 118 | 119 | Future> fetchMessages(int channelId) => _proccess( 120 | action: () { 121 | if (_odooVersion == 14) { 122 | return _api.messageFetch( 123 | RpcPayload.from( 124 | params: MessageFetchParams( 125 | context: _loginResult!.userContext, 126 | channelId: channelId, 127 | ), 128 | ), 129 | ); 130 | } 131 | 132 | return _api.getMessages( 133 | RpcPayload.from( 134 | params: GetMessagesParams( 135 | channelId: channelId, 136 | limit: 30, 137 | ), 138 | ), 139 | ); 140 | }, 141 | ); 142 | 143 | Future sendMessage({ 144 | required int channelId, 145 | required String message, 146 | List attachmentIds = const [], 147 | }) => 148 | _proccess( 149 | action: () async { 150 | if (_odooVersion == 14) { 151 | return _api.messagePost( 152 | RpcPayload.from( 153 | params: MessagePostParams( 154 | context: _loginResult!.userContext, 155 | channelId: channelId, 156 | body: message, 157 | attachmentIds: attachmentIds, 158 | ), 159 | ), 160 | ); 161 | } 162 | 163 | final response = await _api.sendMessage( 164 | RpcPayload.from( 165 | params: SendMessageParams( 166 | channelId: channelId, 167 | body: message, 168 | context: _loginResult!.userContext, 169 | attachmentIds: attachmentIds, 170 | ), 171 | ), 172 | ); 173 | 174 | return RpcResponse( 175 | jsonrpc: response.jsonrpc, 176 | id: response.id, 177 | result: response.result?.id, 178 | ); 179 | }, 180 | ); 181 | 182 | int _lastPoll = 0; 183 | Future> poll({ 184 | int? last, 185 | }) => 186 | _proccess( 187 | action: () async { 188 | final response = await _api.poll( 189 | RpcPayload.from( 190 | params: PollParams( 191 | last: last ?? _lastPoll, 192 | ), 193 | ), 194 | ); 195 | 196 | if (response.result?.isNotEmpty ?? false) { 197 | _lastPoll = response.result?.last.id ?? _lastPoll; 198 | } 199 | 200 | return response; 201 | }, 202 | ); 203 | 204 | String getAttachmentUrl(int id) { 205 | return '${_dio.options.baseUrl}/web/content/ir.attachment/$id/datas'; 206 | } 207 | 208 | Future getAttachment(int id) async { 209 | final response = await _dio.get( 210 | '/web/content/ir.attachment/$id/datas', 211 | options: Options( 212 | responseType: ResponseType.bytes, 213 | contentType: ContentType.binary.value, 214 | ), 215 | ); 216 | 217 | if (response.data == null) { 218 | throw OdooChatException( 219 | code: 404, 220 | message: 'Attachment not found', 221 | data: { 222 | 'id': id, 223 | }, 224 | ); 225 | } 226 | 227 | return Uint8List.fromList(response.data!); 228 | } 229 | 230 | String? _csrfToken; 231 | 232 | Future get csrfToken async { 233 | if (_csrfToken != null) { 234 | return _csrfToken!; 235 | } 236 | 237 | final response = await _dio.get( 238 | '/web', 239 | options: Options( 240 | contentType: ContentType.html.value, 241 | ), 242 | ); 243 | 244 | final document = response.data!; 245 | 246 | final csrfToken = document 247 | .split('csrf_token:') 248 | .last 249 | .split(',') 250 | .first 251 | .replaceAll('"', '') 252 | .replaceAll(' ', ''); 253 | 254 | return _csrfToken = csrfToken; 255 | } 256 | 257 | Future uploadAttachment({ 258 | required String filename, 259 | required Uint8List bytes, 260 | }) async { 261 | final token = await csrfToken; 262 | 263 | final response = await _dio.post( 264 | '/web/binary/upload_attachment', 265 | data: UploadAttachmentPayload( 266 | file: bytes, 267 | fileName: filename, 268 | token: token, 269 | ).payload, 270 | ); 271 | 272 | final attachmentId = 273 | response.data!.split('"id"').last.split(',').first.replaceAll(': ', ''); 274 | 275 | return int.parse(attachmentId); 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /lib/src/model/attachment/attachment.freezed.dart: -------------------------------------------------------------------------------- 1 | // coverage:ignore-file 2 | // GENERATED CODE - DO NOT MODIFY BY HAND 3 | // ignore_for_file: type=lint 4 | // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark 5 | 6 | part of 'attachment.dart'; 7 | 8 | // ************************************************************************** 9 | // FreezedGenerator 10 | // ************************************************************************** 11 | 12 | T _$identity(T value) => value; 13 | 14 | final _privateConstructorUsedError = UnsupportedError( 15 | 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 16 | 17 | Attachment _$AttachmentFromJson(Map json) { 18 | return _Attachment.fromJson(json); 19 | } 20 | 21 | /// @nodoc 22 | mixin _$Attachment { 23 | int get id => throw _privateConstructorUsedError; 24 | String get checksum => throw _privateConstructorUsedError; 25 | String get filename => throw _privateConstructorUsedError; 26 | String get name => throw _privateConstructorUsedError; 27 | String get mimetype => throw _privateConstructorUsedError; 28 | 29 | Map toJson() => throw _privateConstructorUsedError; 30 | @JsonKey(ignore: true) 31 | $AttachmentCopyWith get copyWith => 32 | throw _privateConstructorUsedError; 33 | } 34 | 35 | /// @nodoc 36 | abstract class $AttachmentCopyWith<$Res> { 37 | factory $AttachmentCopyWith( 38 | Attachment value, $Res Function(Attachment) then) = 39 | _$AttachmentCopyWithImpl<$Res, Attachment>; 40 | @useResult 41 | $Res call( 42 | {int id, String checksum, String filename, String name, String mimetype}); 43 | } 44 | 45 | /// @nodoc 46 | class _$AttachmentCopyWithImpl<$Res, $Val extends Attachment> 47 | implements $AttachmentCopyWith<$Res> { 48 | _$AttachmentCopyWithImpl(this._value, this._then); 49 | 50 | // ignore: unused_field 51 | final $Val _value; 52 | // ignore: unused_field 53 | final $Res Function($Val) _then; 54 | 55 | @pragma('vm:prefer-inline') 56 | @override 57 | $Res call({ 58 | Object? id = null, 59 | Object? checksum = null, 60 | Object? filename = null, 61 | Object? name = null, 62 | Object? mimetype = null, 63 | }) { 64 | return _then(_value.copyWith( 65 | id: null == id 66 | ? _value.id 67 | : id // ignore: cast_nullable_to_non_nullable 68 | as int, 69 | checksum: null == checksum 70 | ? _value.checksum 71 | : checksum // ignore: cast_nullable_to_non_nullable 72 | as String, 73 | filename: null == filename 74 | ? _value.filename 75 | : filename // ignore: cast_nullable_to_non_nullable 76 | as String, 77 | name: null == name 78 | ? _value.name 79 | : name // ignore: cast_nullable_to_non_nullable 80 | as String, 81 | mimetype: null == mimetype 82 | ? _value.mimetype 83 | : mimetype // ignore: cast_nullable_to_non_nullable 84 | as String, 85 | ) as $Val); 86 | } 87 | } 88 | 89 | /// @nodoc 90 | abstract class _$$AttachmentImplCopyWith<$Res> 91 | implements $AttachmentCopyWith<$Res> { 92 | factory _$$AttachmentImplCopyWith( 93 | _$AttachmentImpl value, $Res Function(_$AttachmentImpl) then) = 94 | __$$AttachmentImplCopyWithImpl<$Res>; 95 | @override 96 | @useResult 97 | $Res call( 98 | {int id, String checksum, String filename, String name, String mimetype}); 99 | } 100 | 101 | /// @nodoc 102 | class __$$AttachmentImplCopyWithImpl<$Res> 103 | extends _$AttachmentCopyWithImpl<$Res, _$AttachmentImpl> 104 | implements _$$AttachmentImplCopyWith<$Res> { 105 | __$$AttachmentImplCopyWithImpl( 106 | _$AttachmentImpl _value, $Res Function(_$AttachmentImpl) _then) 107 | : super(_value, _then); 108 | 109 | @pragma('vm:prefer-inline') 110 | @override 111 | $Res call({ 112 | Object? id = null, 113 | Object? checksum = null, 114 | Object? filename = null, 115 | Object? name = null, 116 | Object? mimetype = null, 117 | }) { 118 | return _then(_$AttachmentImpl( 119 | id: null == id 120 | ? _value.id 121 | : id // ignore: cast_nullable_to_non_nullable 122 | as int, 123 | checksum: null == checksum 124 | ? _value.checksum 125 | : checksum // ignore: cast_nullable_to_non_nullable 126 | as String, 127 | filename: null == filename 128 | ? _value.filename 129 | : filename // ignore: cast_nullable_to_non_nullable 130 | as String, 131 | name: null == name 132 | ? _value.name 133 | : name // ignore: cast_nullable_to_non_nullable 134 | as String, 135 | mimetype: null == mimetype 136 | ? _value.mimetype 137 | : mimetype // ignore: cast_nullable_to_non_nullable 138 | as String, 139 | )); 140 | } 141 | } 142 | 143 | /// @nodoc 144 | @JsonSerializable() 145 | class _$AttachmentImpl implements _Attachment { 146 | const _$AttachmentImpl( 147 | {required this.id, 148 | required this.checksum, 149 | required this.filename, 150 | required this.name, 151 | required this.mimetype}); 152 | 153 | factory _$AttachmentImpl.fromJson(Map json) => 154 | _$$AttachmentImplFromJson(json); 155 | 156 | @override 157 | final int id; 158 | @override 159 | final String checksum; 160 | @override 161 | final String filename; 162 | @override 163 | final String name; 164 | @override 165 | final String mimetype; 166 | 167 | @override 168 | String toString() { 169 | return 'Attachment(id: $id, checksum: $checksum, filename: $filename, name: $name, mimetype: $mimetype)'; 170 | } 171 | 172 | @override 173 | bool operator ==(Object other) { 174 | return identical(this, other) || 175 | (other.runtimeType == runtimeType && 176 | other is _$AttachmentImpl && 177 | (identical(other.id, id) || other.id == id) && 178 | (identical(other.checksum, checksum) || 179 | other.checksum == checksum) && 180 | (identical(other.filename, filename) || 181 | other.filename == filename) && 182 | (identical(other.name, name) || other.name == name) && 183 | (identical(other.mimetype, mimetype) || 184 | other.mimetype == mimetype)); 185 | } 186 | 187 | @JsonKey(ignore: true) 188 | @override 189 | int get hashCode => 190 | Object.hash(runtimeType, id, checksum, filename, name, mimetype); 191 | 192 | @JsonKey(ignore: true) 193 | @override 194 | @pragma('vm:prefer-inline') 195 | _$$AttachmentImplCopyWith<_$AttachmentImpl> get copyWith => 196 | __$$AttachmentImplCopyWithImpl<_$AttachmentImpl>(this, _$identity); 197 | 198 | @override 199 | Map toJson() { 200 | return _$$AttachmentImplToJson( 201 | this, 202 | ); 203 | } 204 | } 205 | 206 | abstract class _Attachment implements Attachment { 207 | const factory _Attachment( 208 | {required final int id, 209 | required final String checksum, 210 | required final String filename, 211 | required final String name, 212 | required final String mimetype}) = _$AttachmentImpl; 213 | 214 | factory _Attachment.fromJson(Map json) = 215 | _$AttachmentImpl.fromJson; 216 | 217 | @override 218 | int get id; 219 | @override 220 | String get checksum; 221 | @override 222 | String get filename; 223 | @override 224 | String get name; 225 | @override 226 | String get mimetype; 227 | @override 228 | @JsonKey(ignore: true) 229 | _$$AttachmentImplCopyWith<_$AttachmentImpl> get copyWith => 230 | throw _privateConstructorUsedError; 231 | } 232 | -------------------------------------------------------------------------------- /example/odoochat_example/lib/bloc/chat_bloc.dart: -------------------------------------------------------------------------------- 1 | // ignore_for_file: lines_longer_than_80_chars 2 | 3 | import 'dart:async'; 4 | import 'dart:io'; 5 | import 'dart:typed_data'; 6 | 7 | import 'package:equatable/equatable.dart'; 8 | import 'package:flutter_bloc/flutter_bloc.dart'; 9 | import 'package:flutter_chat_types/flutter_chat_types.dart'; 10 | import 'package:freezed_annotation/freezed_annotation.dart'; 11 | import 'package:intl/intl.dart'; 12 | import 'package:odoochat/odoochat.dart' 13 | show 14 | Attachment, 15 | InitMessagingResultExtension, 16 | OdooChat, 17 | PollMessageMessage, 18 | PollResult, 19 | PollResultExtension; 20 | import 'package:path/path.dart'; 21 | import 'package:path_provider/path_provider.dart'; 22 | 23 | // ignore: always_use_package_imports 24 | import 'chat_poll/chat_poll.dart'; 25 | 26 | part 'chat_bloc.freezed.dart'; 27 | part 'chat_state.dart'; 28 | 29 | class ChatBloc extends Cubit { 30 | ChatBloc({ 31 | required this.odooChat, 32 | }) : super(OdooChatState.initial()) { 33 | _loadData(); 34 | } 35 | 36 | final OdooChat odooChat; 37 | 38 | late final ChatPoll chatPoll = ChatPoll( 39 | odooChat: odooChat, 40 | ); 41 | 42 | late final StreamSubscription> _pollSubscription; 43 | 44 | Future _loadData() async { 45 | final loginResult = odooChat.loginResult!; 46 | 47 | final result = await odooChat.initMessaging(); 48 | 49 | final channels = 50 | result.channels.map((e) => AppChannel(id: e.id, name: e.name)); 51 | 52 | emit( 53 | state.copyWith( 54 | channels: channels.toList(), 55 | user: User( 56 | id: loginResult.partnerId.toString(), 57 | firstName: loginResult.partnerDisplayName.split(',').last, 58 | ), 59 | ), 60 | ); 61 | 62 | await chatPoll.run(); 63 | _pollSubscription = chatPoll.stream.listen(_handlePollResults); 64 | } 65 | 66 | Future _downloadAttachment(Attachment attachment) async { 67 | final directory = await getTemporaryDirectory(); 68 | final savePath = join(directory.path, attachment.filename); 69 | final data = await odooChat.getAttachment(attachment.id); 70 | 71 | final file = File(savePath); 72 | await file.writeAsBytes(data); 73 | 74 | return File(savePath); 75 | } 76 | 77 | Future _handlePollResults(List results) async { 78 | final newMessagesFuture = results 79 | .where((e) => e.channelId == state.currentChannel?.id) 80 | .map((e) async { 81 | if (e.message != null && e.message is PollMessageMessage) { 82 | final message = (e.message! as PollMessageMessage).data; 83 | 84 | final author = User( 85 | firstName: message.author.name, 86 | id: message.author.id.toString(), 87 | ); 88 | 89 | final attachments = await Future.wait( 90 | message.atachments.map( 91 | (attach) async { 92 | final saveFile = await _downloadAttachment(attach); 93 | 94 | if (attach.mimetype == 'image/jpeg' || 95 | attach.mimetype == 'image/png') { 96 | return ImageMessage( 97 | author: author, 98 | id: 'attach-${attach.id}', 99 | name: attach.filename, 100 | size: saveFile.lengthSync(), 101 | uri: saveFile.path, 102 | ); 103 | } 104 | 105 | return FileMessage( 106 | author: author, 107 | id: 'attach-${attach.id}', 108 | name: attach.filename, 109 | size: saveFile.lengthSync(), 110 | uri: saveFile.path, 111 | ); 112 | }, 113 | ), 114 | ); 115 | 116 | return [ 117 | if (message.body.isNotEmpty) 118 | TextMessage( 119 | author: author, 120 | id: message.id.toString(), 121 | text: Bidi.stripHtmlIfNeeded(message.body).trim(), 122 | createdAt: DateTime.parse(message.date).millisecondsSinceEpoch, 123 | ), 124 | ...attachments, 125 | ]; 126 | } 127 | 128 | return null; 129 | }); 130 | 131 | final newMessages = await Future.wait(newMessagesFuture); 132 | 133 | final newMessagesFiltered = newMessages 134 | .where((e) => e != null) 135 | .cast>() 136 | .expand((e) => e) 137 | .where((e) => !state.messages.map((e) => e.id).contains(e.id)); 138 | 139 | emit( 140 | state.copyWith( 141 | messages: [ 142 | ...newMessagesFiltered, 143 | ...state.messages, 144 | ], 145 | ), 146 | ); 147 | } 148 | 149 | Future setChannel(AppChannel channel) async { 150 | emit(state.copyWith(currentChannel: channel)); 151 | final result = await odooChat.fetchMessages(channel.id); 152 | 153 | final messages = await Future.wait( 154 | result.map((e) async { 155 | final author = User( 156 | id: e.author.id.toString(), 157 | firstName: e.author.name, 158 | ); 159 | 160 | final attachments = await Future.wait( 161 | e.atachments.map( 162 | (attach) async { 163 | final saveFile = await _downloadAttachment(attach); 164 | 165 | if (attach.mimetype == 'image/jpeg' || 166 | attach.mimetype == 'image/png') { 167 | return ImageMessage( 168 | author: author, 169 | id: 'attach-${attach.id}', 170 | name: attach.filename, 171 | size: saveFile.lengthSync(), 172 | uri: saveFile.path, 173 | ); 174 | } 175 | 176 | return FileMessage( 177 | author: author, 178 | id: 'attach-${attach.id}', 179 | name: attach.filename, 180 | size: saveFile.lengthSync(), 181 | uri: saveFile.path, 182 | ); 183 | }, 184 | ), 185 | ); 186 | 187 | return [ 188 | if (e.body.isNotEmpty) 189 | TextMessage( 190 | id: e.id.toString(), 191 | author: author, 192 | text: Bidi.stripHtmlIfNeeded(e.body).trim(), 193 | createdAt: DateTime.parse(e.date).millisecondsSinceEpoch, 194 | ), 195 | ...attachments, 196 | ]; 197 | }), 198 | ); 199 | 200 | emit( 201 | state.copyWith( 202 | messages: messages.expand((e) => e).toList(), 203 | ), 204 | ); 205 | } 206 | 207 | void exitChannel() => 208 | emit(state.copyWith(currentChannel: null, messages: [])); 209 | 210 | void handlePreviewDataFetched( 211 | TextMessage message, 212 | PreviewData previewData, 213 | ) { 214 | final index = 215 | state.messages.indexWhere((element) => element.id == message.id); 216 | 217 | final updatedMessage = (state.messages[index] as TextMessage).copyWith( 218 | previewData: previewData, 219 | ); 220 | 221 | emit( 222 | state.copyWith( 223 | messages: [ 224 | ...state.messages.sublist(0, index), 225 | updatedMessage, 226 | ...state.messages.sublist(index + 1), 227 | ], 228 | ), 229 | ); 230 | } 231 | 232 | Future sendMessage(PartialText message) async { 233 | if (state.currentChannel != null) { 234 | await odooChat.sendMessage( 235 | channelId: state.currentChannel!.id, 236 | message: message.text, 237 | ); 238 | } 239 | } 240 | 241 | Future sendAttachment({ 242 | required String filename, 243 | required Uint8List bytes, 244 | }) async { 245 | emit(state.copyWith(loading: true)); 246 | final attachmentId = await odooChat.uploadAttachment( 247 | filename: filename, 248 | bytes: bytes, 249 | ); 250 | emit(state.copyWith(loading: false)); 251 | 252 | await odooChat.sendMessage( 253 | channelId: state.currentChannel!.id, 254 | message: '', 255 | attachmentIds: [attachmentId], 256 | ); 257 | } 258 | 259 | @override 260 | Future close() async { 261 | await _pollSubscription.cancel(); 262 | return super.close(); 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /lib/src/payload/message_post_params/message_post_params.freezed.dart: -------------------------------------------------------------------------------- 1 | // coverage:ignore-file 2 | // GENERATED CODE - DO NOT MODIFY BY HAND 3 | // ignore_for_file: type=lint 4 | // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark 5 | 6 | part of 'message_post_params.dart'; 7 | 8 | // ************************************************************************** 9 | // FreezedGenerator 10 | // ************************************************************************** 11 | 12 | T _$identity(T value) => value; 13 | 14 | final _privateConstructorUsedError = UnsupportedError( 15 | 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 16 | 17 | MessagePostParams _$MessagePostParamsFromJson(Map json) { 18 | return _MessagePostParams.fromJson(json); 19 | } 20 | 21 | /// @nodoc 22 | mixin _$MessagePostParams { 23 | List get args => throw _privateConstructorUsedError; 24 | Map get kwargs => throw _privateConstructorUsedError; 25 | String get method => throw _privateConstructorUsedError; 26 | String get model => throw _privateConstructorUsedError; 27 | 28 | Map toJson() => throw _privateConstructorUsedError; 29 | @JsonKey(ignore: true) 30 | $MessagePostParamsCopyWith get copyWith => 31 | throw _privateConstructorUsedError; 32 | } 33 | 34 | /// @nodoc 35 | abstract class $MessagePostParamsCopyWith<$Res> { 36 | factory $MessagePostParamsCopyWith( 37 | MessagePostParams value, $Res Function(MessagePostParams) then) = 38 | _$MessagePostParamsCopyWithImpl<$Res, MessagePostParams>; 39 | @useResult 40 | $Res call( 41 | {List args, 42 | Map kwargs, 43 | String method, 44 | String model}); 45 | } 46 | 47 | /// @nodoc 48 | class _$MessagePostParamsCopyWithImpl<$Res, $Val extends MessagePostParams> 49 | implements $MessagePostParamsCopyWith<$Res> { 50 | _$MessagePostParamsCopyWithImpl(this._value, this._then); 51 | 52 | // ignore: unused_field 53 | final $Val _value; 54 | // ignore: unused_field 55 | final $Res Function($Val) _then; 56 | 57 | @pragma('vm:prefer-inline') 58 | @override 59 | $Res call({ 60 | Object? args = null, 61 | Object? kwargs = null, 62 | Object? method = null, 63 | Object? model = null, 64 | }) { 65 | return _then(_value.copyWith( 66 | args: null == args 67 | ? _value.args 68 | : args // ignore: cast_nullable_to_non_nullable 69 | as List, 70 | kwargs: null == kwargs 71 | ? _value.kwargs 72 | : kwargs // ignore: cast_nullable_to_non_nullable 73 | as Map, 74 | method: null == method 75 | ? _value.method 76 | : method // ignore: cast_nullable_to_non_nullable 77 | as String, 78 | model: null == model 79 | ? _value.model 80 | : model // ignore: cast_nullable_to_non_nullable 81 | as String, 82 | ) as $Val); 83 | } 84 | } 85 | 86 | /// @nodoc 87 | abstract class _$$MessagePostParamsImplCopyWith<$Res> 88 | implements $MessagePostParamsCopyWith<$Res> { 89 | factory _$$MessagePostParamsImplCopyWith(_$MessagePostParamsImpl value, 90 | $Res Function(_$MessagePostParamsImpl) then) = 91 | __$$MessagePostParamsImplCopyWithImpl<$Res>; 92 | @override 93 | @useResult 94 | $Res call( 95 | {List args, 96 | Map kwargs, 97 | String method, 98 | String model}); 99 | } 100 | 101 | /// @nodoc 102 | class __$$MessagePostParamsImplCopyWithImpl<$Res> 103 | extends _$MessagePostParamsCopyWithImpl<$Res, _$MessagePostParamsImpl> 104 | implements _$$MessagePostParamsImplCopyWith<$Res> { 105 | __$$MessagePostParamsImplCopyWithImpl(_$MessagePostParamsImpl _value, 106 | $Res Function(_$MessagePostParamsImpl) _then) 107 | : super(_value, _then); 108 | 109 | @pragma('vm:prefer-inline') 110 | @override 111 | $Res call({ 112 | Object? args = null, 113 | Object? kwargs = null, 114 | Object? method = null, 115 | Object? model = null, 116 | }) { 117 | return _then(_$MessagePostParamsImpl( 118 | args: null == args 119 | ? _value._args 120 | : args // ignore: cast_nullable_to_non_nullable 121 | as List, 122 | kwargs: null == kwargs 123 | ? _value._kwargs 124 | : kwargs // ignore: cast_nullable_to_non_nullable 125 | as Map, 126 | method: null == method 127 | ? _value.method 128 | : method // ignore: cast_nullable_to_non_nullable 129 | as String, 130 | model: null == model 131 | ? _value.model 132 | : model // ignore: cast_nullable_to_non_nullable 133 | as String, 134 | )); 135 | } 136 | } 137 | 138 | /// @nodoc 139 | @JsonSerializable() 140 | class _$MessagePostParamsImpl implements _MessagePostParams { 141 | const _$MessagePostParamsImpl( 142 | {required final List args, 143 | required final Map kwargs, 144 | required this.method, 145 | required this.model}) 146 | : _args = args, 147 | _kwargs = kwargs; 148 | 149 | factory _$MessagePostParamsImpl.fromJson(Map json) => 150 | _$$MessagePostParamsImplFromJson(json); 151 | 152 | final List _args; 153 | @override 154 | List get args { 155 | if (_args is EqualUnmodifiableListView) return _args; 156 | // ignore: implicit_dynamic_type 157 | return EqualUnmodifiableListView(_args); 158 | } 159 | 160 | final Map _kwargs; 161 | @override 162 | Map get kwargs { 163 | if (_kwargs is EqualUnmodifiableMapView) return _kwargs; 164 | // ignore: implicit_dynamic_type 165 | return EqualUnmodifiableMapView(_kwargs); 166 | } 167 | 168 | @override 169 | final String method; 170 | @override 171 | final String model; 172 | 173 | @override 174 | String toString() { 175 | return 'MessagePostParams._(args: $args, kwargs: $kwargs, method: $method, model: $model)'; 176 | } 177 | 178 | @override 179 | bool operator ==(Object other) { 180 | return identical(this, other) || 181 | (other.runtimeType == runtimeType && 182 | other is _$MessagePostParamsImpl && 183 | const DeepCollectionEquality().equals(other._args, _args) && 184 | const DeepCollectionEquality().equals(other._kwargs, _kwargs) && 185 | (identical(other.method, method) || other.method == method) && 186 | (identical(other.model, model) || other.model == model)); 187 | } 188 | 189 | @JsonKey(ignore: true) 190 | @override 191 | int get hashCode => Object.hash( 192 | runtimeType, 193 | const DeepCollectionEquality().hash(_args), 194 | const DeepCollectionEquality().hash(_kwargs), 195 | method, 196 | model); 197 | 198 | @JsonKey(ignore: true) 199 | @override 200 | @pragma('vm:prefer-inline') 201 | _$$MessagePostParamsImplCopyWith<_$MessagePostParamsImpl> get copyWith => 202 | __$$MessagePostParamsImplCopyWithImpl<_$MessagePostParamsImpl>( 203 | this, _$identity); 204 | 205 | @override 206 | Map toJson() { 207 | return _$$MessagePostParamsImplToJson( 208 | this, 209 | ); 210 | } 211 | } 212 | 213 | abstract class _MessagePostParams implements MessagePostParams { 214 | const factory _MessagePostParams( 215 | {required final List args, 216 | required final Map kwargs, 217 | required final String method, 218 | required final String model}) = _$MessagePostParamsImpl; 219 | 220 | factory _MessagePostParams.fromJson(Map json) = 221 | _$MessagePostParamsImpl.fromJson; 222 | 223 | @override 224 | List get args; 225 | @override 226 | Map get kwargs; 227 | @override 228 | String get method; 229 | @override 230 | String get model; 231 | @override 232 | @JsonKey(ignore: true) 233 | _$$MessagePostParamsImplCopyWith<_$MessagePostParamsImpl> get copyWith => 234 | throw _privateConstructorUsedError; 235 | } 236 | -------------------------------------------------------------------------------- /lib/src/payload/message_fetch_params/message_fetch_params.freezed.dart: -------------------------------------------------------------------------------- 1 | // coverage:ignore-file 2 | // GENERATED CODE - DO NOT MODIFY BY HAND 3 | // ignore_for_file: type=lint 4 | // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark 5 | 6 | part of 'message_fetch_params.dart'; 7 | 8 | // ************************************************************************** 9 | // FreezedGenerator 10 | // ************************************************************************** 11 | 12 | T _$identity(T value) => value; 13 | 14 | final _privateConstructorUsedError = UnsupportedError( 15 | 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); 16 | 17 | MessageFetchParams _$MessageFetchParamsFromJson(Map json) { 18 | return _MessageFetchParams.fromJson(json); 19 | } 20 | 21 | /// @nodoc 22 | mixin _$MessageFetchParams { 23 | List get args => throw _privateConstructorUsedError; 24 | Map get kwargs => throw _privateConstructorUsedError; 25 | String get method => throw _privateConstructorUsedError; 26 | String get model => throw _privateConstructorUsedError; 27 | 28 | Map toJson() => throw _privateConstructorUsedError; 29 | @JsonKey(ignore: true) 30 | $MessageFetchParamsCopyWith get copyWith => 31 | throw _privateConstructorUsedError; 32 | } 33 | 34 | /// @nodoc 35 | abstract class $MessageFetchParamsCopyWith<$Res> { 36 | factory $MessageFetchParamsCopyWith( 37 | MessageFetchParams value, $Res Function(MessageFetchParams) then) = 38 | _$MessageFetchParamsCopyWithImpl<$Res, MessageFetchParams>; 39 | @useResult 40 | $Res call( 41 | {List args, 42 | Map kwargs, 43 | String method, 44 | String model}); 45 | } 46 | 47 | /// @nodoc 48 | class _$MessageFetchParamsCopyWithImpl<$Res, $Val extends MessageFetchParams> 49 | implements $MessageFetchParamsCopyWith<$Res> { 50 | _$MessageFetchParamsCopyWithImpl(this._value, this._then); 51 | 52 | // ignore: unused_field 53 | final $Val _value; 54 | // ignore: unused_field 55 | final $Res Function($Val) _then; 56 | 57 | @pragma('vm:prefer-inline') 58 | @override 59 | $Res call({ 60 | Object? args = null, 61 | Object? kwargs = null, 62 | Object? method = null, 63 | Object? model = null, 64 | }) { 65 | return _then(_value.copyWith( 66 | args: null == args 67 | ? _value.args 68 | : args // ignore: cast_nullable_to_non_nullable 69 | as List, 70 | kwargs: null == kwargs 71 | ? _value.kwargs 72 | : kwargs // ignore: cast_nullable_to_non_nullable 73 | as Map, 74 | method: null == method 75 | ? _value.method 76 | : method // ignore: cast_nullable_to_non_nullable 77 | as String, 78 | model: null == model 79 | ? _value.model 80 | : model // ignore: cast_nullable_to_non_nullable 81 | as String, 82 | ) as $Val); 83 | } 84 | } 85 | 86 | /// @nodoc 87 | abstract class _$$MessageFetchParamsImplCopyWith<$Res> 88 | implements $MessageFetchParamsCopyWith<$Res> { 89 | factory _$$MessageFetchParamsImplCopyWith(_$MessageFetchParamsImpl value, 90 | $Res Function(_$MessageFetchParamsImpl) then) = 91 | __$$MessageFetchParamsImplCopyWithImpl<$Res>; 92 | @override 93 | @useResult 94 | $Res call( 95 | {List args, 96 | Map kwargs, 97 | String method, 98 | String model}); 99 | } 100 | 101 | /// @nodoc 102 | class __$$MessageFetchParamsImplCopyWithImpl<$Res> 103 | extends _$MessageFetchParamsCopyWithImpl<$Res, _$MessageFetchParamsImpl> 104 | implements _$$MessageFetchParamsImplCopyWith<$Res> { 105 | __$$MessageFetchParamsImplCopyWithImpl(_$MessageFetchParamsImpl _value, 106 | $Res Function(_$MessageFetchParamsImpl) _then) 107 | : super(_value, _then); 108 | 109 | @pragma('vm:prefer-inline') 110 | @override 111 | $Res call({ 112 | Object? args = null, 113 | Object? kwargs = null, 114 | Object? method = null, 115 | Object? model = null, 116 | }) { 117 | return _then(_$MessageFetchParamsImpl( 118 | args: null == args 119 | ? _value._args 120 | : args // ignore: cast_nullable_to_non_nullable 121 | as List, 122 | kwargs: null == kwargs 123 | ? _value._kwargs 124 | : kwargs // ignore: cast_nullable_to_non_nullable 125 | as Map, 126 | method: null == method 127 | ? _value.method 128 | : method // ignore: cast_nullable_to_non_nullable 129 | as String, 130 | model: null == model 131 | ? _value.model 132 | : model // ignore: cast_nullable_to_non_nullable 133 | as String, 134 | )); 135 | } 136 | } 137 | 138 | /// @nodoc 139 | @JsonSerializable() 140 | class _$MessageFetchParamsImpl implements _MessageFetchParams { 141 | const _$MessageFetchParamsImpl( 142 | {required final List args, 143 | required final Map kwargs, 144 | required this.method, 145 | required this.model}) 146 | : _args = args, 147 | _kwargs = kwargs; 148 | 149 | factory _$MessageFetchParamsImpl.fromJson(Map json) => 150 | _$$MessageFetchParamsImplFromJson(json); 151 | 152 | final List _args; 153 | @override 154 | List get args { 155 | if (_args is EqualUnmodifiableListView) return _args; 156 | // ignore: implicit_dynamic_type 157 | return EqualUnmodifiableListView(_args); 158 | } 159 | 160 | final Map _kwargs; 161 | @override 162 | Map get kwargs { 163 | if (_kwargs is EqualUnmodifiableMapView) return _kwargs; 164 | // ignore: implicit_dynamic_type 165 | return EqualUnmodifiableMapView(_kwargs); 166 | } 167 | 168 | @override 169 | final String method; 170 | @override 171 | final String model; 172 | 173 | @override 174 | String toString() { 175 | return 'MessageFetchParams._(args: $args, kwargs: $kwargs, method: $method, model: $model)'; 176 | } 177 | 178 | @override 179 | bool operator ==(Object other) { 180 | return identical(this, other) || 181 | (other.runtimeType == runtimeType && 182 | other is _$MessageFetchParamsImpl && 183 | const DeepCollectionEquality().equals(other._args, _args) && 184 | const DeepCollectionEquality().equals(other._kwargs, _kwargs) && 185 | (identical(other.method, method) || other.method == method) && 186 | (identical(other.model, model) || other.model == model)); 187 | } 188 | 189 | @JsonKey(ignore: true) 190 | @override 191 | int get hashCode => Object.hash( 192 | runtimeType, 193 | const DeepCollectionEquality().hash(_args), 194 | const DeepCollectionEquality().hash(_kwargs), 195 | method, 196 | model); 197 | 198 | @JsonKey(ignore: true) 199 | @override 200 | @pragma('vm:prefer-inline') 201 | _$$MessageFetchParamsImplCopyWith<_$MessageFetchParamsImpl> get copyWith => 202 | __$$MessageFetchParamsImplCopyWithImpl<_$MessageFetchParamsImpl>( 203 | this, _$identity); 204 | 205 | @override 206 | Map toJson() { 207 | return _$$MessageFetchParamsImplToJson( 208 | this, 209 | ); 210 | } 211 | } 212 | 213 | abstract class _MessageFetchParams implements MessageFetchParams { 214 | const factory _MessageFetchParams( 215 | {required final List args, 216 | required final Map kwargs, 217 | required final String method, 218 | required final String model}) = _$MessageFetchParamsImpl; 219 | 220 | factory _MessageFetchParams.fromJson(Map json) = 221 | _$MessageFetchParamsImpl.fromJson; 222 | 223 | @override 224 | List get args; 225 | @override 226 | Map get kwargs; 227 | @override 228 | String get method; 229 | @override 230 | String get model; 231 | @override 232 | @JsonKey(ignore: true) 233 | _$$MessageFetchParamsImplCopyWith<_$MessageFetchParamsImpl> get copyWith => 234 | throw _privateConstructorUsedError; 235 | } 236 | --------------------------------------------------------------------------------