2023-02-02 21:39:25 +09:00
import ' dart:async ' ;
2022-08-04 17:24:02 +08:00
import ' package:dash_chat_2/dash_chat_2.dart ' ;
2023-07-06 09:40:03 +08:00
import ' package:desktop_multi_window/desktop_multi_window.dart ' ;
2022-08-11 10:19:12 +08:00
import ' package:draggable_float_widget/draggable_float_widget.dart ' ;
2022-02-28 21:26:44 +08:00
import ' package:flutter/material.dart ' ;
2023-06-08 16:00:48 +02:00
import ' package:flutter/services.dart ' ;
2023-07-06 09:40:03 +08:00
import ' package:flutter_hbb/common/shared_state.dart ' ;
import ' package:flutter_hbb/desktop/widgets/tabbar_widget.dart ' ;
2023-07-10 09:40:41 +08:00
import ' package:flutter_hbb/mobile/pages/home_page.dart ' ;
2022-08-08 17:53:51 +08:00
import ' package:flutter_hbb/models/platform_model.dart ' ;
2023-07-06 09:40:03 +08:00
import ' package:flutter_hbb/models/state_model.dart ' ;
2023-02-06 20:10:39 +08:00
import ' package:get/get.dart ' ;
2023-07-10 16:02:47 +08:00
import ' package:uuid/uuid.dart ' ;
2022-08-22 20:12:58 +08:00
import ' package:window_manager/window_manager.dart ' ;
2023-05-29 09:46:16 +08:00
import ' package:flutter_svg/flutter_svg.dart ' ;
2022-03-03 14:58:57 +08:00
2022-11-08 11:07:20 +08:00
import ' ../consts.dart ' ;
2022-08-11 10:19:12 +08:00
import ' ../common.dart ' ;
2022-09-13 09:03:34 +08:00
import ' ../common/widgets/overlay.dart ' ;
2023-06-20 12:43:38 +08:00
import ' ../main.dart ' ;
2022-03-03 14:58:57 +08:00
import ' model.dart ' ;
2022-02-28 21:26:44 +08:00
2023-07-09 19:14:57 +08:00
class MessageKey {
final String peerId ;
final int connId ;
2023-07-10 21:03:35 +08:00
bool get isOut = > connId = = ChatModel . clientModeID ;
2023-07-09 19:14:57 +08:00
MessageKey ( this . peerId , this . connId ) ;
@ override
bool operator = = ( other ) {
return other is MessageKey & &
other . peerId = = peerId & &
other . isOut = = isOut ;
}
@ override
int get hashCode = > peerId . hashCode ^ isOut . hashCode ;
}
2022-05-16 00:01:27 +08:00
class MessageBody {
ChatUser chatUser ;
List < ChatMessage > chatMessages ;
MessageBody ( this . chatUser , this . chatMessages ) ;
2022-08-04 17:24:02 +08:00
void insert ( ChatMessage cm ) {
2022-10-26 23:50:36 +09:00
chatMessages . insert ( 0 , cm ) ;
2022-05-16 00:01:27 +08:00
}
void clear ( ) {
2022-10-26 23:50:36 +09:00
chatMessages . clear ( ) ;
2022-05-16 00:01:27 +08:00
}
}
2022-02-28 21:26:44 +08:00
class ChatModel with ChangeNotifier {
2022-03-22 16:40:23 +08:00
static final clientModeID = - 1 ;
2022-08-11 10:19:12 +08:00
OverlayEntry ? chatIconOverlayEntry ;
OverlayEntry ? chatWindowOverlayEntry ;
2023-02-06 20:10:39 +08:00
2022-11-04 21:43:51 +08:00
bool isConnManager = false ;
2022-08-11 10:19:12 +08:00
2023-02-06 09:54:21 +09:00
RxBool isWindowFocus = true . obs ;
2023-09-01 12:08:33 +05:30
BlockableOverlayState _blockableOverlayState = BlockableOverlayState ( ) ;
2023-02-06 20:10:39 +08:00
final Rx < VoiceCallStatus > _voiceCallStatus = Rx ( VoiceCallStatus . notStarted ) ;
Rx < VoiceCallStatus > get voiceCallStatus = > _voiceCallStatus ;
2023-02-06 09:54:21 +09:00
2023-06-08 16:00:48 +02:00
TextEditingController textController = TextEditingController ( ) ;
2023-07-10 09:40:41 +08:00
RxInt mobileUnreadSum = 0. obs ;
2023-07-10 21:58:27 +08:00
MessageKey ? latestReceivedKey ;
2023-06-08 16:00:48 +02:00
2023-09-04 01:45:48 +05:30
Offset chatWindowPosition = Offset ( 20 , 80 ) ;
2023-09-08 09:05:07 +08:00
void setChatWindowPosition ( Offset position ) {
2023-09-04 01:45:48 +05:30
chatWindowPosition = position ;
notifyListeners ( ) ;
}
2023-06-08 16:00:48 +02:00
@ override
void dispose ( ) {
textController . dispose ( ) ;
super . dispose ( ) ;
}
2022-03-03 14:58:57 +08:00
final ChatUser me = ChatUser (
2023-07-10 16:02:47 +08:00
id: Uuid ( ) . v4 ( ) . toString ( ) ,
2023-03-13 20:43:03 +01:00
firstName: translate ( " Me " ) ,
2022-03-03 14:58:57 +08:00
) ;
2023-07-09 19:14:57 +08:00
late final Map < MessageKey , MessageBody > _messages = { } ;
2022-05-16 00:01:27 +08:00
2023-07-10 16:02:47 +08:00
MessageKey _currentKey = MessageKey ( ' ' , - 2 ) ; // -2 is invalid value
2023-09-06 16:56:39 +08:00
late bool _isShowCMSidePage = false ;
2022-03-22 16:40:23 +08:00
2023-07-09 19:14:57 +08:00
Map < MessageKey , MessageBody > get messages = > _messages ;
2022-03-25 16:34:27 +08:00
2023-07-09 19:14:57 +08:00
MessageKey get currentKey = > _currentKey ;
2022-03-03 14:58:57 +08:00
2023-09-06 16:56:39 +08:00
bool get isShowCMSidePage = > _isShowCMSidePage ;
2022-08-22 20:12:58 +08:00
2023-02-08 22:01:15 +09:00
void setOverlayState ( BlockableOverlayState blockableOverlayState ) {
_blockableOverlayState = blockableOverlayState ;
2023-02-07 00:11:48 +09:00
2023-10-16 23:19:07 +08:00
_blockableOverlayState . addMiddleBlockedListener ( ( v ) {
2023-02-07 00:11:48 +09:00
if ( ! v ) {
isWindowFocus . value = false ;
if ( isWindowFocus . value ) {
isWindowFocus . toggle ( ) ;
}
}
} ) ;
}
2022-09-27 20:35:02 +08:00
final WeakReference < FFI > parent ;
2022-06-13 21:07:26 +08:00
2023-06-06 07:39:44 +08:00
late final SessionID sessionId ;
2023-06-08 16:00:48 +02:00
late FocusNode inputNode ;
2023-06-06 07:39:44 +08:00
ChatModel ( this . parent ) {
sessionId = parent . target ! . sessionId ;
2023-06-08 16:00:48 +02:00
inputNode = FocusNode (
2023-06-09 10:07:27 +02:00
onKey: ( _ , event ) {
2023-06-08 16:00:48 +02:00
bool isShiftPressed = event . isKeyPressed ( LogicalKeyboardKey . shiftLeft ) ;
bool isEnterPressed = event . isKeyPressed ( LogicalKeyboardKey . enter ) ;
2023-06-09 10:07:27 +02:00
// don't send empty messages
if ( isEnterPressed & & isEnterPressed & & textController . text . isEmpty ) {
return KeyEventResult . handled ;
2023-06-08 16:00:48 +02:00
}
if ( isEnterPressed & & ! isShiftPressed ) {
final ChatMessage message = ChatMessage (
2023-06-09 10:07:27 +02:00
text: textController . text ,
2023-06-08 16:00:48 +02:00
user: me ,
createdAt: DateTime . now ( ) ,
) ;
send ( message ) ;
2023-06-09 10:07:27 +02:00
textController . clear ( ) ;
return KeyEventResult . handled ;
2023-06-08 16:00:48 +02:00
}
return KeyEventResult . ignored ;
} ,
) ;
}
2022-10-26 23:50:36 +09:00
2023-07-09 19:14:57 +08:00
ChatUser ? get currentUser = > _messages [ _currentKey ] ? . chatUser ;
2022-04-04 14:54:00 +08:00
2022-08-11 10:19:12 +08:00
showChatIconOverlay ( { Offset offset = const Offset ( 200 , 50 ) } ) {
if ( chatIconOverlayEntry ! = null ) {
chatIconOverlayEntry ! . remove ( ) ;
}
// mobile check navigationBar
final bar = navigationBarKey . currentWidget ;
if ( bar ! = null ) {
if ( ( bar as BottomNavigationBar ) . currentIndex = = 1 ) {
return ;
}
}
2023-09-01 12:08:33 +05:30
final overlayState = _blockableOverlayState . state ;
2022-08-11 10:19:12 +08:00
if ( overlayState = = null ) return ;
final overlay = OverlayEntry ( builder: ( context ) {
return DraggableFloatWidget (
2023-05-20 15:12:52 +02:00
config: DraggableFloatWidgetBaseConfig (
initPositionYInTop: false ,
initPositionYMarginBorder: 100 ,
borderTopContainTopBar: true ,
) ,
child: FloatingActionButton (
onPressed: ( ) {
if ( chatWindowOverlayEntry = = null ) {
showChatWindowOverlay ( ) ;
} else {
hideChatWindowOverlay ( ) ;
}
} ,
backgroundColor: Theme . of ( context ) . colorScheme . primary ,
2023-05-24 14:18:42 +08:00
child: SvgPicture . asset ( ' assets/chat2.svg ' ) ,
2023-05-20 15:12:52 +02:00
) ,
) ;
2022-08-11 10:19:12 +08:00
} ) ;
overlayState . insert ( overlay ) ;
chatIconOverlayEntry = overlay ;
}
hideChatIconOverlay ( ) {
if ( chatIconOverlayEntry ! = null ) {
chatIconOverlayEntry ! . remove ( ) ;
chatIconOverlayEntry = null ;
}
}
2023-02-07 00:11:48 +09:00
showChatWindowOverlay ( { Offset ? chatInitPos } ) {
2022-08-11 10:19:12 +08:00
if ( chatWindowOverlayEntry ! = null ) return ;
2023-02-07 00:11:48 +09:00
isWindowFocus . value = true ;
2023-10-16 23:19:07 +08:00
_blockableOverlayState . setMiddleBlocked ( true ) ;
2023-02-07 00:11:48 +09:00
2023-10-16 23:19:07 +08:00
final overlayState = _blockableOverlayState . state ;
2022-08-11 10:19:12 +08:00
if ( overlayState = = null ) return ;
2023-07-10 21:58:27 +08:00
if ( isMobile & &
! gFFI . chatModel . currentKey . isOut & & // not in remote page
gFFI . chatModel . latestReceivedKey ! = null ) {
gFFI . chatModel . changeCurrentKey ( gFFI . chatModel . latestReceivedKey ! ) ;
gFFI . chatModel . mobileClearClientUnread ( gFFI . chatModel . currentKey . connId ) ;
}
2022-08-11 10:19:12 +08:00
final overlay = OverlayEntry ( builder: ( context ) {
2023-02-06 09:54:21 +09:00
return Listener (
onPointerDown: ( _ ) {
2023-02-07 00:11:48 +09:00
if ( ! isWindowFocus . value ) {
isWindowFocus . value = true ;
2023-10-16 23:19:07 +08:00
_blockableOverlayState . setMiddleBlocked ( true ) ;
2023-02-06 09:54:21 +09:00
}
} ,
2023-02-07 00:11:48 +09:00
child: DraggableChatWindow (
2023-09-04 01:45:48 +05:30
position: chatInitPos ? ? chatWindowPosition ,
2023-02-07 00:11:48 +09:00
width: 250 ,
height: 350 ,
chatModel: this ) ) ;
2022-08-11 10:19:12 +08:00
} ) ;
overlayState . insert ( overlay ) ;
chatWindowOverlayEntry = overlay ;
2023-02-02 21:39:25 +09:00
requestChatInputFocus ( ) ;
2022-08-11 10:19:12 +08:00
}
hideChatWindowOverlay ( ) {
if ( chatWindowOverlayEntry ! = null ) {
2023-10-16 23:19:07 +08:00
_blockableOverlayState . setMiddleBlocked ( false ) ;
2022-08-11 10:19:12 +08:00
chatWindowOverlayEntry ! . remove ( ) ;
chatWindowOverlayEntry = null ;
return ;
}
}
2022-11-04 21:43:51 +08:00
_isChatOverlayHide ( ) = > ( ( ! isDesktop & & chatIconOverlayEntry = = null ) | |
chatWindowOverlayEntry = = null ) ;
2023-02-07 00:11:48 +09:00
toggleChatOverlay ( { Offset ? chatInitPos } ) {
2022-11-04 21:43:51 +08:00
if ( _isChatOverlayHide ( ) ) {
2022-08-11 10:19:12 +08:00
gFFI . invokeMethod ( " enable_soft_keyboard " , true ) ;
2022-09-08 22:18:02 +08:00
if ( ! isDesktop ) {
showChatIconOverlay ( ) ;
}
2023-02-07 00:11:48 +09:00
showChatWindowOverlay ( chatInitPos: chatInitPos ) ;
2022-08-11 10:19:12 +08:00
} else {
hideChatIconOverlay ( ) ;
hideChatWindowOverlay ( ) ;
}
}
2023-05-29 09:46:16 +08:00
hideChatOverlay ( ) {
if ( ! _isChatOverlayHide ( ) ) {
hideChatIconOverlay ( ) ;
hideChatWindowOverlay ( ) ;
}
}
2023-07-09 19:14:57 +08:00
showChatPage ( MessageKey key ) async {
2023-07-08 16:08:23 +08:00
if ( isDesktop ) {
if ( isConnManager ) {
2023-09-06 16:56:39 +08:00
if ( ! _isShowCMSidePage ) {
2023-07-09 19:14:57 +08:00
await toggleCMChatPage ( key ) ;
2023-07-08 16:08:23 +08:00
}
} else {
if ( _isChatOverlayHide ( ) ) {
await toggleChatOverlay ( ) ;
}
2022-11-04 21:43:51 +08:00
}
} else {
2023-07-09 19:14:57 +08:00
if ( key . connId = = clientModeID ) {
2023-07-08 16:08:23 +08:00
if ( _isChatOverlayHide ( ) ) {
await toggleChatOverlay ( ) ;
}
2022-11-04 21:43:51 +08:00
}
}
}
2023-07-09 19:14:57 +08:00
toggleCMChatPage ( MessageKey key ) async {
if ( gFFI . chatModel . currentKey ! = key ) {
2023-07-10 16:02:47 +08:00
gFFI . chatModel . changeCurrentKey ( key ) ;
2022-08-22 20:12:58 +08:00
}
2023-09-06 16:56:39 +08:00
await toggleCMSidePage ( ) ;
}
2023-11-05 15:55:09 +08:00
toggleCMFilePage ( ) async {
await toggleCMSidePage ( ) ;
}
2023-09-29 15:09:58 +08:00
var _togglingCMSidePage = false ; // protect order for await
2023-09-06 16:56:39 +08:00
toggleCMSidePage ( ) async {
2023-09-29 15:09:58 +08:00
if ( _togglingCMSidePage ) return false ;
_togglingCMSidePage = true ;
2023-09-06 16:56:39 +08:00
if ( _isShowCMSidePage ) {
_isShowCMSidePage = ! _isShowCMSidePage ;
2023-07-10 17:59:04 +08:00
notifyListeners ( ) ;
2023-07-11 10:01:56 +08:00
await windowManager . show ( ) ;
await windowManager . setSizeAlignment (
kConnectionManagerWindowSizeClosedChat , Alignment . topRight ) ;
2022-08-22 20:12:58 +08:00
} else {
2023-11-05 15:55:09 +08:00
final currentSelectedTab =
gFFI . serverModel . tabController . state . value . selectedTabInfo ;
final client = parent . target ? . serverModel . clients . firstWhereOrNull (
( client ) = > client . id . toString ( ) = = currentSelectedTab . key ) ;
if ( client ! = null ) {
client . unreadChatMessageCount . value = 0 ;
}
2023-02-02 21:39:25 +09:00
requestChatInputFocus ( ) ;
2023-07-11 10:01:56 +08:00
await windowManager . show ( ) ;
2023-05-18 11:41:16 +02:00
await windowManager . setSizeAlignment (
kConnectionManagerWindowSizeOpenChat , Alignment . topRight ) ;
2023-09-06 16:56:39 +08:00
_isShowCMSidePage = ! _isShowCMSidePage ;
2022-08-22 20:12:58 +08:00
notifyListeners ( ) ;
}
2023-09-29 15:09:58 +08:00
_togglingCMSidePage = false ;
2022-08-22 20:12:58 +08:00
}
2023-07-10 16:02:47 +08:00
changeCurrentKey ( MessageKey key ) {
2023-07-09 19:14:57 +08:00
updateConnIdOfKey ( key ) ;
2023-07-10 16:02:47 +08:00
String ? peerName ;
if ( key . connId = = clientModeID ) {
peerName = parent . target ? . ffiModel . pi . username ;
2022-04-04 14:54:00 +08:00
} else {
2023-07-10 16:02:47 +08:00
peerName = parent . target ? . serverModel . clients
. firstWhereOrNull ( ( client ) = > client . peerId = = key . peerId )
? . name ;
}
if ( ! _messages . containsKey ( key ) ) {
2022-05-16 00:01:27 +08:00
final chatUser = ChatUser (
2023-07-09 19:14:57 +08:00
id: key . peerId ,
firstName: peerName ,
2022-05-16 00:01:27 +08:00
) ;
2023-07-09 19:14:57 +08:00
_messages [ key ] = MessageBody ( chatUser , [ ] ) ;
2023-07-10 16:02:47 +08:00
} else {
if ( peerName ! = null & & peerName . isNotEmpty ) {
_messages [ key ] ? . chatUser . firstName = peerName ;
}
2022-03-25 16:34:27 +08:00
}
2023-07-10 16:02:47 +08:00
_currentKey = key ;
notifyListeners ( ) ;
2023-07-10 09:40:41 +08:00
mobileClearClientUnread ( key . connId ) ;
2022-03-25 16:34:27 +08:00
}
2022-03-22 16:40:23 +08:00
2022-08-08 17:53:51 +08:00
receive ( int id , String text ) async {
2022-10-26 23:50:36 +09:00
final session = parent . target ;
if ( session = = null ) {
debugPrint ( " Failed to receive msg, session state is null " ) ;
return ;
}
2022-03-03 14:58:57 +08:00
if ( text . isEmpty ) return ;
2023-06-20 12:43:38 +08:00
if ( desktopType = = DesktopType . cm ) {
await showCmWindow ( ) ;
}
2023-07-09 19:14:57 +08:00
String ? peerId ;
if ( id = = clientModeID ) {
peerId = session . id ;
} else {
peerId = session . serverModel . clients
. firstWhereOrNull ( ( e ) = > e . id = = id )
? . peerId ;
}
if ( peerId = = null ) {
debugPrint ( " Failed to receive msg, peerId is null " ) ;
return ;
}
final messagekey = MessageKey ( peerId , id ) ;
2023-06-20 12:43:38 +08:00
2022-08-22 20:12:58 +08:00
// mobile: first message show overlay icon
2023-07-10 21:58:27 +08:00
if ( ! isDesktop & & chatIconOverlayEntry = = null ) {
2022-11-04 21:43:51 +08:00
showChatIconOverlay ( ) ;
2022-08-22 20:12:58 +08:00
}
2022-11-04 21:43:51 +08:00
// show chat page
2023-07-09 19:14:57 +08:00
await showChatPage ( messagekey ) ;
2022-10-26 23:50:36 +09:00
late final ChatUser chatUser ;
2022-04-05 00:51:47 +08:00
if ( id = = clientModeID ) {
2022-03-25 16:34:27 +08:00
chatUser = ChatUser (
2022-10-26 23:50:36 +09:00
firstName: session . ffiModel . pi . username ,
2023-07-09 19:14:57 +08:00
id: peerId ,
2022-03-25 16:34:27 +08:00
) ;
2023-07-06 09:40:03 +08:00
if ( isDesktop ) {
if ( Get . isRegistered < DesktopTabController > ( ) ) {
DesktopTabController tabController = Get . find < DesktopTabController > ( ) ;
var index = tabController . state . value . tabs
. indexWhere ( ( e ) = > e . key = = session . id ) ;
final notSelected =
index > = 0 & & tabController . state . value . selected ! = index ;
// minisized: top and switch tab
// not minisized: add count
if ( await WindowController . fromWindowId ( stateGlobal . windowId )
. isMinimized ( ) ) {
2023-08-02 20:38:09 +08:00
windowOnTop ( stateGlobal . windowId ) ;
2023-07-06 09:40:03 +08:00
if ( notSelected ) {
tabController . jumpTo ( index ) ;
}
} else {
if ( notSelected ) {
2023-07-09 19:14:57 +08:00
UnreadChatCountState . find ( peerId ) . value + = 1 ;
2023-07-06 09:40:03 +08:00
}
}
}
}
2022-04-05 00:51:47 +08:00
} else {
2023-07-09 19:14:57 +08:00
final client = session . serverModel . clients
. firstWhereOrNull ( ( client ) = > client . id = = id ) ;
if ( client = = null ) {
debugPrint ( " Failed to receive msg, client is null " ) ;
return ;
}
2022-09-01 21:18:53 +08:00
if ( isDesktop ) {
2023-08-02 20:38:09 +08:00
windowOnTop ( null ) ;
2022-10-26 23:50:36 +09:00
// disable auto jumpTo other tab when hasFocus, and mark unread message
final currentSelectedTab =
session . serverModel . tabController . state . value . selectedTabInfo ;
if ( currentSelectedTab . key ! = id . toString ( ) & & inputNode . hasFocus ) {
2023-07-05 17:01:33 +08:00
client . unreadChatMessageCount . value + = 1 ;
2022-10-26 23:50:36 +09:00
} else {
parent . target ? . serverModel . jumpTo ( id ) ;
2022-09-01 21:18:53 +08:00
}
2023-07-10 09:40:41 +08:00
} else {
2023-09-03 07:21:27 +08:00
if ( HomePage . homeKey . currentState ? . isChatPageCurrentTab ! = true | |
2023-07-10 16:02:47 +08:00
_currentKey ! = messagekey ) {
2023-07-10 09:40:41 +08:00
client . unreadChatMessageCount . value + = 1 ;
mobileUpdateUnreadSum ( ) ;
}
2022-09-01 21:18:53 +08:00
}
2022-08-04 17:24:02 +08:00
chatUser = ChatUser ( id: client . peerId , firstName: client . name ) ;
2022-03-25 16:34:27 +08:00
}
2023-07-10 09:40:41 +08:00
insertMessage ( messagekey ,
2022-08-04 17:24:02 +08:00
ChatMessage ( text: text , user: chatUser , createdAt: DateTime . now ( ) ) ) ;
2023-07-10 09:40:41 +08:00
if ( id = = clientModeID | | _currentKey . peerId . isEmpty ) {
2023-07-10 16:02:47 +08:00
// client or invalid
2023-07-10 09:40:41 +08:00
_currentKey = messagekey ;
mobileClearClientUnread ( messagekey . connId ) ;
}
2023-07-10 21:58:27 +08:00
latestReceivedKey = messagekey ;
2022-03-03 14:58:57 +08:00
notifyListeners ( ) ;
}
2022-03-22 16:40:23 +08:00
send ( ChatMessage message ) {
2023-06-09 10:07:27 +02:00
String trimmedText = message . text . trim ( ) ;
if ( trimmedText . isEmpty ) {
return ;
}
message . text = trimmedText ;
2023-07-09 19:14:57 +08:00
insertMessage ( _currentKey , message ) ;
if ( _currentKey . connId = = clientModeID & & parent . target ! = null ) {
2023-06-09 10:07:27 +02:00
bind . sessionSendChat ( sessionId: sessionId , text: message . text ) ;
} else {
2023-07-09 19:14:57 +08:00
bind . cmSendChat ( connId: _currentKey . connId , msg: message . text ) ;
2022-03-03 14:58:57 +08:00
}
2023-06-09 10:07:27 +02:00
2022-03-03 14:58:57 +08:00
notifyListeners ( ) ;
2023-06-08 16:00:48 +02:00
inputNode . requestFocus ( ) ;
2022-03-03 14:58:57 +08:00
}
2022-02-28 21:26:44 +08:00
2023-07-09 19:14:57 +08:00
insertMessage ( MessageKey key , ChatMessage message ) {
updateConnIdOfKey ( key ) ;
if ( ! _messages . containsKey ( key ) ) {
_messages [ key ] = MessageBody ( message . user , [ ] ) ;
}
_messages [ key ] ? . insert ( message ) ;
}
updateConnIdOfKey ( MessageKey key ) {
if ( _messages . keys
. toList ( )
. firstWhereOrNull ( ( e ) = > e = = key & & e . connId ! = key . connId ) ! =
null ) {
2023-07-10 16:02:47 +08:00
final value = _messages . remove ( key ) ;
if ( value ! = null ) {
_messages [ key ] = value ;
2023-07-09 19:14:57 +08:00
}
}
2023-07-10 16:02:47 +08:00
if ( _currentKey = = key | | _currentKey . peerId . isEmpty ) {
2023-07-10 09:40:41 +08:00
_currentKey = key ; // hash != assign
}
}
void mobileUpdateUnreadSum ( ) {
if ( ! isMobile ) return ;
var sum = 0 ;
parent . target ? . serverModel . clients
. map ( ( e ) = > sum + = e . unreadChatMessageCount . value )
. toList ( ) ;
Future . delayed ( Duration . zero , ( ) {
mobileUnreadSum . value = sum ;
} ) ;
}
void mobileClearClientUnread ( int id ) {
if ( ! isMobile ) return ;
final client = parent . target ? . serverModel . clients
. firstWhereOrNull ( ( client ) = > client . id = = id ) ;
if ( client ! = null ) {
Future . delayed ( Duration . zero , ( ) {
client . unreadChatMessageCount . value = 0 ;
mobileUpdateUnreadSum ( ) ;
} ) ;
}
2023-07-09 19:14:57 +08:00
}
2022-03-25 16:34:27 +08:00
close ( ) {
2022-03-03 14:58:57 +08:00
hideChatIconOverlay ( ) ;
hideChatWindowOverlay ( ) ;
notifyListeners ( ) ;
}
2022-05-16 00:01:27 +08:00
resetClientMode ( ) {
_messages [ clientModeID ] ? . clear ( ) ;
}
2023-02-02 21:39:25 +09:00
void requestChatInputFocus ( ) {
Timer ( Duration ( milliseconds: 100 ) , ( ) {
if ( inputNode . hasListeners & & inputNode . canRequestFocus ) {
inputNode . requestFocus ( ) ;
}
} ) ;
}
2023-02-08 22:29:51 +09:00
2023-02-06 20:10:39 +08:00
void onVoiceCallWaiting ( ) {
_voiceCallStatus . value = VoiceCallStatus . waitingForResponse ;
}
void onVoiceCallStarted ( ) {
_voiceCallStatus . value = VoiceCallStatus . connected ;
2024-05-14 09:20:27 +08:00
if ( isAndroid ) {
parent . target ? . invokeMethod ( " on_voice_call_started " ) ;
}
2023-02-06 20:10:39 +08:00
}
void onVoiceCallClosed ( String reason ) {
_voiceCallStatus . value = VoiceCallStatus . notStarted ;
2024-05-14 09:20:27 +08:00
if ( isAndroid ) {
2024-06-21 16:43:54 +08:00
// We can always invoke "on_voice_call_closed"
// no matter if the `_voiceCallStatus` was `VoiceCallStatus.notStarted` or not.
2024-05-14 09:20:27 +08:00
parent . target ? . invokeMethod ( " on_voice_call_closed " ) ;
}
2023-02-06 20:10:39 +08:00
}
void onVoiceCallIncoming ( ) {
if ( isConnManager ) {
_voiceCallStatus . value = VoiceCallStatus . incoming ;
}
}
2023-02-07 16:11:55 +08:00
2023-06-06 07:39:44 +08:00
void closeVoiceCall ( ) {
bind . sessionCloseVoiceCall ( sessionId: sessionId ) ;
2023-02-07 16:11:55 +08:00
}
2022-03-22 16:40:23 +08:00
}
2023-02-06 20:10:39 +08:00
enum VoiceCallStatus {
notStarted ,
waitingForResponse ,
connected ,
// Connection manager only.
incoming
2022-03-22 16:40:23 +08:00
}