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,7 +207,18 @@ 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>(
selector: (_, provider) => _ChatConnectionState(
isLoading: provider.chatLoginTokenLoading,
loginResponse: provider.chatLoginResponse,
),
builder: (context, connectionState, child) {
if (!connectionState.isLoading && connectionState.loginResponse == null) {
return SizedBox();
} else {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
if (kDebugMode) if (kDebugMode)
Selector<ChatProvider, bool>( Selector<ChatProvider, bool>(
selector: (_, provider) => provider.areCallHandlersRegistered, selector: (_, provider) => provider.areCallHandlersRegistered,
@ -228,8 +240,25 @@ class _ChatPageState extends State<ChatPage> {
selector: (_, provider) => provider.recipient, selector: (_, provider) => provider.recipient,
builder: (context, recipient, _) => IconButton( builder: (context, recipient, _) => IconButton(
icon: "calling_icon".toSvgAsset(width: 24, height: 24), icon: "calling_icon".toSvgAsset(width: 24, height: 24),
onPressed: () { onPressed: () async{
log('recipient: ${recipient?.userName}'); 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) { if (recipient != null) {
chatProvider.startCall(recipient, CallType.audio); chatProvider.startCall(recipient, CallType.audio);
Navigator.push( Navigator.push(
@ -239,7 +268,35 @@ class _ChatPageState extends State<ChatPage> {
), ),
); );
} }
}
});
} 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, padding: EdgeInsets.zero,
constraints: const BoxConstraints(), constraints: const BoxConstraints(),
), ),
@ -267,6 +324,10 @@ class _ChatPageState extends State<ChatPage> {
), ),
), ),
], ],
);
}
}),
],
), ),
// OPTIMIZATION: Using Selector for connection state (rarely changes) // OPTIMIZATION: Using Selector for connection state (rarely changes)
// This prevents rebuilding entire chat UI on every message/typing event // This prevents rebuilding entire chat UI on every message/typing event

@ -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,8 +9,10 @@ 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) {
@ -21,14 +23,14 @@ class AAlertDialog extends StatelessWidget {
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);
}, },
@ -37,20 +39,21 @@ class AAlertDialog extends StatelessWidget {
) )
: AlertDialog( : AlertDialog(
backgroundColor: AppColor.background(context), backgroundColor: AppColor.background(context),
actionsPadding: const EdgeInsets.only(bottom: 12, left: 24, right: 24),
title: title != null ? Text(title!) : null, title: title != null ? Text(title!) : null,
content: content != null ? Text(content!) : null, content: content != null ? Text(content!) : null,
// contentTextStyle: AppTextStyles.bodyText.copyWith(color: (context.isDark ? AppColor.neutral30 : AppColor.neutral50)), // contentTextStyle: AppTextStyles.bodyText.copyWith(color: (context.isDark ? AppColor.neutral30 : AppColor.neutral50)),
actions: <Widget>[ actions: <Widget>[
TextButton( TextButton(
// child: Text(_subtitle.confirm), // child: Text(_subtitle.confirm),
child: Text(context.translation.confirm, style: AppTextStyles.bodyText.copyWith(color: AppColor.loadingColor(context))), child: Text(button1Text ?? context.translation.confirm, style: AppTextStyles.bodyText.copyWith(color: AppColor.loadingColor(context))),
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, style: AppTextStyles.bodyText.copyWith(color: AppColor.loadingColor(context))), child: Text(button2Text ?? context.translation.cancel, style: AppTextStyles.bodyText.copyWith(color: AppColor.loadingColor(context))),
onPressed: () { onPressed: () {
Navigator.of(context).pop(false); Navigator.of(context).pop(false);
}, },

Loading…
Cancel
Save