chat development cont.

design_3.0_cx_module
Sikander Saleem 2 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/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;
@ -341,4 +344,10 @@ class URLs {
static get convertDetailToComplete => '$_baseUrl/AssetInventory/ConvertDetailToComplete';
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/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/cx_module/chat/chat_provider.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/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/settings/setting_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 'providers/lookups/classification_lookup_provider.dart';
import 'providers/lookups/department_lookup_provider.dart';
@ -238,8 +240,11 @@ class MyApp extends StatelessWidget {
ChangeNotifierProvider(create: (_) => ServiceReportRepairLocationProvider()),
ChangeNotifierProvider(create: (_) => ServiceRequestFaultDescriptionProvider()),
///todo deleted
//ChangeNotifierProvider(create: (_) => ServiceReportVisitOperatorProvider()),
//chat
ChangeNotifierProvider(create: (_) => ChatProvider()),
//chat
ChangeNotifierProvider(create: (_) => SurveyProvider()),
///todo deleted
//ChangeNotifierProvider(create: (_) => ServiceReportMaintenanceSituationProvider()),
//ChangeNotifierProvider(create: (_) => ServiceReportUsersProvider()),

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

@ -1,3 +1,4 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/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/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/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/common_widgets/default_app_bar.dart';
import 'package:test_sa/views/widgets/loaders/no_data_found.dart';
@ -81,6 +84,18 @@ class _ServiceRequestDetailMainState extends State<ServiceRequestDetailMain> {
Navigator.pop(context);
},
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
? IconButton(
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:http/http.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: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_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/app_state/app_state.dart';
@ -33,100 +38,137 @@ class ChatApiClient {
factory ChatApiClient() => _instance;
Future<UserAutoLoginModel> getUserLoginToken() async {
UserAutoLoginModel userLoginResponse = UserAutoLoginModel();
String? deviceToken = AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken;
Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.chatLoginTokenUrl}externaluserlogin",
{
"employeeNumber": AppState().memberInformationList!.eMPLOYEENUMBER.toString(),
"password": "FxIu26rWIKoF8n6mpbOmAjDLphzFGmpG",
"isMobile": true,
"platform": Platform.isIOS ? "ios" : "android",
"deviceToken": AppState().getIsHuawei ? AppState().getHuaweiPushToken : AppState().getDeviceToken,
"isHuaweiDevice": AppState().getIsHuawei,
"voipToken": Platform.isIOS ? "80a3b01fc1ef2453eb4f1daa4fc31d8142d9cb67baf848e91350b607971fe2ba" : "",
},
);
ChatLoginResponse? chatLoginResponse;
Future<ChatLoginResponse?> getChatLoginToken(int moduleId, int requestId, String title, String employeeNumber) async {
Response response = await ApiClient().postJsonForResponse(URLs.chatSdkToken, {
"apiKey": URLs.chatApiKey,
"employeeNumber": employeeNumber,
"userDetails": {"userName": ApiManager.instance.user?.username, "email": ApiManager.instance.user?.email},
"contextEnabled": true,
"moduleCode": moduleId.toString(),
"referenceId": requestId.toString(),
"referenceType": "ticket",
"title": title
});
if (!kReleaseMode) {
// logger.i("login-res: " + response.body);
}
if (response.statusCode == 200) {
userLoginResponse = user.userAutoLoginModelFromJson(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;
chatLoginResponse = ChatLoginResponse.fromJson(jsonDecode(response.body));
}
return userLoginResponse;
return chatLoginResponse;
}
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);
Future<ChatParticipantModel?> loadParticipants(int moduleId, int referenceId,String? assigneeEmployeeNumber) async {
Response response = await ApiClient().getJsonForResponse("${URLs.chatHubUrlApi}/chat/context/$moduleId/$referenceId?assigneeEmployeeNumber=$assigneeEmployeeNumber", token: chatLoginResponse!.token);
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<ChatUserModel> getRecentChats() async {
Future<UserChatHistoryModel?> loadChatHistory(int moduleId, int referenceId, String myId, String otherId) async {
Response response = await ApiClient().postJsonForResponse(
"${URLs.chatHubUrlApi}/UserChatHistory/GetUserChatHistory/$myId/$otherId/0", {"moduleCode": moduleId.toString(), "referenceId": referenceId.toString()},
token: chatLoginResponse!.token);
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);
if (response.statusCode == 200) {
return UserChatHistoryModel.fromJson(jsonDecode(response.body));
} else {
return null;
}
return ChatUserModel.fromJson(
json.decode(response.body),
);
} catch (e) {
throw e;
} catch (ex) {
return null;
}
}
// // 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 {
Future<ChatResponse?> sendTextMessage(String message, int conversationId) 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);
Response response =
await ApiClient().postJsonForResponse("${URLs.chatHubUrlApi}/chat/conversations/$conversationId/messages", {"content": message, "messageType": "Text"}, token: chatLoginResponse!.token);
if (response.statusCode == 200) {
return ChatResponse.fromJson(jsonDecode(response.body));
} else {
return null;
}
return response;
} catch (e) {
getSingleUserChatHistory(senderUID: senderUID, receiverUID: receiverUID, loadMore: loadMore, paginationVal: paginationVal);
throw e;
} catch (ex) {
print(ex);
return null;
}
}
// 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
// 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);
@ -137,54 +179,54 @@ class ChatApiClient {
// return favoriteChatUser;
// }
// //UnFavorite Users
// Future<fav.FavoriteChatUser> unFavUser({required int userID, required int targetUserID}) async {
// try {
// Response response = await ApiClient().postJsonForResponse(
// "${ApiConsts.chatFavUser}deleteFavUser",
// {"targetUserId": targetUserID, "userId": userID},
// token: AppState().chatDetails!.response!.token,
// );
// if (!kReleaseMode) {
// logger.i("res: " + response.body);
// }
// fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body);
// return favoriteChatUser;
// } catch (e) {
// e as APIException;
// throw e;
// }
// }
// //UnFavorite Users
// Future<fav.FavoriteChatUser> unFavUser({required int userID, required int targetUserID}) async {
// try {
// Response response = await ApiClient().postJsonForResponse(
// "${ApiConsts.chatFavUser}deleteFavUser",
// {"targetUserId": targetUserID, "userId": userID},
// token: AppState().chatDetails!.response!.token,
// );
// if (!kReleaseMode) {
// logger.i("res: " + response.body);
// }
// fav.FavoriteChatUser favoriteChatUser = fav.FavoriteChatUser.fromRawJson(response.body);
// return favoriteChatUser;
// } catch (e) {
// e as APIException;
// throw e;
// }
// }
// Upload Chat Media
Future<Object?> uploadMedia(String userId, File file, String fileSource) async {
if (kDebugMode) {
print("${ApiConsts.chatMediaImageUploadUrl}upload");
print(AppState().chatDetails!.response!.token);
}
dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload'));
request.fields.addAll({'userId': userId, 'fileSource': fileSource});
request.files.add(await MultipartFile.fromPath('files', file.path));
request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'});
StreamedResponse response = await request.send();
String data = await response.stream.bytesToString();
if (!kReleaseMode) {
logger.i("res: " + data);
}
return jsonDecode(data);
}
// Future<Object?> uploadMedia(String userId, File file, String fileSource) async {
// if (kDebugMode) {
// print("${ApiConsts.chatMediaImageUploadUrl}upload");
// print(AppState().chatDetails!.response!.token);
// }
//
// dynamic request = MultipartRequest('POST', Uri.parse('${ApiConsts.chatMediaImageUploadUrl}upload'));
// request.fields.addAll({'userId': userId, 'fileSource': fileSource});
// request.files.add(await MultipartFile.fromPath('files', file.path));
// request.headers.addAll({'Authorization': 'Bearer ${AppState().chatDetails!.response!.token}'});
// StreamedResponse response = await request.send();
// String data = await response.stream.bytesToString();
// if (!kReleaseMode) {
// logger.i("res: " + data);
// }
// return jsonDecode(data);
// }
// Download File For Chat
Future<Uint8List> downloadURL({required String fileName, required String fileTypeDescription, required int fileSource}) async {
Response response = await ApiClient().postJsonForResponse(
"${ApiConsts.chatMediaImageUploadUrl}download",
{"fileType": fileTypeDescription, "fileName": fileName, "fileSource": fileSource},
token: AppState().chatDetails!.response!.token,
);
Uint8List data = Uint8List.fromList(response.bodyBytes);
return data;
}
// Download File For Chat
// Future<Uint8List> downloadURL({required String fileName, required String fileTypeDescription, required int fileSource}) async {
// Response response = await ApiClient().postJsonForResponse(
// "${ApiConsts.chatMediaImageUploadUrl}download",
// {"fileType": fileTypeDescription, "fileName": fileName, "fileSource": fileSource},
// token: AppState().chatDetails!.response!.token,
// );
// Uint8List data = Uint8List.fromList(response.bodyBytes);
// return data;
// }
// //Get Chat Users & Favorite Images
// Future<List<ChatUserImageModel>> getUsersImages({required List<String> encryptedEmails}) async {

@ -1,17 +1,27 @@
import 'package:audio_waveforms/audio_waveforms.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/string_extensions.dart';
import 'package:test_sa/extensions/text_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/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/common_widgets/app_filled_button.dart';
import 'package:test_sa/new_views/common_widgets/default_app_bar.dart';
enum ChatState { idle, voiceRecordingStarted, voiceRecordingCompleted }
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
_ChatPageState createState() {
@ -27,11 +37,14 @@ class _ChatPageState extends State<ChatPage> {
final RecorderController recorderController = RecorderController();
PlayerController playerController = PlayerController();
TextEditingController textEditingController = TextEditingController();
ChatState chatState = ChatState.idle;
@override
void initState() {
super.initState();
getChatToken();
playerController.addListener(() async {
// if (playerController.playerState == PlayerState.playing && playerController.maxDuration == await playerController.getDuration()) {
// 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
void dispose() {
playerController.dispose();
@ -50,342 +68,394 @@ class _ChatPageState extends State<ChatPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.white10,
appBar: const DefaultAppBar(title: "Req No. 343443"),
body: Column(
children: [
Container(
color: AppColor.neutral50,
constraints: const BoxConstraints(maxHeight: 56),
padding: const EdgeInsets.all(16),
child: Row(
backgroundColor: AppColor.white10,
appBar: DefaultAppBar(title: widget.title),
body: Consumer<ChatProvider>(builder: (context, chatProvider, child) {
if (chatProvider.chatLoginTokenLoading) return const CircularProgressIndicator(color: AppColor.primary10, strokeWidth: 3).center;
if (chatProvider.chatLoginResponse == null) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Engineer: Mahmoud Shrouf",
"Failed to connect chat",
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10),
).expanded,
4.width,
Text(
"View All Documents",
style: AppTextStyles.bodyText.copyWith(
color: AppColor.white10,
decoration: TextDecoration.underline,
decorationColor: AppColor.white10,
),
maxLines: 1,
style: AppTextStyles.heading6.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w500),
),
24.height,
AppFilledButton(
label: "Retry",
maxWidth: true,
buttonColor: AppColor.primary10,
onPressed: () async {
getChatToken();
},
).paddingOnly(start: 48, end: 48)
],
),
),
Container(
// width: double.infinity,
color: AppColor.neutral100,
child: ListView(
).center;
}
return Column(
children: [
Container(
color: AppColor.neutral50,
constraints: const BoxConstraints(maxHeight: 56),
padding: const EdgeInsets.all(16),
children: [
recipientMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?"),
recipientMsgCard(false, "testing"),
recipientMsgCard(false, "testing testing testing"),
dateCard("Mon 27 Oct"),
senderMsgCard(true, "Please let me know what is the issue? Please let me know what is the issue?"),
senderMsgCard(false, "Please let me know what is the issue?"),
],
)).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.
child: Row(
children: [
Text(
"Engineer: Mahmoud Shrouf",
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10),
).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
4.width,
Text(
"View All Documents",
style: AppTextStyles.bodyText.copyWith(
color: AppColor.white10,
decoration: TextDecoration.underline,
decorationColor: AppColor.white10,
),
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) ...[
// isAudioRecording
// ? AudioWaveforms(
// size: Size(MediaQuery.of(context).size.width, 56.0),
//
// // enableGesture: true,
//
// waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false),
// padding: const EdgeInsets.only(left: 16),
// recorderController: recorderController, // Customize how waveforms looks.
// ).expanded
// : 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(),
// ),
// ],
// if (recordedFilePath == null)
// ...[]
// else ...[
// IconButton(
// onPressed: () async {
// await playerController.preparePlayer(path: recordedFilePath!);
// playerController.startPlayer();
// },
// style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ),
// icon: const Icon(Icons.play_circle_fill_rounded, size: 20),
// constraints: const BoxConstraints(),
// ),
// AudioFileWaveforms(
// playerController: playerController,
// size: Size(300, 50),
// ).expanded,
// IconButton(
// onPressed: () async {
// playerController.pausePlayer();
// },
// style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ),
// icon: const Icon(Icons.pause_circle_filled_outlined, size: 20),
// constraints: const BoxConstraints(),
// ),
// IconButton(
// onPressed: () {},
// style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ),
// icon: "delete".toSvgAsset(width: 24, height: 24),
// constraints: const BoxConstraints(),
// ),
// ],
// if (isAudioRecording && recorderController.isRecording)
// IconButton(
// onPressed: () {},
// style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ),
// icon: "chat_msg_send".toSvgAsset(width: 24, height: 24),
// constraints: const BoxConstraints(),
// ),
// if (isAudioRecording)
// 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
// IconButton(
// onPressed: () async {
// await recorderController.checkPermission();
// if (recorderController.hasPermission) {
// setState(() {
// isAudioRecording = true;
// });
// recorderController.record();
// } 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(),
// ),
// if (recordedFilePath == null) ...[
// isAudioRecording
// ? AudioWaveforms(
// size: Size(MediaQuery.of(context).size.width, 56.0),
//
// // enableGesture: true,
//
// waveStyle: const WaveStyle(waveColor: AppColor.neutral50, extendWaveform: true, showMiddleLine: false),
// padding: const EdgeInsets.only(left: 16),
// recorderController: recorderController, // Customize how waveforms looks.
// ).expanded
// : 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(),
// ),
// ],
// if (recordedFilePath == null)
// ...[]
// else ...[
// IconButton(
// onPressed: () async {
// await playerController.preparePlayer(path: recordedFilePath!);
// playerController.startPlayer();
// },
// style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ),
// icon: const Icon(Icons.play_circle_fill_rounded, size: 20),
// constraints: const BoxConstraints(),
// ),
// AudioFileWaveforms(
// playerController: playerController,
// size: Size(300, 50),
// ).expanded,
// IconButton(
// onPressed: () async {
// playerController.pausePlayer();
// },
// style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ),
// icon: const Icon(Icons.pause_circle_filled_outlined, size: 20),
// constraints: const BoxConstraints(),
// ),
// IconButton(
// onPressed: () {},
// style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ),
// icon: "delete".toSvgAsset(width: 24, height: 24),
// constraints: const BoxConstraints(),
// ),
// ],
// if (isAudioRecording && recorderController.isRecording)
// IconButton(
// onPressed: () {},
// style: const ButtonStyle(
// tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
// ),
// icon: "chat_msg_send".toSvgAsset(width: 24, height: 24),
// constraints: const BoxConstraints(),
// ),
// if (isAudioRecording)
// 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
// IconButton(
// onPressed: () async {
// await recorderController.checkPermission();
// if (recorderController.hasPermission) {
// setState(() {
// isAudioRecording = true;
// });
// recorderController.record();
// } 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(),
// ),
IconButton(
onPressed: () {},
style: const ButtonStyle(
tapTargetSize: MaterialTapTargetSize.shrinkWrap, // or .padded
IconButton(
onPressed: () {
chatProvider.sendTextMessage(textEditingController.text).then((success) {
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) {
@ -400,7 +470,7 @@ class _ChatPageState extends State<ChatPage> {
.center;
}
Widget senderMsgCard(bool showHeader, String msg) {
Widget senderMsgCard(bool showHeader, String msg, {bool loading = false}) {
Widget senderHeader = Row(
mainAxisSize: MainAxisSize.min,
children: [
@ -409,13 +479,13 @@ class _ChatPageState extends State<ChatPage> {
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: AppTextStyles.bodyText.copyWith(color: AppColor.neutral50, fontWeight: FontWeight.w600),
),
).toShimmer(context: context, isShow: loading),
8.width,
Container(
height: 26,
width: 26,
decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.grey),
),
).toShimmer(context: context, isShow: loading),
],
);
@ -440,11 +510,11 @@ class _ChatPageState extends State<ChatPage> {
Text(
msg,
style: AppTextStyles.bodyText2.copyWith(color: AppColor.neutral120),
),
).toShimmer(context: context, isShow: loading),
Text(
"2:00 PM",
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(
mainAxisSize: MainAxisSize.min,
children: [
@ -460,14 +530,14 @@ class _ChatPageState extends State<ChatPage> {
height: 26,
width: 26,
decoration: BoxDecoration(shape: BoxShape.circle, color: Colors.grey),
),
).toShimmer(context: context, isShow: loading),
8.width,
Text(
"Mahmoud Shrouf",
overflow: TextOverflow.ellipsis,
maxLines: 1,
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(
msg,
style: AppTextStyles.bodyText2.copyWith(color: AppColor.white10),
),
).toShimmer(context: context, isShow: loading),
Align(
alignment: Alignment.centerRight,
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(() {
Navigator.push(context, CupertinoPageRoute(builder: (context) => ChatPage()));
// Navigator.push(context, CupertinoPageRoute(builder: (context) => ChatPage()));
return;
}),
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';
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
_SurveyPageState createState() {
@ -29,6 +32,11 @@ class _SurveyPageState extends State<SurveyPage> {
@override
void initState() {
super.initState();
getSurveyQuestion();
}
void getSurveyQuestion(){
}
@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/material.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/widget_extensions.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/forget_password_module/forget_passwod_verify_otp.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 {
Navigator.push(context, MaterialPageRoute(builder: (context) => SurveyPage()));
return;
// Navigator.push(context, CupertinoPageRoute(builder: (context) => ChatPage(moduleId: 1, requestId: 1845972)));
// return;
if (!_formKey.currentState!.validate()) return;
if (privacyPolicyChecked == false) {

Loading…
Cancel
Save