diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index 1cf1205..b4cf456 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -520,5 +520,6 @@ "noUpcoming": "لا يوجد قادم", "fakeLocation": ".لقد تتبعنا أنك تحاول استخدام موقع مزيف! يعتبر هذا مخالفة وقد تم إخطار الموارد البشرية", "noWinner": "حزين! لم يفز أحد اليوم.", + "myTeam" : "فريقي" "youCanPlayDemo": "لكن يمكنك لعب العرض" } \ No newline at end of file diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index e836721..3d37c1b 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -520,5 +520,6 @@ "noUpcoming": "There is no upcoming", "fakeLocation": "We traced out that you try to use a fake location! This is considered a violation, and HR has been notified.", "noWinner": "Sad! No one won today.", + "myTeam" : "My Team" "youCanPlayDemo": "But you can play demo" } \ No newline at end of file diff --git a/lib/generated/locale_keys.g.dart b/lib/generated/locale_keys.g.dart index e4a3bca..aa61124 100644 --- a/lib/generated/locale_keys.g.dart +++ b/lib/generated/locale_keys.g.dart @@ -507,5 +507,6 @@ abstract class LocaleKeys { static const fakeLocation = 'fakeLocation'; static const noWinner = 'noWinner'; static const youCanPlayDemo = 'youCanPlayDemo'; + static const myTeam = 'myTeam'; } diff --git a/lib/provider/chat_provider_model.dart b/lib/provider/chat_provider_model.dart index 0851392..460a338 100644 --- a/lib/provider/chat_provider_model.dart +++ b/lib/provider/chat_provider_model.dart @@ -119,16 +119,8 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { } void getUserRecentChats() async { - if (chatHubConnection.state != HubConnectionState.Connected) { - getUserAutoLoginToken().whenComplete(() async { - await buildHubConnection(); - getUserRecentChats(); - }); - return; - } ChatUserModel recentChat = await ChatApiClient().getRecentChats(); ChatUserModel favUList = await ChatApiClient().getFavUsers(); - if (favUList.response != null && recentChat.response != null) { favUsersList = favUList.response!; favUsersList.sort( @@ -1208,19 +1200,42 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { playerController.dispose(); } - void startRecoding() async { - PermissionStatus status = await Permission.microphone.request(); - if (status.isDenied == true) { - startRecoding(); - } else { - isVoiceMsg = true; - recorderController.reset(); - await recorderController.record(path); - _recodeDuration = 0; - _startTimer(); - isRecoding = !isRecoding; - notifyListeners(); - } + void startRecoding(BuildContext context) async { + await Permission.microphone.request().then((PermissionStatus status) { + if (status.isPermanentlyDenied) { + Utils.confirmDialog( + context, + "The app needs microphone access to be able to record audio.", + onTap: () { + Navigator.of(context).pop(); + openAppSettings(); + }, + ); + } else if (status.isDenied) { + Utils.confirmDialog( + context, + "The app needs microphone access to be able to record audio.", + onTap: () { + Navigator.of(context).pop(); + openAppSettings(); + }, + ); + } else if (status.isGranted) { + sRecoding(); + } else { + startRecoding(context); + } + }); + } + + void sRecoding() async { + isVoiceMsg = true; + recorderController.reset(); + await recorderController.record(path); + _recodeDuration = 0; + _startTimer(); + isRecoding = !isRecoding; + notifyListeners(); } Future _startTimer() async { @@ -1295,15 +1310,23 @@ class ChatProviderModel with ChangeNotifier, DiagnosticableTreeMixin { return numberStr; } - Future downChatVoice(Uint8List bytes, String ext, SingleUserChatModel data) async { - String dirPath = '${(await getApplicationDocumentsDirectory()).path}/chat_audios'; - if (!await Directory(dirPath).exists()) { - await Directory(dirPath).create(); - await File('$dirPath/.nomedia').create(); + Future downChatVoice(Uint8List bytes, String ext, SingleUserChatModel data) async { + File file; + try { + String dirPath = '${(await getApplicationDocumentsDirectory()).path}/chat_audios'; + if (!await Directory(dirPath).exists()) { + await Directory(dirPath).create(); + await File('$dirPath/.nomedia').create(); + } + file = File("$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}" + ext); + await file.writeAsBytes(bytes); + } catch (e) { + if (kDebugMode) { + print(e); + } + file = File(""); } - File file = File("$dirPath/${data.currentUserId}-${data.targetUserId}-${DateTime.now().microsecondsSinceEpoch}." + ext); - await file.writeAsBytes(bytes); - return file.path; + return file; } void scrollToMsg(SingleUserChatModel data) { diff --git a/lib/provider/dashboard_provider_model.dart b/lib/provider/dashboard_provider_model.dart index c851570..aa9a38f 100644 --- a/lib/provider/dashboard_provider_model.dart +++ b/lib/provider/dashboard_provider_model.dart @@ -244,7 +244,7 @@ class DashboardProviderModel with ChangeNotifier, DiagnosticableTreeMixin { void getCategoryOffersListAPI(BuildContext context) async { try { // Utils.showLoading(context); - getOffersList = await OffersAndDiscountsApiClient().getOffersList(0, 6); + getOffersList = await OffersAndDiscountsApiClient().getOffersList(0, 10); isOffersLoading = false; notifyListeners(); } catch (ex) { diff --git a/lib/ui/chat/chat_bubble.dart b/lib/ui/chat/chat_bubble.dart index 93fea00..6d1e2eb 100644 --- a/lib/ui/chat/chat_bubble.dart +++ b/lib/ui/chat/chat_bubble.dart @@ -12,6 +12,7 @@ import 'package:mohem_flutter_app/classes/utils.dart'; import 'package:mohem_flutter_app/extensions/int_extensions.dart'; import 'package:mohem_flutter_app/extensions/string_extensions.dart'; import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/main.dart'; import 'package:mohem_flutter_app/models/chat/get_single_user_chat_list_model.dart'; import 'package:mohem_flutter_app/provider/chat_provider_model.dart'; import 'package:mohem_flutter_app/ui/chat/chat_full_image_preview.dart'; @@ -56,35 +57,70 @@ class ChatBubble extends StatelessWidget { userName = AppState().chatDetails!.response!.userName == cItem.currentUserName.toString() ? "You" : cItem.currentUserName.toString(); } + Future getCurrentUrl(String url)async{ + if(Platform.isIOS){ + String a = url.substring(url.indexOf("Documents/") + 10, url.length) ; + Directory dir = await getApplicationDocumentsDirectory(); + a = "${dir.path}/$a"; + return a; + } + else{ + return url; + } + } + void playVoice( BuildContext context, { required SingleUserChatModel data, }) async { if (data.voice != null && data.voice!.existsSync()) { - await data.voiceController!.setFilePath(data!.voice!.path); - await data.voiceController!.setLoopMode(LoopMode.off); - Duration? duration = await data.voiceController!.load(); - await data.voiceController!.seek(duration); - await data.voiceController!.play(); - } else { - Utils.showLoading(context); - Uint8List encodedString = await ChatApiClient().downloadURL(fileName: data.contant!, fileTypeDescription: provider.getFileTypeDescription(data.fileTypeResponse!.fileTypeName ?? "")); - try { - String path = await provider.downChatVoice(encodedString, data.fileTypeResponse!.fileTypeName ?? "", data); - File file = File(path!); - await file.readAsBytes(); - data.voice = file; - Duration? duration = await data.voiceController!.setFilePath(file.path); - await data.voiceController!.setLoopMode(LoopMode.off); + if (Platform.isIOS) { + Duration? duration = await data.voiceController!.setAudioSource(MyCustomStream(data.voice!.readAsBytesSync())); await data.voiceController!.seek(duration); + await data.voiceController!.setLoopMode(LoopMode.off); await data.voiceController!.setVolume(1.0); await data.voiceController!.load(); - Utils.hideLoading(context); + data.voiceController!.play(); + } else { + await data.voiceController!.setFilePath(data!.voice!.path); + Duration? duration = await data.voiceController!.load(); + await data.voiceController!.seek(duration); + await data.voiceController!.setLoopMode(LoopMode.off); await data.voiceController!.play(); - } catch (e) { - Utils.hideLoading(context); - Utils.showToast(e.toString()); } + } else { + Utils.showLoading(context); + Uint8List encodedString = await ChatApiClient().downloadURL(fileName: data.contant!, fileTypeDescription: provider.getFileTypeDescription(data.fileTypeResponse!.fileTypeName ?? "")); + // try { + File sFile = await provider.downChatVoice(encodedString, data.fileTypeResponse!.fileTypeName ?? "", data); + if(sFile.path.isEmpty){ + logger.d("Path Is Emptyyyyyyy"); + }else{ + logger.d("Path Exsists"); + } + data.voice = sFile; + if (Platform.isIOS) { + logger.d("isIOS"); + Duration? duration = await data.voiceController!.setAudioSource(MyCustomStream(data.voice!.readAsBytesSync())); + await data.voiceController!.seek(duration); + await data.voiceController!.setLoopMode(LoopMode.off); + await data.voiceController!.setVolume(1.0); + await data.voiceController!.load(); + Utils.hideLoading(context); + data.voiceController!.play(); + } else { + Duration? duration = await data.voiceController!.setFilePath(sFile.path); + await data.voiceController!.setLoopMode(LoopMode.off); + await data.voiceController!.seek(duration); + + Utils.hideLoading(context); + await data.voiceController!.play(); + } + + // } catch (e) { + // Utils.hideLoading(context); + // Utils.showToast(e.toString()); + // } } } @@ -439,3 +475,23 @@ class ChatBubble extends StatelessWidget { ); } } + +// Feed your own stream of bytes into the player +class MyCustomStream extends StreamAudioSource { + final Uint8List bytes; + + MyCustomStream(this.bytes); + + @override + Future request([int? start, int? end]) async { + start ??= 0; + end ??= bytes.length; + return StreamAudioResponse( + sourceLength: bytes.length, + contentLength: end - start, + offset: start, + stream: Stream.value(bytes.sublist(start, end)), + contentType: 'audio/aac', + ); + } +} diff --git a/lib/ui/chat/chat_detailed_screen.dart b/lib/ui/chat/chat_detailed_screen.dart index 595dc13..3e02d96 100644 --- a/lib/ui/chat/chat_detailed_screen.dart +++ b/lib/ui/chat/chat_detailed_screen.dart @@ -275,7 +275,6 @@ class _ChatDetailScreenState extends State { : null, ), onChanged: (String val) { - print(val.length); if (val.isNotEmpty) { m.isTextMsg = true; } else { @@ -302,7 +301,7 @@ class _ChatDetailScreenState extends State { Icons.mic, color: MyColors.lightGreenColor, ).paddingOnly(right: 15).onPress(() { - m.startRecoding(); + m.startRecoding(context); }), SvgPicture.asset("assets/icons/chat/chat_send_icon.svg", height: 26, width: 26) .onPress( diff --git a/lib/ui/chat/chat_home.dart b/lib/ui/chat/chat_home.dart index 49908dd..bbb3048 100644 --- a/lib/ui/chat/chat_home.dart +++ b/lib/ui/chat/chat_home.dart @@ -83,7 +83,7 @@ class _ChatHomeState extends State { children: [ myTab(LocaleKeys.mychats.tr(), 0), myTab(LocaleKeys.favorite.tr(), 1), - AppState().getempStatusIsManager ? myTab("My Team", 2) : const SizedBox(), + AppState().getempStatusIsManager ? myTab(LocaleKeys.myTeam.tr(), 2) : const SizedBox(), ], ), ), diff --git a/lib/ui/chat/my_team_screen.dart b/lib/ui/chat/my_team_screen.dart index 5d36a68..79da90d 100644 --- a/lib/ui/chat/my_team_screen.dart +++ b/lib/ui/chat/my_team_screen.dart @@ -101,7 +101,7 @@ class _MyTeamScreenState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - (m.teamMembersList![index].userName!.replaceFirst(".", " ").capitalizeFirstofEach ?? "").toText14(color: MyColors.darkTextColor).paddingOnly(left: 11, top: 13), + (m.teamMembersList[index].userName! ?? "").toText14(color: MyColors.darkTextColor).paddingOnly(left: 11, top: 13), ], ).expanded, // SizedBox( diff --git a/lib/ui/landing/dashboard_screen.dart b/lib/ui/landing/dashboard_screen.dart index 6c782fc..98bf976 100644 --- a/lib/ui/landing/dashboard_screen.dart +++ b/lib/ui/landing/dashboard_screen.dart @@ -415,7 +415,7 @@ class _DashboardScreenState extends State { ); }, separatorBuilder: (BuildContext cxt, int index) => 8.width, - itemCount: 6), + itemCount: 9), ); }, ), @@ -463,7 +463,7 @@ class _DashboardScreenState extends State { "assets/icons/create_req.svg", color: currentIndex == 1 ? MyColors.grey3AColor : MyColors.grey98Color, ).paddingAll(4), - label: LocaleKeys.createRequest.tr(), + label: LocaleKeys.mowadhafhiRequest.tr(), ), BottomNavigationBarItem( icon: Stack( diff --git a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart index d06bfdc..b20674e 100644 --- a/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart +++ b/lib/widgets/bottom_sheets/search_employee_bottom_sheet.dart @@ -136,7 +136,6 @@ class _SearchEmployeeBottomSheetState extends State { @override void dispose() { - print("// TODO: implement dispose"); super.dispose(); provider.chatUsersList = []; provider.pageNo = 1; diff --git a/lib/widgets/chat_app_bar_widge.dart b/lib/widgets/chat_app_bar_widge.dart index 790840c..25ed34c 100644 --- a/lib/widgets/chat_app_bar_widge.dart +++ b/lib/widgets/chat_app_bar_widge.dart @@ -76,7 +76,7 @@ AppBar ChatAppBarWidget(BuildContext context, if (chatUser!.isTyping!) ("Typing ...").toText10(color: MyColors.textMixColor) else const SizedBox(), ], ), - ) + ).expanded ], ); }), diff --git a/lib/widgets/image_picker.dart b/lib/widgets/image_picker.dart index 75466fc..834695b 100644 --- a/lib/widgets/image_picker.dart +++ b/lib/widgets/image_picker.dart @@ -20,7 +20,7 @@ class ImageOptions { if (Platform.isAndroid) { cameraImageAndroid(image); } else { - File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 10))?.path ?? ""); + File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? ""); String fileName = _image.path; var bytes = File(fileName).readAsBytesSync(); String base64Encode = base64.encode(bytes); @@ -33,7 +33,7 @@ class ImageOptions { if (Platform.isAndroid) { galleryImageAndroid(image); } else { - File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 10))?.path ?? ""); + File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 20))?.path ?? ""); String fileName = _image.path; var bytes = File(fileName).readAsBytesSync(); String base64Encode = base64.encode(bytes); @@ -114,7 +114,7 @@ class ImageOptions { } void galleryImageAndroid(Function(String, File) image) async { - File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 10))?.path ?? ""); + File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.gallery, imageQuality: 20))?.path ?? ""); String fileName = _image.path; var bytes = File(fileName).readAsBytesSync(); String base64Encode = base64.encode(bytes); @@ -124,7 +124,7 @@ void galleryImageAndroid(Function(String, File) image) async { } void cameraImageAndroid(Function(String, File) image) async { - File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 10))?.path ?? ""); + File _image = File((await ImagePicker.platform.pickImage(source: ImageSource.camera, imageQuality: 20))?.path ?? ""); String fileName = _image.path; var bytes = File(fileName).readAsBytesSync(); String base64Encode = base64.encode(bytes); diff --git a/pubspec.yaml b/pubspec.yaml index 95f6b3e..3167dcd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 3.1.5+300015 +version: 3.6.0+300060 environment: sdk: ">=2.16.0 <3.0.0"