structure improvements.

ui_ux_rollout_merge_audio_video_call
Sikander Saleem 1 week ago
parent 11c6e2411e
commit b212be19c6

@ -4,17 +4,18 @@ class URLs {
static const String appReleaseBuildNumber = "44"; static const String appReleaseBuildNumber = "44";
// static const host1 = "https://atomsm.hmg.com"; // production url // static const host1 = "https://atomsm.hmg.com"; // production url
// static const host1 = "https://atomsmdev.hmg.com"; // local DEV url static const host1 = "https://atomsmdev.hmg.com"; // local DEV url
static const host1 = "https://atomsmuat.hmg.com"; // local UAT url // static const host1 = "https://atomsmuat.hmg.com"; // local UAT url
// static final String _baseUrl = "$_host/mobile"; // host local UAT static final String _baseUrl = "$_host/mobile"; // host local UAT
static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis // static final String _baseUrl = "$_host/v2/mobile"; // new V2 apis
// 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/v4/mobile"; // v4 for Demo module // static final String _baseUrl = "$_host/v4/mobile"; // v4 for Demo module
// static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation // static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation
// static final String _baseUrl = "$_host/v6/mobile"; // for asset delivery module // static final String _baseUrl = "$_host/v6/mobile"; // for asset delivery module
static const String chatHubUrl = "https://apiderichat.hmg.com/chathub"; // static const String chatHubUrl = "https://apiderichat.hmg.com/chathub";
static const String chatHubUrl = "$host1/api/DeriChat";
static const String chatHubUrlApi = "$chatHubUrl/api"; // new V2 apis static const String chatHubUrlApi = "$chatHubUrl/api"; // new V2 apis
static const String chatHubUrlChat = "$chatHubUrl/hubs/chat"; // new V2 apis static const String chatHubUrlChat = "$chatHubUrl/hubs/chat"; // new V2 apis

@ -1,7 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:developer'; import 'dart:developer';
import 'dart:io'; import 'dart:io';
import 'package:permission_handler/permission_handler.dart' as PermissionHandler;
import 'package:audio_waveforms/audio_waveforms.dart'; import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
@ -26,6 +26,7 @@ import 'package:test_sa/modules/cx_module/chat/view_all_attachment_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/app_filled_button.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';
import 'package:test_sa/views/widgets/dialogs/dialog.dart';
import 'package:test_sa/views/widgets/sound/sound_player.dart'; import 'package:test_sa/views/widgets/sound/sound_player.dart';
import 'helper/chat_audio_player.dart'; import 'helper/chat_audio_player.dart';
@ -206,66 +207,126 @@ class _ChatPageState extends State<ChatPage> {
appBar: DefaultAppBar( appBar: DefaultAppBar(
title: widget.title, title: widget.title,
actions: [ actions: [
// NEW: Call readiness indicator - shows if device can receive calls Selector<ChatProvider, _ChatConnectionState>(
if (kDebugMode) selector: (_, provider) => _ChatConnectionState(
Selector<ChatProvider, bool>( isLoading: provider.chatLoginTokenLoading,
selector: (_, provider) => provider.areCallHandlersRegistered, loginResponse: provider.chatLoginResponse,
builder: (context, handlersRegistered, _) => Padding(
padding: const EdgeInsets.only(right: 8),
child: Center(
child: Container(
width: 8,
height: 8,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: handlersRegistered ? Colors.green : Colors.red,
),
), ),
), builder: (context, connectionState, child) {
), if (!connectionState.isLoading && connectionState.loginResponse == null) {
), return SizedBox();
Selector<ChatProvider, Participants?>( } else {
selector: (_, provider) => provider.recipient, return Row(
builder: (context, recipient, _) => IconButton( mainAxisSize: MainAxisSize.min,
icon: "calling_icon".toSvgAsset(width: 24, height: 24), children: [
onPressed: () { if (kDebugMode)
log('recipient: ${recipient?.userName}'); Selector<ChatProvider, bool>(
if (recipient != null) { selector: (_, provider) => provider.areCallHandlersRegistered,
chatProvider.startCall(recipient, CallType.audio); builder: (context, handlersRegistered, _) => Padding(
Navigator.push( padding: const EdgeInsets.only(right: 8),
context, child: Center(
MaterialPageRoute( child: Container(
builder: (context) => const AudioCallPage(), width: 8,
), height: 8,
); decoration: BoxDecoration(
} shape: BoxShape.circle,
}, color: handlersRegistered ? Colors.green : Colors.red,
padding: EdgeInsets.zero, ),
constraints: const BoxConstraints(), ),
), ),
), ),
Selector<ChatProvider, Participants?>( ),
selector: (_, provider) => provider.recipient, Selector<ChatProvider, Participants?>(
builder: (context, recipient, _) => IconButton( selector: (_, provider) => provider.recipient,
icon: "video_call_icon".toSvgAsset( builder: (context, recipient, _) => IconButton(
width: 24, icon: "calling_icon".toSvgAsset(width: 24, height: 24),
height: 24, onPressed: () async{
), bool audioPermission = await Provider.of<ChatProvider>(context, listen: false).checkAudioPermissions();
onPressed: () { if (!audioPermission) {
if (recipient != null) { context.showConfirmDialog("To perform audio call, we need permission to access microphone.", title: "Permission Required", onTap: () async {
chatProvider.startCall(recipient, CallType.video); Navigator.pop(context);
Navigator.push( audioPermission = await Provider.of<ChatProvider>(context, listen: false).requestAudioPermissions();
context, if (!audioPermission) {
MaterialPageRoute( bool openSetting = await showDialog(
builder: (context) => const VideoCallPage(), context: context,
), builder: (_) => const AAlertDialog(
title: "Permission denied",
content: "Permission is denied. Please go to application Setting to enable it.",
button1Text: "Cancel",
button2Text: "Open Setting",
),
);
if (!openSetting) PermissionHandler.openAppSettings();
return;
} else {
if (recipient != null) {
chatProvider.startCall(recipient, CallType.audio);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const AudioCallPage(),
),
);
}
}
});
} else {
if (recipient != null) {
chatProvider.startCall(recipient, CallType.audio);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const AudioCallPage(),
),
);
}
}
},
// {
// log('recipient: ${recipient?.userName}');
//
//
// if (recipient != null) {
// chatProvider.startCall(recipient, CallType.audio);
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (context) => const AudioCallPage(),
// ),
// );
// }
// },
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
),
),
Selector<ChatProvider, Participants?>(
selector: (_, provider) => provider.recipient,
builder: (context, recipient, _) => IconButton(
icon: "video_call_icon".toSvgAsset(
width: 24,
height: 24,
),
onPressed: () {
if (recipient != null) {
chatProvider.startCall(recipient, CallType.video);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const VideoCallPage(),
),
);
}
},
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
),
),
],
); );
} }
}, }),
padding: EdgeInsets.zero,
constraints: const BoxConstraints(),
),
),
], ],
), ),
// OPTIMIZATION: Using Selector for connection state (rarely changes) // OPTIMIZATION: Using Selector for connection state (rarely changes)

@ -199,6 +199,21 @@ class ChatProvider with ChangeNotifier, DiagnosticableTreeMixin {
// } // }
// } // }
Future<bool> checkAudioPermissions() => Permission.microphone.isGranted;
Future<bool> checkVideoPermissions() async => (await Permission.microphone.isGranted) && (await Permission.camera.isGranted);
Future<bool> requestAudioPermissions() async {
var result = await [Permission.microphone].request();
return (result[Permission.microphone] == PermissionStatus.granted);
}
Future<bool> requestVideoPermissions() async {
var result = await [Permission.microphone, Permission.camera].request();
return (result[Permission.microphone] == PermissionStatus.granted) && (result[Permission.camera] == PermissionStatus.granted);
}
Future<void> getUserAutoLoginTokenSilent(int moduleId, int requestId, String title, String myId, String assigneeEmployeeNumber, {bool isMounted = true}) async { Future<void> getUserAutoLoginTokenSilent(int moduleId, int requestId, String title, String myId, String assigneeEmployeeNumber, {bool isMounted = true}) async {
// OPTIMIZATION: Use async reset for proper cleanup // OPTIMIZATION: Use async reset for proper cleanup
await reset(); await reset();

@ -9,53 +9,56 @@ import 'package:test_sa/new_views/app_style/app_color.dart';
class AAlertDialog extends StatelessWidget { class AAlertDialog extends StatelessWidget {
final String? title; final String? title;
final String? content; final String? content;
final String? button1Text;
final String? button2Text;
const AAlertDialog({Key? key, this.title, this.content}) : super(key: key); const AAlertDialog({Key? key, this.title, this.content, this.button1Text, this.button2Text}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Platform.isIOS return Platform.isIOS
? CupertinoAlertDialog( ? CupertinoAlertDialog(
title: title != null ? Text(title!) : null, title: title != null ? Text(title!) : null,
content: content != null ? Text(content!) : null, content: content != null ? Text(content!) : null,
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(
// child: Text(_subtitle.confirm), // child: Text(_subtitle.confirm),
child: Text(context.translation.confirm), child: Text(button1Text ?? context.translation.confirm),
onPressed: () { onPressed: () {
Navigator.of(context).pop(true); Navigator.of(context).pop(true);
}, },
), ),
TextButton( TextButton(
// child: Text(_subtitle.cancel), // child: Text(_subtitle.cancel),
child: Text(context.translation.cancel), child: Text(button2Text ?? context.translation.cancel),
onPressed: () { onPressed: () {
Navigator.of(context).pop(false); Navigator.of(context).pop(false);
}, },
), ),
], ],
) )
: AlertDialog( : AlertDialog(
backgroundColor: AppColor.background(context), backgroundColor: AppColor.background(context),
title: title != null ? Text(title!) : null, actionsPadding: const EdgeInsets.only(bottom: 12, left: 24, right: 24),
content: content != null ? Text(content!) : null, title: title != null ? Text(title!) : null,
// contentTextStyle: AppTextStyles.bodyText.copyWith(color: (context.isDark ? AppColor.neutral30 : AppColor.neutral50)), content: content != null ? Text(content!) : null,
actions: <Widget>[ // contentTextStyle: AppTextStyles.bodyText.copyWith(color: (context.isDark ? AppColor.neutral30 : AppColor.neutral50)),
TextButton( actions: <Widget>[
// child: Text(_subtitle.confirm), TextButton(
child: Text(context.translation.confirm, style: AppTextStyles.bodyText.copyWith(color: AppColor.loadingColor(context))), // child: Text(_subtitle.confirm),
onPressed: () { child: Text(button1Text ?? context.translation.confirm, style: AppTextStyles.bodyText.copyWith(color: AppColor.loadingColor(context))),
Navigator.of(context).pop(true); onPressed: () {
}, Navigator.of(context).pop(true);
), },
TextButton( ),
// child: Text(_subtitle.cancel), TextButton(
child: Text(context.translation.cancel, style: AppTextStyles.bodyText.copyWith(color: AppColor.loadingColor(context))), // child: Text(_subtitle.cancel),
onPressed: () { child: Text(button2Text ?? context.translation.cancel, style: AppTextStyles.bodyText.copyWith(color: AppColor.loadingColor(context))),
Navigator.of(context).pop(false); onPressed: () {
}, Navigator.of(context).pop(false);
), },
], ),
); ],
);
} }
} }

Loading…
Cancel
Save