chat development cont.

design_3.0_cx_module
Sikander Saleem 3 months ago
parent ec28f8992c
commit 01f004cecc

@ -15,7 +15,10 @@ class URLs {
// static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM // static final String _baseUrl = "$_host/v3/mobile"; // v3 for production CM,PM,TM
// static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation
static const String chatHubUrl = "https://apiderichat.hmg.com/chathub/api"; // new V2 apis static const String chatHubUrl = "https://apiderichat.hmg.com/chathub";
static const String chatHubUrlApi = "$chatHubUrl/api"; // new V2 apis
static const String chatHubUrlChat = "$chatHubUrl/hubs/chat"; // new V2 apis
static const String chatApiKey = "f53a98286f82798d588f67a7f0db19f7aebc839e"; // new V2 apis
static String _host = host1; static String _host = host1;
@ -341,4 +344,10 @@ class URLs {
static get convertDetailToComplete => '$_baseUrl/AssetInventory/ConvertDetailToComplete'; static get convertDetailToComplete => '$_baseUrl/AssetInventory/ConvertDetailToComplete';
static get getClassification => '$_baseUrl/AssetInventory/Classification'; static get getClassification => '$_baseUrl/AssetInventory/Classification';
//chat
static get chatSdkToken => '$chatHubUrlApi/auth/sdk-token';
//survey
static get getQuestionnaire => '$_baseUrl/SurveyQuestionnaire/GetQuestionnaire';
} }

@ -30,6 +30,7 @@ import 'package:test_sa/controllers/providers/api/status_drop_down/report/servic
import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart'; import 'package:test_sa/modules/asset_inventory_module/provider/asset_inventory_provider.dart';
import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart';
import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart'; import 'package:test_sa/modules/cm_module/views/nurse/create_new_request_view.dart';
import 'package:test_sa/modules/cx_module/chat/chat_provider.dart';
import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart'; import 'package:test_sa/modules/tm_module/tasks_wo/create_task_view.dart';
import 'package:test_sa/modules/traf_module/create_traf_request_page.dart'; import 'package:test_sa/modules/traf_module/create_traf_request_page.dart';
import 'package:test_sa/modules/traf_module/traf_request_provider.dart'; import 'package:test_sa/modules/traf_module/traf_request_provider.dart';
@ -99,6 +100,7 @@ import 'controllers/providers/api/gas_refill_comments.dart';
import 'controllers/providers/api/user_provider.dart'; import 'controllers/providers/api/user_provider.dart';
import 'controllers/providers/settings/setting_provider.dart'; import 'controllers/providers/settings/setting_provider.dart';
import 'dashboard_latest/dashboard_provider.dart'; import 'dashboard_latest/dashboard_provider.dart';
import 'modules/cx_module/survey/survey_provider.dart';
import 'new_views/pages/gas_refill_request_form.dart'; import 'new_views/pages/gas_refill_request_form.dart';
import 'providers/lookups/classification_lookup_provider.dart'; import 'providers/lookups/classification_lookup_provider.dart';
import 'providers/lookups/department_lookup_provider.dart'; import 'providers/lookups/department_lookup_provider.dart';
@ -238,8 +240,11 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => ServiceReportRepairLocationProvider()), ChangeNotifierProvider(create: (_) => ServiceReportRepairLocationProvider()),
ChangeNotifierProvider(create: (_) => ServiceRequestFaultDescriptionProvider()), ChangeNotifierProvider(create: (_) => ServiceRequestFaultDescriptionProvider()),
///todo deleted //chat
//ChangeNotifierProvider(create: (_) => ServiceReportVisitOperatorProvider()), ChangeNotifierProvider(create: (_) => ChatProvider()),
//chat
ChangeNotifierProvider(create: (_) => SurveyProvider()),
///todo deleted ///todo deleted
//ChangeNotifierProvider(create: (_) => ServiceReportMaintenanceSituationProvider()), //ChangeNotifierProvider(create: (_) => ServiceReportMaintenanceSituationProvider()),
//ChangeNotifierProvider(create: (_) => ServiceReportUsersProvider()), //ChangeNotifierProvider(create: (_) => ServiceReportUsersProvider()),

@ -112,7 +112,6 @@ class User {
} }
} }
Map<String, dynamic> toUpdateProfileJson() { Map<String, dynamic> toUpdateProfileJson() {
Map<String, dynamic> jsonObject = {}; Map<String, dynamic> jsonObject = {};
// if (departmentId != null) jsonObject["department"] = departmentId; // if (departmentId != null) jsonObject["department"] = departmentId;

@ -1,3 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:test_sa/controllers/providers/api/user_provider.dart'; import 'package:test_sa/controllers/providers/api/user_provider.dart';
@ -10,6 +11,8 @@ import 'package:test_sa/models/enums/work_order_next_step.dart';
import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart'; import 'package:test_sa/models/helper_data_models/workorder/work_order_helper_models.dart';
import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart'; import 'package:test_sa/modules/cm_module/service_request_detail_provider.dart';
import 'package:test_sa/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart'; import 'package:test_sa/modules/cm_module/views/components/bottom_sheets/service_request_bottomsheet.dart';
import 'package:test_sa/modules/cx_module/chat/chat_page.dart';
import 'package:test_sa/modules/cx_module/survey/survey_page.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart'; import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
@ -81,6 +84,18 @@ class _ServiceRequestDetailMainState extends State<ServiceRequestDetailMain> {
Navigator.pop(context); Navigator.pop(context);
}, },
actions: [ actions: [
IconButton(
icon: const Icon(Icons.feedback_rounded),
onPressed: () {
Navigator.push(context, CupertinoPageRoute(builder: (context) => SurveyPage(moduleId: 1, requestId: widget.requestId)));
},
),
IconButton(
icon: const Icon(Icons.chat_bubble),
onPressed: () {
Navigator.push(context, CupertinoPageRoute(builder: (context) => ChatPage(moduleId: 1, requestId: widget.requestId)));
},
),
isNurse isNurse
? IconButton( ? IconButton(
icon: 'qr'.toSvgAsset( icon: 'qr'.toSvgAsset(

@ -0,0 +1,295 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart';
import 'package:http/io_client.dart';
// ignore_for_file: avoid_annotating_with_dynamic
typedef FactoryConstructor<U> = U Function(dynamic);
class APIError {
dynamic errorCode;
int? errorType;
String? errorMessage;
int? errorStatusCode;
APIError(this.errorCode, this.errorMessage, this.errorType, this.errorStatusCode);
Map<String, dynamic> toJson() => {'errorCode': errorCode, 'errorMessage': errorMessage, 'errorType': errorType, 'ErrorStatusCode': errorStatusCode};
@override
String toString() {
return jsonEncode(this);
}
}
APIException _throwAPIException(Response response) {
switch (response.statusCode) {
case 200:
APIError? apiError;
if (response.body != null && response.body.isNotEmpty) {
var jsonError = jsonDecode(response.body);
print(jsonError);
apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType'], jsonError['ErrorStatusCode']);
}
return APIException(APIException.BAD_REQUEST, error: apiError);
case 400:
APIError? apiError;
if (response.body != null && response.body.isNotEmpty) {
var jsonError = jsonDecode(response.body);
apiError = APIError(jsonError['ErrorCode'], jsonError['ErrorMessage'], jsonError['ErrorType'], jsonError['ErrorStatusCode']);
}
return APIException(APIException.BAD_REQUEST, error: apiError);
case 401:
return APIException(APIException.UNAUTHORIZED);
case 403:
return APIException(APIException.FORBIDDEN);
case 404:
return APIException(APIException.NOT_FOUND);
case 500:
return APIException(APIException.INTERNAL_SERVER_ERROR);
case 444:
var downloadUrl = response.headers["location"];
return APIException(APIException.UPGRADE_REQUIRED, arguments: downloadUrl);
default:
return APIException(APIException.OTHER);
}
}
class ApiClient {
static final ApiClient _instance = ApiClient._internal();
ApiClient._internal();
factory ApiClient() => _instance;
Future<U> postJsonForObject<T, U>(FactoryConstructor<U> factoryConstructor, String url, T jsonObject,
{String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async {
var _headers = {'Accept': 'application/json'};
if (headers != null && headers.isNotEmpty) {
_headers.addAll(headers);
}
if (!kReleaseMode) {
print("Url:$url");
var bodyJson = json.encode(jsonObject);
print("body:$bodyJson");
}
var response = await postJsonForResponse(url, jsonObject, token: token, queryParameters: queryParameters, headers: _headers, retryTimes: retryTimes, isFormData: isFormData);
try {
if (!kReleaseMode) {
// logger.i("Url: " + url);
// logger.i("res: " + response.body);
}
var jsonData = jsonDecode(response.body);
if (jsonData["IsAuthenticated"] != null) {
// AppState().setIsAuthenticated = jsonData["IsAuthenticated"];
}
// if(url.contains("GetOfferDiscountsConfigData")) {
// jsonData["ErrorMessage"] = "Service Not Available";
// jsonData["ErrorEndUserMessage"] = "Service Not Available";
// }
if (jsonData["ErrorMessage"] == null) {
return factoryConstructor(jsonData);
} else if (jsonData["MessageStatus"] == 2 && jsonData["IsOTPMaxLimitExceed"] == true) {
// await Utils.performLogout(AppRoutes.navigatorKey.currentContext, null);
throw const APIException(APIException.UNAUTHORIZED, error: null);
} else {
APIError? apiError;
apiError = APIError(jsonData['ErrorCode'], jsonData['ErrorEndUserMessage'], jsonData['ErrorType'] ?? 0, jsonData['ErrorStatusCode']);
throw APIException(APIException.BAD_REQUEST, error: apiError);
}
} catch (ex) {
if (ex is APIException) {
rethrow;
} else {
throw APIException(APIException.BAD_RESPONSE_FORMAT, arguments: ex);
}
}
}
Future<Response> postJsonForResponse<T>(String url, T jsonObject,
{String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0, bool isFormData = false}) async {
String? requestBody;
late Map<String, String> stringObj;
if (jsonObject != null) {
requestBody = jsonEncode(jsonObject);
if (headers == null) {
headers = {'Content-Type': 'application/json'};
} else {
headers['Content-Type'] = 'application/json';
}
}
if (isFormData) {
headers = {'Content-Type': 'application/x-www-form-urlencoded'};
stringObj = ((jsonObject ?? {}) as Map<String, dynamic>).map((key, value) => MapEntry(key, value?.toString() ?? ""));
}
return await _postForResponse(url, isFormData ? stringObj : requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes);
}
Future<Response> _postForResponse(String url, requestBody, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0}) async {
try {
var _headers = <String, String>{};
if (token != null) {
_headers['Authorization'] = 'Bearer $token';
}
if (headers != null && headers.isNotEmpty) {
_headers.addAll(headers);
}
if (queryParameters != null) {
var queryString = new Uri(queryParameters: queryParameters).query;
url = url + '?' + queryString;
}
var response = await _post(Uri.parse(url), body: requestBody, headers: _headers).timeout(Duration(seconds: 120));
if (response.statusCode >= 200 && response.statusCode < 300) {
return response;
} else {
throw _throwAPIException(response);
}
} on SocketException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
}
} on HttpException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
}
} on TimeoutException catch (e) {
throw APIException(APIException.TIMEOUT, arguments: e);
} on ClientException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
return await _postForResponse(url, requestBody, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
}
}
}
Future<Response> getJsonForResponse<T>(String url, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0}) async {
if (headers == null) {
headers = {'Content-Type': 'application/json'};
} else {
headers['Content-Type'] = 'application/json';
}
if (!kReleaseMode) {
print("Url:$url");
// var bodyJson = json.encode(jsonObject);
// print("body:$bodyJson");
}
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes);
}
Future<Response> _getForResponse(String url, {String? token, Map<String, dynamic>? queryParameters, Map<String, String>? headers, int retryTimes = 0}) async {
try {
var _headers = <String, String>{};
if (token != null) {
_headers['Authorization'] = 'Bearer $token';
}
if (headers != null && headers.isNotEmpty) {
_headers.addAll(headers);
}
if (queryParameters != null) {
var queryString = new Uri(queryParameters: queryParameters).query;
url = url + '?' + queryString;
}
var response = await _get(Uri.parse(url), headers: _headers).timeout(Duration(seconds: 60));
if (response.statusCode >= 200 && response.statusCode < 300) {
return response;
} else {
throw _throwAPIException(response);
}
} on SocketException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
}
} on HttpException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
}
} on TimeoutException catch (e) {
throw APIException(APIException.TIMEOUT, arguments: e);
} on ClientException catch (e) {
if (retryTimes > 0) {
print('will retry after 3 seconds...');
await Future.delayed(Duration(seconds: 3));
return await _getForResponse(url, token: token, queryParameters: queryParameters, headers: headers, retryTimes: retryTimes - 1);
} else {
throw APIException(APIException.OTHER, arguments: e);
}
}
}
Future<Response> _get(url, {Map<String, String>? headers}) => _withClient((client) => client.get(url, headers: headers));
bool _certificateCheck(X509Certificate cert, String host, int port) => true;
Future<T> _withClient<T>(Future<T> Function(Client) fn) async {
var httpClient = HttpClient()..badCertificateCallback = _certificateCheck;
var client = IOClient(httpClient);
try {
return await fn(client);
} finally {
client.close();
}
}
Future<Response> _post(url, {Map<String, String>? headers, body, Encoding? encoding}) => _withClient((client) => client.post(url, headers: headers, body: body, encoding: encoding));
}
class APIException implements Exception {
static const String BAD_REQUEST = 'api_common_bad_request';
static const String UNAUTHORIZED = 'api_common_unauthorized';
static const String FORBIDDEN = 'api_common_forbidden';
static const String NOT_FOUND = 'api_common_not_found';
static const String INTERNAL_SERVER_ERROR = 'api_common_internal_server_error';
static const String UPGRADE_REQUIRED = 'api_common_upgrade_required';
static const String BAD_RESPONSE_FORMAT = 'api_common_bad_response_format';
static const String OTHER = 'api_common_http_error';
static const String TIMEOUT = 'api_common_http_timeout';
static const String UNKNOWN = 'unexpected_error';
final String message;
final APIError? error;
final arguments;
const APIException(this.message, {this.arguments, this.error});
Map<String, dynamic> toJson() => {'message': message, 'error': error, 'arguments': '$arguments'};
@override
String toString() {
return jsonEncode(this);
}
}

@ -6,10 +6,15 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:http/http.dart'; import 'package:http/http.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart'; import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart';
import 'package:http/http.dart' as http;
import 'api_client.dart';
import 'model/chat_login_response_model.dart';
import 'model/chat_participant_model.dart';
import 'model/get_search_user_chat_model.dart'; import 'model/get_search_user_chat_model.dart';
import 'model/get_user_login_token_model.dart'; import 'model/get_user_login_token_model.dart' as userLoginTokenModel;
import 'model/user_chat_history_model.dart';
// import 'package:mohem_flutter_app/api/api_client.dart'; // import 'package:mohem_flutter_app/api/api_client.dart';
// import 'package:mohem_flutter_app/app_state/app_state.dart'; // import 'package:mohem_flutter_app/app_state/app_state.dart';
@ -33,100 +38,137 @@ class ChatApiClient {
factory ChatApiClient() => _instance; factory ChatApiClient() => _instance;
Future<UserAutoLoginModel> getUserLoginToken() async { ChatLoginResponse? chatLoginResponse;
UserAutoLoginModel userLoginResponse = UserAutoLoginModel();
String? deviceToken = AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken; Future<ChatLoginResponse?> getChatLoginToken(int moduleId, int requestId, String title, String employeeNumber) async {
Response response = await ApiClient().postJsonForResponse( Response response = await ApiClient().postJsonForResponse(URLs.chatSdkToken, {
"${ApiConsts.chatLoginTokenUrl}externaluserlogin", "apiKey": URLs.chatApiKey,
{ "employeeNumber": employeeNumber,
"employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(), "userDetails": {"userName": ApiManager.instance.user?.username, "email": ApiManager.instance.user?.email},
"password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG", "contextEnabled": true,
"isMobile": true, "moduleCode": moduleId.toString(),
"platform": Platform.isIOS ? "ios" : "android", "referenceId": requestId.toString(),
"deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken, "referenceType": "ticket",
"isHuaweiDevice": AppState().getIsHuawei, "title": title
"voipToken": Platform.isIOS ? "80a3b01fc1ef2453eb4f1daa4fc31d8142d9cb67baf848e91350b607971fe2ba" : "", });
},
);
if (!kReleaseMode) { if (!kReleaseMode) {
// logger.i("login-res: " + response.body); // logger.i("login-res: " + response.body);
} }
if (response.statusCode == 200) { if (response.statusCode == 200) {
userLoginResponse = user.userAutoLoginModelFromJson(response.body); chatLoginResponse = ChatLoginResponse.fromJson(jsonDecode(response.body));
} else if (response.statusCode == 501 || response.statusCode == 502 || response.statusCode == 503 || response.statusCode == 504) {
getUserLoginToken();
} else {
userLoginResponse = user.userAutoLoginModelFromJson(response.body);
userLoginResponse.errorResponses!.first.message!.showToast;
} }
return userLoginResponse; return chatLoginResponse;
} }
Future<ChatUserModel> getChatMemberFromSearch(String searchParam, int cUserId, int pageNo) async { Future<ChatParticipantModel?> loadParticipants(int moduleId, int referenceId,String? assigneeEmployeeNumber) async {
ChatUserModel chatUserModel; Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber", token: chatLoginResponse!.token);
Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatLoginTokenUrl}getUserWithStatusAndFavAsync", {"employeeNumber": cUserId, "userName": searchParam, "pageNumber": pageNo},
token: AppState().chatDetails!.response!.token);
if (!kReleaseMode) { if (!kReleaseMode) {
logger.i("res: " + response.body); // logger.i("login-res: " + response.body);
}
if (response.statusCode == 200) {
return ChatParticipantModel.fromJson(jsonDecode(response.body));
} else {
return null;
} }
chatUserModel = chatUserModelFromJson(response.body);
return chatUserModel;
} }
//Get User Recent Chats Future<UserChatHistoryModel?> loadChatHistory(int moduleId, int referenceId, String myId, String otherId) async {
Future<ChatUserModel> getRecentChats() async { Response response = await ApiClient().postJsonForResponse(
"${URLs.chatHubUrlApi}/UserChatHistory/GetUserChatHistory/$myId/$otherId/0", {"moduleCode": moduleId.toString(), "referenceId": referenceId.toString()},
token: chatLoginResponse!.token);
try { try {
Response response = if (response.statusCode == 200) {
return UserChatHistoryModel.fromJson(jsonDecode(response.body));
} else {
// await ApiManager.instance.get(URLs.getAllRequestsAndCount,h); return null;
await ApiClient().getJsonForResponse(
"${ApiConsts.chatRecentUrl}getchathistorybyuserid",
token: AppState().chatDetails!.response!.token,
);
if (!kReleaseMode) {
logger.i("res: " + response.body);
} }
return ChatUserModel.fromJson( } catch (ex) {
json.decode(response.body), return null;
);
} catch (e) {
throw e;
} }
} }
// // Get Favorite Users Future<ChatResponse?> sendTextMessage(String message, int conversationId) async {
// Future<ChatUserModel> getFavUsers() async {
// Response favRes = await ApiClient().getJsonForResponse(
// "${ApiConsts.chatFavUser}getFavUserById/${AppState().chatDetails!.response!.id}",
// token: AppState().chatDetails!.response!.token,
// );
// if (!kReleaseMode) {
// logger.i("res: " + favRes.body);
// }
// return ChatUserModel.fromJson(json.decode(favRes.body));
// }
//Get User Chat History
Future<Response> getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false, required int paginationVal}) async {
try { try {
Response response = await ApiClient().getJsonForResponse( Response response =
"${ApiConsts.chatSingleUserHistoryUrl}GetUserChatHistory/$senderUID/$receiverUID/$paginationVal", await ApiClient().postJsonForResponse("${URLs.chatHubUrlApi}/chat/conversations/$conversationId/messages", {"content": message, "messageType": "Text"}, token: chatLoginResponse!.token);
token: AppState().chatDetails!.response!.token,
); if (response.statusCode == 200) {
if (!kReleaseMode) { return ChatResponse.fromJson(jsonDecode(response.body));
logger.i("res: " + response.body); } else {
return null;
} }
return response; } catch (ex) {
} catch (e) { print(ex);
getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal); return null;
throw e;
} }
} }
// Future<ChatUserModel> getChatMemberFromSearch(String searchParam, int cUserId, int pageNo) async {
// ChatUserModel chatUserModel;
// Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatLoginTokenUrl}getUserWithStatusAndFavAsync", {"employeeNumber": cUserId, "userName": searchParam, "pageNumber": pageNo},
// token: AppState().chatDetails!.response!.token);
// if (!kReleaseMode) {
// logger.i("res: " + response.body);
// }
// chatUserModel = chatUserModelFromJson(response.body);
// return chatUserModel;
// }
// //Get User Recent Chats
// Future<ChatUserModel> getRecentChats() async {
// try {
// Response response =
//
//
// // await ApiManager.instance.get(URLs.getAllRequestsAndCount,h);
//
//
// await ApiClient().getJsonForResponse(
// "${ApiConsts.chatRecentUrl}getchathistorybyuserid",
// token: AppState().chatDetails!.response!.token,
// );
// if (!kReleaseMode) {
// logger.i("res: " + response.body);
// }
// return ChatUserModel.fromJson(
// json.decode(response.body),
// );
// } catch (e) {
// throw e;
// }
// }
// // Get Favorite Users
// Future<ChatUserModel> getFavUsers() async {
// Response favRes = await ApiClient().getJsonForResponse(
// "${ApiConsts.chatFavUser}getFavUserById/${AppState().chatDetails!.response!.id}",
// token: AppState().chatDetails!.response!.token,
// );
// if (!kReleaseMode) {
// logger.i("res: " + favRes.body);
// }
// return ChatUserModel.fromJson(json.decode(favRes.body));
// }
// //Get User Chat History
// Future<Response> getSingleUserChatHistory({required int senderUID, required int receiverUID, required bool loadMore, bool isNewChat = false, required int paginationVal}) async {
// try {
// Response response = await ApiClient().getJsonForResponse(
// "${ApiConsts.chatSingleUserHistoryUrl}GetUserChatHistory/$senderUID/$receiverUID/$paginationVal",
// token: AppState().chatDetails!.response!.token,
// );
// if (!kReleaseMode) {
// logger.i("res: " + response.body);
// }
// return response;
// } catch (e) {
// getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal);
// throw e;
// }
// }
// //Favorite Users // //Favorite Users
// Future<fav.FavoriteChatUser> favUser({required int userID, required int targetUserID}) async { // Future<fav.FavoriteChatUser> favUser({required int userID, required int targetUserID}) async {
// Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatFavUser}addFavUser", {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token); // Response response = await ApiClient().postJsonForResponse("${ApiConsts.chatFavUser}addFavUser", {"targetUserId": targetUserID, "userId": userID}, token: AppState().chatDetails!.response!.token);
@ -137,54 +179,54 @@ class ChatApiClient {
// return favoriteChatUser; // return favoriteChatUser;
// } // }
// //UnFavorite Users // //UnFavorite Users
// Future<fav.FavoriteChatUser> unFavUser({required int userID, required int targetUserID}) async { // Future<fav.FavoriteChatUser> unFavUser({required int userID, required int targetUserID}) async {
// try { // try {
// Response response = await ApiClient().postJsonForResponse( // Response response = await ApiClient().postJsonForResponse(
// "${ApiConsts.chatFavUser}deleteFavUser", // "${ApiConsts.chatFavUser}deleteFavUser",
// {"targetUserId": targetUserID, "userId": userID}, // {"targetUserId": targetUserID, "userId": userID},
// token: AppState().chatDetails!.response!.token, // token: AppState().chatDetails!.response!.token,
// ); // );
// if (!kReleaseMode) { // if (!kReleaseMode) {
// logger.i("res: " + response.body); // logger.i("res: " + response.body);
// } // }
// fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body); // fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body);
// return favoriteChatUser; // return favoriteChatUser;
// } catch (e) { // } catch (e) {
// e as APIException; // e as APIException;
// throw e; // throw e;
// } // }
// } // }
// Upload Chat Media // Upload Chat Media
Future<Object?> uploadMedia(String userId, File file, String fileSource) async { // Future<Object?> uploadMedia(String userId, File file, String fileSource) async {
if (kDebugMode) { // if (kDebugMode) {
print("${ApiConsts.chatMediaImageUploadUrl}upload"); // print("${ApiConsts.chatMediaImageUploadUrl}upload");
print(AppState().chatDetails!.response!.token); // print(AppState().chatDetails!.response!.token);
} // }
//
dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload')); // dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload'));
request.fields.addAll({'userId': userId, 'fileSource': fileSource}); // request.fields.addAll({'userId': userId, 'fileSource': fileSource});
request.files.add(await MultipartFile.fromPath('files', file.path)); // request.files.add(await MultipartFile.fromPath('files', file.path));
request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'}); // request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'});
StreamedResponse response = await request.send(); // StreamedResponse response = await request.send();
String data = await response.stream.bytesToString(); // String data = await response.stream.bytesToString();
if (!kReleaseMode) { // if (!kReleaseMode) {
logger.i("res: " + data); // logger.i("res: " + data);
} // }
return jsonDecode(data); // return jsonDecode(data);
} // }
// Download File For Chat // Download File For Chat
Future<Uint8List> downloadURL({required String fileName, required String fileTypeDescription, required int fileSource}) async { // Future<Uint8List> downloadURL({required String fileName, required String fileTypeDescription, required int fileSource}) async {
Response response = await ApiClient().postJsonForResponse( // Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.chatMediaImageUploadUrl}download", // "${ApiConsts.chatMediaImageUploadUrl}download",
{"fileType": fileTypeDescription, "fileName": fileName, "fileSource": fileSource}, // {"fileType": fileTypeDescription, "fileName": fileName, "fileSource": fileSource},
token: AppState().chatDetails!.response!.token, // token: AppState().chatDetails!.response!.token,
); // );
Uint8List data = Uint8List.fromList(response.bodyBytes); // Uint8List data = Uint8List.fromList(response.bodyBytes);
return data; // return data;
} // }
// //Get Chat Users & Favorite Images // //Get Chat Users & Favorite Images
// Future<List<ChatUserImageModel>> getUsersImages({required List<String> encryptedEmails}) async { // Future<List<ChatUserImageModel>> getUsersImages({required List<String> encryptedEmails}) async {

@ -1,17 +1,27 @@
import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_sa/extensions/context_extension.dart';
import 'package:test_sa/extensions/int_extensions.dart'; import 'package:test_sa/extensions/int_extensions.dart';
import 'package:test_sa/extensions/string_extensions.dart'; import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart'; import 'package:test_sa/modules/cm_module/views/components/action_button/footer_action_button.dart';
import 'package:test_sa/modules/cx_module/chat/chat_api_client.dart';
import 'package:test_sa/modules/cx_module/chat/chat_provider.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted } enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted }
class ChatPage extends StatefulWidget { class ChatPage extends StatefulWidget {
ChatPage({Key? key}) : super(key: key); int moduleId;
int requestId;
String title;
bool readOnly;
ChatPage({Key? key, required this.moduleId, required this.requestId, this.title = "Chat", this.readOnly = false}) : super(key: key);
@override @override
_ChatPageState createState() { _ChatPageState createState() {
@ -27,11 +37,14 @@ class _ChatPageState extends State<ChatPage> {
final RecorderController recorderController = RecorderController(); final RecorderController recorderController = RecorderController();
PlayerController playerController = PlayerController(); PlayerController playerController = PlayerController();
TextEditingController textEditingController = TextEditingController();
ChatState chatState = ChatState.idle; ChatState chatState = ChatState.idle;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
getChatToken();
playerController.addListener(() async { playerController.addListener(() async {
// if (playerController.playerState == PlayerState.playing && playerController.maxDuration == await playerController.getDuration()) { // if (playerController.playerState == PlayerState.playing && playerController.maxDuration == await playerController.getDuration()) {
// await playerController.stopPlayer(); // await playerController.stopPlayer();
@ -40,6 +53,11 @@ class _ChatPageState extends State<ChatPage> {
}); });
} }
void getChatToken() {
String assigneeEmployeeNumber = "";
Provider.of<ChatProvider>(context, listen: false).getUserAutoLoginToken(widget.moduleId, widget.requestId + 2, widget.title, context.settingProvider.username, assigneeEmployeeNumber);
}
@override @override
void dispose() { void dispose() {
playerController.dispose(); playerController.dispose();
@ -50,342 +68,394 @@ class _ChatPageState extends State<ChatPage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
backgroundColor: AppColor.white10, backgroundColor: AppColor.white10,
appBar: const DefaultAppBar(title: "Req No. 343443"), appBar: DefaultAppBar(title: widget.title),
body: Column( body: Consumer<ChatProvider>(builder: (context, chatProvider, child) {
children: [ if (chatProvider.chatLoginTokenLoading) return const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3).center;
Container(
color: AppColor.neutral50, if (chatProvider.chatLoginResponse == null) {
constraints: const BoxConstraints(maxHeight: 56), return Column(
padding: const EdgeInsets.all(16), mainAxisSize: MainAxisSize.min,
child: Row( crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
Text( Text(
"Engineer: Mahmoud Shrouf", "Failed to connect chat",
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 2, maxLines: 1,
style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), style: AppTextStyles.heading6.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w500),
).expanded,
4.width,
Text(
"View All Documents",
style: AppTextStyles.bodyText.copyWith(
color: AppColor.white10,
decoration: TextDecoration.underline,
decorationColor: AppColor.white10,
),
), ),
24.height,
AppFilledButton(
label: "Retry",
maxWidth: true,
buttonColor: AppColor.primary10,
onPressed: () async {
getChatToken();
},
).paddingOnly(start: 48, end: 48)
], ],
), ).center;
), }
Container( return Column(
// width: double.infinity, children: [
color: AppColor.neutral100, Container(
child: ListView( color: AppColor.neutral50,
constraints: const BoxConstraints(maxHeight: 56),
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
children: [ child: Row(
recipientMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?"), children: [
recipientMsgCard(false, "testing"), Text(
recipientMsgCard(false, "testing testing testing"), "Engineer: Mahmoud Shrouf",
dateCard("Mon 27 Oct"), overflow: TextOverflow.ellipsis,
senderMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?"), maxLines: 2,
senderMsgCard(false, "Please let me know what is the issue?"), style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10),
],
)).expanded,
Divider(height: 1, thickness: 1, color: const Color(0xff767676).withOpacity(.11)),
SafeArea(
child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: 56),
child: Row(
children: [
if (chatState == ChatState.idle) ...[
TextFormField(
cursorColor: AppColor.neutral50,
style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50),
minLines: 1,
maxLines: 3,
textInputAction: TextInputAction.none,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
border: InputBorder.none,
errorBorder: InputBorder.none,
contentPadding: const EdgeInsets.only(left: 16, top: 8, bottom: 8),
alignLabelWithHint: true,
filled: true,
constraints: const BoxConstraints(),
suffixIconConstraints: const BoxConstraints(),
hintText: "Type your message here...",
hintStyle: AppTextStyles.bodyText.copyWith(color: const Color(0xffCCCCCC)),
// suffixIcon: Row(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.end,
// mainAxisAlignment: MainAxisAlignment.end,
// children: [
//
// 8.width,
// ],
// )
),
).expanded,
IconButton(
onPressed: () {},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: "chat_attachment".toSvgAsset(width: 24, height: 24),
constraints: const BoxConstraints(),
),
IconButton(
onPressed: () async {
await recorderController.checkPermission();
if (recorderController.hasPermission) {
chatState = ChatState.voiceRecordingStarted;
recorderController.record();
setState(() {});
} else {
"Audio permission denied. Please enable from setting".showToast;
}
// if (!isPermissionGranted) {
// "Audio permission denied. Please enable from setting".showToast;
// return;
// }
},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: "chat_mic".toSvgAsset(width: 24, height: 24),
constraints: const BoxConstraints(),
),
] else if (chatState == ChatState.voiceRecordingStarted) ...[
AudioWaveforms(
size: Size(MediaQuery.of(context).size.width, 56.0),
waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false),
padding: const EdgeInsets.only(left: 16),
recorderController: recorderController, // Customize how waveforms looks.
).expanded, ).expanded,
IconButton( 4.width,
onPressed: () async { Text(
isAudioRecording = false; "View All Documents",
await recorderController.pause(); style: AppTextStyles.bodyText.copyWith(
recordedFilePath = await recorderController.stop(); color: AppColor.white10,
chatState = ChatState.voiceRecordingCompleted; decoration: TextDecoration.underline,
setState(() {}); decorationColor: AppColor.white10,
},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
), ),
icon: Icon(Icons.stop_circle_rounded),
constraints: const BoxConstraints(),
)
] else if (chatState == ChatState.voiceRecordingCompleted) ...[
if (playerController.playerState == PlayerState.playing)
IconButton(
onPressed: () async {
await playerController.pausePlayer();
await playerController.stopPlayer();
setState(() {});
},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: const Icon(Icons.stop_circle_outlined, size: 20),
constraints: const BoxConstraints(),
)
else
IconButton(
onPressed: () async {
await playerController.preparePlayer(path: recordedFilePath!);
await playerController.startPlayer();
setState(() {});
},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: const Icon(Icons.play_circle_fill_rounded, size: 20),
constraints: const BoxConstraints(),
),
AudioFileWaveforms(
playerController: playerController,
waveformData: recorderController.waveData,
enableSeekGesture: false,
continuousWaveform: false,
waveformType: WaveformType.long,
playerWaveStyle: const PlayerWaveStyle(
fixedWaveColor: AppColor.neutral50,
liveWaveColor: AppColor.primary10,
showSeekLine: true,
),
size: Size(MediaQuery.of(context).size.width, 56.0),
).expanded,
IconButton(
onPressed: () async {
await playerController.stopPlayer();
recorderController.reset();
recordedFilePath = null;
chatState = ChatState.idle;
setState(() {});
},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: "delete_icon".toSvgAsset(width: 24, height: 24),
constraints: const BoxConstraints(),
), ),
], ],
),
),
Container(
// width: double.infinity,
color: AppColor.neutral100,
child: !chatProvider.userChatHistoryLoading
? ListView(
padding: const EdgeInsets.all(16),
children: [
recipientMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?", loading: true),
recipientMsgCard(false, "testing", loading: true),
recipientMsgCard(false, "testing testing testing", loading: true),
// dateCard("Mon 27 Oct",),
senderMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?", loading: true),
senderMsgCard(false, "Please let me know what is the issue?", loading: true),
],
)
: chatProvider.chatResponseList.isEmpty
? Text(
"Send a message to start conversation",
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: AppTextStyles.heading6.copyWith(color: AppColor.neutral50.withOpacity(.5), fontWeight: FontWeight.w500),
).center
: ListView.builder(
itemBuilder: (cxt, index) => recipientMsgCard(true, chatProvider.chatResponseList[index].content ?? ""), itemCount: chatProvider.chatResponseList.length))
.expanded,
if (!widget.readOnly) ...[
Divider(height: 1, thickness: 1, color: const Color(0xff767676).withOpacity(.11)),
SafeArea(
child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: 56),
child: Row(
children: [
if (chatState == ChatState.idle) ...[
TextFormField(
controller: textEditingController,
cursorColor: AppColor.neutral50,
style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50),
minLines: 1,
maxLines: 3,
textInputAction: TextInputAction.none,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
enabledBorder: InputBorder.none,
focusedBorder: InputBorder.none,
border: InputBorder.none,
errorBorder: InputBorder.none,
contentPadding: const EdgeInsets.only(left: 16, top: 8, bottom: 8),
alignLabelWithHint: true,
filled: true,
constraints: const BoxConstraints(),
suffixIconConstraints: const BoxConstraints(),
hintText: "Type your message here...",
hintStyle: AppTextStyles.bodyText.copyWith(color: const Color(0xffCCCCCC)),
// suffixIcon: Row(
// mainAxisSize: MainAxisSize.min,
// crossAxisAlignment: CrossAxisAlignment.end,
// mainAxisAlignment: MainAxisAlignment.end,
// children: [
//
// 8.width,
// ],
// )
),
).expanded,
IconButton(
onPressed: () {},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: "chat_attachment".toSvgAsset(width: 24, height: 24),
constraints: const BoxConstraints(),
),
IconButton(
onPressed: () async {
await recorderController.checkPermission();
if (recorderController.hasPermission) {
chatState = ChatState.voiceRecordingStarted;
recorderController.record();
setState(() {});
} else {
"Audio permission denied. Please enable from setting".showToast;
}
// if (!isPermissionGranted) {
// "Audio permission denied. Please enable from setting".showToast;
// return;
// }
},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: "chat_mic".toSvgAsset(width: 24, height: 24),
constraints: const BoxConstraints(),
),
] else if (chatState == ChatState.voiceRecordingStarted) ...[
AudioWaveforms(
size: Size(MediaQuery.of(context).size.width, 56.0),
waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false),
padding: const EdgeInsets.only(left: 16),
recorderController: recorderController, // Customize how waveforms looks.
).expanded,
IconButton(
onPressed: () async {
isAudioRecording = false;
await recorderController.pause();
recordedFilePath = await recorderController.stop();
chatState = ChatState.voiceRecordingCompleted;
setState(() {});
},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: Icon(Icons.stop_circle_rounded),
constraints: const BoxConstraints(),
)
] else if (chatState == ChatState.voiceRecordingCompleted) ...[
if (playerController.playerState == PlayerState.playing)
IconButton(
onPressed: () async {
await playerController.pausePlayer();
await playerController.stopPlayer();
setState(() {});
},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: const Icon(Icons.stop_circle_outlined, size: 20),
constraints: const BoxConstraints(),
)
else
IconButton(
onPressed: () async {
await playerController.preparePlayer(path: recordedFilePath!);
await playerController.startPlayer();
setState(() {});
},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: const Icon(Icons.play_circle_fill_rounded, size: 20),
constraints: const BoxConstraints(),
),
AudioFileWaveforms(
playerController: playerController,
waveformData: recorderController.waveData,
enableSeekGesture: false,
continuousWaveform: false,
waveformType: WaveformType.long,
playerWaveStyle: const PlayerWaveStyle(
fixedWaveColor: AppColor.neutral50,
liveWaveColor: AppColor.primary10,
showSeekLine: true,
),
size: Size(MediaQuery.of(context).size.width, 56.0),
).expanded,
IconButton(
onPressed: () async {
await playerController.stopPlayer();
recorderController.reset();
recordedFilePath = null;
chatState = ChatState.idle;
setState(() {});
},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: "delete_icon".toSvgAsset(width: 24, height: 24),
constraints: const BoxConstraints(),
),
],
// if (recordedFilePath == null) ...[ // if (recordedFilePath == null) ...[
// isAudioRecording // isAudioRecording
// ? AudioWaveforms( // ? AudioWaveforms(
// size: Size(MediaQuery.of(context).size.width, 56.0), // size: Size(MediaQuery.of(context).size.width, 56.0),
// //
// // enableGesture: true, // // enableGesture: true,
// //
// waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false), // waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false),
// padding: const EdgeInsets.only(left: 16), // padding: const EdgeInsets.only(left: 16),
// recorderController: recorderController, // Customize how waveforms looks. // recorderController: recorderController, // Customize how waveforms looks.
// ).expanded // ).expanded
// : TextFormField( // : TextFormField(
// cursorColor: AppColor.neutral50, // cursorColor: AppColor.neutral50,
// style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50), // style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50),
// minLines: 1, // minLines: 1,
// maxLines: 3, // maxLines: 3,
// textInputAction: TextInputAction.none, // textInputAction: TextInputAction.none,
// keyboardType: TextInputType.multiline, // keyboardType: TextInputType.multiline,
// decoration: InputDecoration( // decoration: InputDecoration(
// enabledBorder: InputBorder.none, // enabledBorder: InputBorder.none,
// focusedBorder: InputBorder.none, // focusedBorder: InputBorder.none,
// border: InputBorder.none, // border: InputBorder.none,
// errorBorder: InputBorder.none, // errorBorder: InputBorder.none,
// contentPadding: const EdgeInsets.only(left: 16, top: 8, bottom: 8), // contentPadding: const EdgeInsets.only(left: 16, top: 8, bottom: 8),
// alignLabelWithHint: true, // alignLabelWithHint: true,
// filled: true, // filled: true,
// constraints: const BoxConstraints(), // constraints: const BoxConstraints(),
// suffixIconConstraints: const BoxConstraints(), // suffixIconConstraints: const BoxConstraints(),
// hintText: "Type your message here...", // hintText: "Type your message here...",
// hintStyle: AppTextStyles.bodyText.copyWith(color: const Color(0xffCCCCCC)), // hintStyle: AppTextStyles.bodyText.copyWith(color: const Color(0xffCCCCCC)),
// // suffixIcon: Row( // // suffixIcon: Row(
// // mainAxisSize: MainAxisSize.min, // // mainAxisSize: MainAxisSize.min,
// // crossAxisAlignment: CrossAxisAlignment.end, // // crossAxisAlignment: CrossAxisAlignment.end,
// // mainAxisAlignment: MainAxisAlignment.end, // // mainAxisAlignment: MainAxisAlignment.end,
// // children: [ // // children: [
// // // //
// // 8.width, // // 8.width,
// // ], // // ],
// // ) // // )
// ), // ),
// ).expanded, // ).expanded,
// IconButton( // IconButton(
// onPressed: () {}, // onPressed: () {},
// style: const ButtonStyle( // style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ), // ),
// icon: "chat_attachment".toSvgAsset(width: 24, height: 24), // icon: "chat_attachment".toSvgAsset(width: 24, height: 24),
// constraints: const BoxConstraints(), // constraints: const BoxConstraints(),
// ), // ),
// ], // ],
// if (recordedFilePath == null) // if (recordedFilePath == null)
// ...[] // ...[]
// else ...[ // else ...[
// IconButton( // IconButton(
// onPressed: () async { // onPressed: () async {
// await playerController.preparePlayer(path: recordedFilePath!); // await playerController.preparePlayer(path: recordedFilePath!);
// playerController.startPlayer(); // playerController.startPlayer();
// }, // },
// style: const ButtonStyle( // style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ), // ),
// icon: const Icon(Icons.play_circle_fill_rounded, size: 20), // icon: const Icon(Icons.play_circle_fill_rounded, size: 20),
// constraints: const BoxConstraints(), // constraints: const BoxConstraints(),
// ), // ),
// AudioFileWaveforms( // AudioFileWaveforms(
// playerController: playerController, // playerController: playerController,
// size: Size(300, 50), // size: Size(300, 50),
// ).expanded, // ).expanded,
// IconButton( // IconButton(
// onPressed: () async { // onPressed: () async {
// playerController.pausePlayer(); // playerController.pausePlayer();
// }, // },
// style: const ButtonStyle( // style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ), // ),
// icon: const Icon(Icons.pause_circle_filled_outlined, size: 20), // icon: const Icon(Icons.pause_circle_filled_outlined, size: 20),
// constraints: const BoxConstraints(), // constraints: const BoxConstraints(),
// ), // ),
// IconButton( // IconButton(
// onPressed: () {}, // onPressed: () {},
// style: const ButtonStyle( // style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ), // ),
// icon: "delete".toSvgAsset(width: 24, height: 24), // icon: "delete".toSvgAsset(width: 24, height: 24),
// constraints: const BoxConstraints(), // constraints: const BoxConstraints(),
// ), // ),
// ], // ],
// if (isAudioRecording && recorderController.isRecording) // if (isAudioRecording && recorderController.isRecording)
// IconButton( // IconButton(
// onPressed: () {}, // onPressed: () {},
// style: const ButtonStyle( // style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ), // ),
// icon: "chat_msg_send".toSvgAsset(width: 24, height: 24), // icon: "chat_msg_send".toSvgAsset(width: 24, height: 24),
// constraints: const BoxConstraints(), // constraints: const BoxConstraints(),
// ), // ),
// if (isAudioRecording) // if (isAudioRecording)
// IconButton( // IconButton(
// onPressed: () async { // onPressed: () async {
// isAudioRecording = false; // isAudioRecording = false;
// await recorderController.pause(); // await recorderController.pause();
// recordedFilePath = await recorderController.stop(); // recordedFilePath = await recorderController.stop();
// chatState = ChatState.voiceRecordingCompleted; // chatState = ChatState.voiceRecordingCompleted;
// setState(() {}); // setState(() {});
// }, // },
// style: const ButtonStyle( // style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ), // ),
// icon: Icon(Icons.stop_circle_rounded), // icon: Icon(Icons.stop_circle_rounded),
// constraints: const BoxConstraints(), // constraints: const BoxConstraints(),
// ) // )
// else // else
// IconButton( // IconButton(
// onPressed: () async { // onPressed: () async {
// await recorderController.checkPermission(); // await recorderController.checkPermission();
// if (recorderController.hasPermission) { // if (recorderController.hasPermission) {
// setState(() { // setState(() {
// isAudioRecording = true; // isAudioRecording = true;
// }); // });
// recorderController.record(); // recorderController.record();
// } else { // } else {
// "Audio permission denied. Please enable from setting".showToast; // "Audio permission denied. Please enable from setting".showToast;
// } // }
// // if (!isPermissionGranted) { // // if (!isPermissionGranted) {
// // "Audio permission denied. Please enable from setting".showToast; // // "Audio permission denied. Please enable from setting".showToast;
// // return; // // return;
// // } // // }
// }, // },
// style: const ButtonStyle( // style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded // tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ), // ),
// icon: "chat_mic".toSvgAsset(width: 24, height: 24), // icon: "chat_mic".toSvgAsset(width: 24, height: 24),
// constraints: const BoxConstraints(), // constraints: const BoxConstraints(),
// ), // ),
IconButton( IconButton(
onPressed: () {}, onPressed: () {
style: const ButtonStyle( chatProvider.sendTextMessage(textEditingController.text).then((success) {
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded if (success) {
textEditingController.clear();
}
});
},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
),
icon: chatProvider.messageIsSending
? const SizedBox(
height: 24,
width: 24,
child: CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 2),
)
: "chat_msg_send".toSvgAsset(width: 24, height: 24),
constraints: const BoxConstraints(),
),
8.width,
],
), ),
icon: "chat_msg_send".toSvgAsset(width: 24, height: 24),
constraints: const BoxConstraints(),
), ),
8.width, )
], ]
), ],
), );
) }));
],
),
);
} }
Widget dateCard(String date) { Widget dateCard(String date) {
@ -400,7 +470,7 @@ class _ChatPageState extends State<ChatPage> {
.center; .center;
} }
Widget senderMsgCard(bool showHeader, String msg) { Widget senderMsgCard(bool showHeader, String msg, {bool loading = false}) {
Widget senderHeader = Row( Widget senderHeader = Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -409,13 +479,13 @@ class _ChatPageState extends State<ChatPage> {
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 1, maxLines: 1,
style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600),
), ).toShimmer(context: context, isShow: loading),
8.width, 8.width,
Container( Container(
height: 26, height: 26,
width: 26, width: 26,
decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.grey), decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.grey),
), ).toShimmer(context: context, isShow: loading),
], ],
); );
@ -440,11 +510,11 @@ class _ChatPageState extends State<ChatPage> {
Text( Text(
msg, msg,
style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120), style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120),
), ).toShimmer(context: context, isShow: loading),
Text( Text(
"2:00 PM", "2:00 PM",
style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.neutral50.withOpacity(0.5)), style: AppTextStyles.textFieldLabelStyle.copyWith(color: AppColor.neutral50.withOpacity(0.5)),
), ).toShimmer(context: context, isShow: loading),
], ],
)), )),
], ],
@ -452,7 +522,7 @@ class _ChatPageState extends State<ChatPage> {
); );
} }
Widget recipientMsgCard(bool showHeader, String msg) { Widget recipientMsgCard(bool showHeader, String msg, {bool loading = false}) {
Widget recipientHeader = Row( Widget recipientHeader = Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@ -460,14 +530,14 @@ class _ChatPageState extends State<ChatPage> {
height: 26, height: 26,
width: 26, width: 26,
decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.grey), decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.grey),
), ).toShimmer(context: context, isShow: loading),
8.width, 8.width,
Text( Text(
"Mahmoud Shrouf", "Mahmoud Shrouf",
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 1, maxLines: 1,
style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600), style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600),
) ).toShimmer(context: context, isShow: loading)
], ],
); );
@ -492,7 +562,7 @@ class _ChatPageState extends State<ChatPage> {
Text( Text(
msg, msg,
style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10), style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10),
), ).toShimmer(context: context, isShow: loading),
Align( Align(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
widthFactor: 1, widthFactor: 1,
@ -502,7 +572,7 @@ class _ChatPageState extends State<ChatPage> {
), ),
), ),
], ],
)), ).toShimmer(context: context, isShow: loading)),
], ],
), ),
); );

File diff suppressed because it is too large Load Diff

@ -80,7 +80,7 @@ class _ChatPageState extends State<ChatRoomsPage> {
), ),
], ],
).paddingOnly(top: 4, bottom: 4).onPress(() { ).paddingOnly(top: 4, bottom: 4).onPress(() {
Navigator.push(context, CupertinoPageRoute(builder: (context) => ChatPage())); // Navigator.push(context, CupertinoPageRoute(builder: (context) => ChatPage()));
return; return;
}), }),
separatorBuilder: (cxt, index) => const Divider().defaultStyle(context), separatorBuilder: (cxt, index) => const Divider().defaultStyle(context),

@ -0,0 +1,30 @@
class ChatLoginResponse {
String? token;
int? userId;
String? userName;
int? applicationId;
int? expiresIn;
String? context;
ChatLoginResponse({this.token, this.userId, this.userName, this.applicationId, this.expiresIn, this.context});
ChatLoginResponse.fromJson(Map<String, dynamic> json) {
token = json['token'];
userId = json['userId'];
userName = json['userName'];
applicationId = json['applicationId'];
expiresIn = json['expiresIn'];
context = json['context'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['token'] = this.token;
data['userId'] = this.userId;
data['userName'] = this.userName;
data['applicationId'] = this.applicationId;
data['expiresIn'] = this.expiresIn;
data['context'] = this.context;
return data;
}
}

@ -0,0 +1,65 @@
class ChatParticipantModel {
int? id;
String? title;
String? conversationType;
List<Participants>? participants;
String? lastMessage;
String? createdAt;
ChatParticipantModel({this.id, this.title, this.conversationType, this.participants, this.lastMessage, this.createdAt});
ChatParticipantModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
title = json['title'];
conversationType = json['conversationType'];
if (json['participants'] != null) {
participants = <Participants>[];
json['participants'].forEach((v) {
participants!.add(new Participants.fromJson(v));
});
}
lastMessage = json['lastMessage'];
createdAt = json['createdAt'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['title'] = this.title;
data['conversationType'] = this.conversationType;
if (this.participants != null) {
data['participants'] = this.participants!.map((v) => v.toJson()).toList();
}
data['lastMessage'] = this.lastMessage;
data['createdAt'] = this.createdAt;
return data;
}
}
class Participants {
String? userId;
String? userName;
String? employeeNumber;
String? role;
int? userStatus;
Participants({this.userId, this.userName, this.employeeNumber, this.role, this.userStatus});
Participants.fromJson(Map<String, dynamic> json) {
userId = json['userId'];
userName = json['userName'];
employeeNumber = json['employeeNumber'];
role = json['role'];
userStatus = json['userStatus'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['userId'] = this.userId;
data['userName'] = this.userName;
data['employeeNumber'] = this.employeeNumber;
data['role'] = this.role;
data['userStatus'] = this.userStatus;
return data;
}
}

@ -0,0 +1,65 @@
class UserChatHistoryModel {
List<ChatResponse>? response;
bool? isSuccess;
List<String>? onlineUserConnId;
UserChatHistoryModel({this.response, this.isSuccess, this.onlineUserConnId});
UserChatHistoryModel.fromJson(Map<String, dynamic> json) {
if (json['response'] != null) {
response = <ChatResponse>[];
json['response'].forEach((v) {
response!.add(new ChatResponse.fromJson(v));
});
}
isSuccess = json['isSuccess'];
onlineUserConnId = json['onlineUserConnId'].cast<String>();
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.response != null) {
data['response'] = this.response!.map((v) => v.toJson()).toList();
}
data['isSuccess'] = this.isSuccess;
data['onlineUserConnId'] = this.onlineUserConnId;
return data;
}
}
class ChatResponse {
int? id;
int? conversationId;
String? userId;
int? userIdInt;
String? userName;
String? content;
String? messageType;
String? createdAt;
ChatResponse({this.id, this.conversationId, this.userId, this.userIdInt, this.userName, this.content, this.messageType, this.createdAt});
ChatResponse.fromJson(Map<String, dynamic> json) {
id = json['id'];
conversationId = json['conversationId'];
userId = json['userId'];
userIdInt = json['userIdInt'];
userName = json['userName'];
content = json['content'];
messageType = json['messageType'];
createdAt = json['createdAt'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['conversationId'] = this.conversationId;
data['userId'] = this.userId;
data['userIdInt'] = this.userIdInt;
data['userName'] = this.userName;
data['content'] = this.content;
data['messageType'] = this.messageType;
data['createdAt'] = this.createdAt;
return data;
}
}

@ -13,7 +13,10 @@ import 'package:test_sa/new_views/common_widgets/app_text_form_field.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart'; import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
class SurveyPage extends StatefulWidget { class SurveyPage extends StatefulWidget {
SurveyPage({Key? key}) : super(key: key); int moduleId;
int requestId;
SurveyPage({Key? key, required this.moduleId, required this.requestId}) : super(key: key);
@override @override
_SurveyPageState createState() { _SurveyPageState createState() {
@ -29,6 +32,11 @@ class _SurveyPageState extends State<SurveyPage> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
getSurveyQuestion();
}
void getSurveyQuestion(){
} }
@override @override

@ -0,0 +1,34 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:test_sa/controllers/api_routes/api_manager.dart';
import 'package:test_sa/controllers/api_routes/urls.dart';
class SurveyProvider with ChangeNotifier {
bool loading = false;
void reset() {
loading = false;
// ChatApiClient().chatLoginResponse = null;
}
Future<void> getQuestionnaire(int surveySubmissionId) async {
reset();
loading = true;
notifyListeners();
final response = await ApiManager.instance.get(URLs.getQuestionnaire + "?surveySubmissionId=$surveySubmissionId");
loading = false;
notifyListeners();
}
// Future<void> loadChatHistory(int moduleId, int requestId) async {
// // loadChatHistoryLoading = true;
// // notifyListeners();
// chatLoginResponse = await ChatApiClient().loadChatHistory(moduleId, requestId);
// loadChatHistoryLoading = false;
// notifyListeners();
// }
}

@ -1,3 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart'; import 'package:fluttertoast/fluttertoast.dart';
@ -12,7 +13,8 @@ import 'package:test_sa/extensions/string_extensions.dart';
import 'package:test_sa/extensions/text_extensions.dart'; import 'package:test_sa/extensions/text_extensions.dart';
import 'package:test_sa/extensions/widget_extensions.dart'; import 'package:test_sa/extensions/widget_extensions.dart';
import 'package:test_sa/models/new_models/general_response_model.dart'; import 'package:test_sa/models/new_models/general_response_model.dart';
import 'package:test_sa/modules/cx_module/survey_page.dart'; import 'package:test_sa/modules/cx_module/chat/chat_page.dart';
import 'package:test_sa/modules/cx_module/survey/survey_page.dart';
import 'package:test_sa/new_views/app_style/app_color.dart'; import 'package:test_sa/new_views/app_style/app_color.dart';
import 'package:test_sa/new_views/forget_password_module/forget_passwod_verify_otp.dart'; import 'package:test_sa/new_views/forget_password_module/forget_passwod_verify_otp.dart';
import 'package:test_sa/new_views/pages/land_page/land_page.dart'; import 'package:test_sa/new_views/pages/land_page/land_page.dart';
@ -226,9 +228,8 @@ class _LoginPageState extends State<LoginPage> {
} }
Future<void> _login() async { Future<void> _login() async {
Navigator.push(context, MaterialPageRoute(builder: (context) => SurveyPage())); // Navigator.push(context, CupertinoPageRoute(builder: (context) => ChatPage(moduleId: 1, requestId: 1845972)));
// return;
return;
if (!_formKey.currentState!.validate()) return; if (!_formKey.currentState!.validate()) return;
if (privacyPolicyChecked == false) { if (privacyPolicyChecked == false) {

Loading…
Cancel
Save