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 host1 = "https://atomsm.hmg.com"; // production 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://atomsmdev.hmg.com"; // local DEV 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/v2/mobile"; // new V2 apis
static final String _baseUrl = "$_host/mobile"; // host local UAT
// 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/v4/mobile"; // v4 for Demo module
// static final String _baseUrl = "$_host/v5/mobile"; // v5 for data segregation
// 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 chatHubUrlChat = "$chatHubUrl/hubs/chat"; // new V2 apis

@ -1,7 +1,7 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:permission_handler/permission_handler.dart' as PermissionHandler;
import 'package:audio_waveforms/audio_waveforms.dart';
import 'package:cached_network_image/cached_network_image.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/common_widgets/app_filled_button.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 'helper/chat_audio_player.dart';
@ -206,66 +207,126 @@ class _ChatPageState extends State<ChatPage> {
appBar: DefaultAppBar(
title: widget.title,
actions: [
// NEW: Call readiness indicator - shows if device can receive calls
if (kDebugMode)
Selector<ChatProvider, bool>(
selector: (_, provider) => provider.areCallHandlersRegistered,
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,
),
Selector<ChatProvider, _ChatConnectionState>(
selector: (_, provider) => _ChatConnectionState(
isLoading: provider.chatLoginTokenLoading,
loginResponse: provider.chatLoginResponse,
),
),
),
),
Selector<ChatProvider, Participants?>(
selector: (_, provider) => provider.recipient,
builder: (context, recipient, _) => IconButton(
icon: "calling_icon".toSvgAsset(width: 24, height: 24),
onPressed: () {
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(),
),
builder: (context, connectionState, child) {
if (!connectionState.isLoading && connectionState.loginResponse == null) {
return SizedBox();
} else {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
if (kDebugMode)
Selector<ChatProvider, bool>(
selector: (_, provider) => provider.areCallHandlersRegistered,
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,
),
),
),
),
),
Selector<ChatProvider, Participants?>(
selector: (_, provider) => provider.recipient,
builder: (context, recipient, _) => IconButton(
icon: "calling_icon".toSvgAsset(width: 24, height: 24),
onPressed: () async{
bool audioPermission = await Provider.of<ChatProvider>(context, listen: false).checkAudioPermissions();
if (!audioPermission) {
context.showConfirmDialog("To perform audio call, we need permission to access microphone.", title: "Permission Required", onTap: () async {
Navigator.pop(context);
audioPermission = await Provider.of<ChatProvider>(context, listen: false).requestAudioPermissions();
if (!audioPermission) {
bool openSetting = await showDialog(
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)

@ -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 {
// OPTIMIZATION: Use async reset for proper cleanup
await reset();

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

Loading…
Cancel
Save