聊天對話單元
主要參考檔案: ValoChat
我們能觀察到以下區段,了解個別資料做什麼職責,其他幾乎是 UI 上的細節:
- ValoChat
ComposerProvider: 對話的底部的共用資料。- ex: 媒體面板、目前輸入訊息文字、訊息檔案、回覆訊息...等
- ValoChat
SearchProvider: 針對對話搜尋,集中的共用資料。- ex: 是否已切換
搜尋模式、目前輸入搜尋文字、搜尋後的結果
- ex: 是否已切換
- ValoChatGroup
MessageReadCountProvider: 針對整個對話,所以的已讀數量的共用資料。- 當時後續疊加的功能,需要一個地方去
熱更新數量,拉出來獨立做管理較方便。 群組已讀數量、好友已讀,先參考Agora Message Receipts- 進入聊天對話時,需要將每則訊息
已讀數量準備好。 - 進入聊天對話後,開始監聽
Agora 已讀事件,熱更新數量。
- 進入聊天對話時,需要將每則訊息
- 當時後續疊加的功能,需要一個地方去
- ValoChat
ResendProvider: 針對整個對話,失敗訊息的共用資料。- 當時後續疊加的功能,沒想太多就拉出來。
- 進入聊天對話時,將失敗訊息保存起來
- 該則訊息
重送後,會轉交由ChatClient.getInstance.chatManager.addMessageEvent:onSuccess,成功後,會將該筆失敗訊息刪除。
- 當時後續疊加的功能,沒想太多就拉出來。
ForeceMessageIdProvider: 紀錄 目前使用者對哪則訊息長按,要給1-3單元使用的共用資料。
Widget build(BuildContext context) {
return MultiProvider(
providers: [
Provider.value(value: conversation),
ChangeNotifierProvider(create: (context) => ValoChatComposerProvider()),
ChangeNotifierProvider(create: (context) => ValoChatSearchProvider()),
ChangeNotifierProvider(create: (context) => ValoChatGroupMessageReadCountProvider()),
ChangeNotifierProvider(create: (context) => ValoChatResendProvider()),
ChangeNotifierProvider(create: (context) => ForeceMessageIdProvider()),
],
1. 訊息類別(參考:Agora Message)
1-1. 加入群組


ChatCustomMessage(event:group_invite)
- 邀請人
inviter_user_id - 群名稱
group_name
對方如何擁有 加入群組訊息:
- 我/建立群組時,邀請好友
- 我/群組聊天/右上
more/邀請好友
提示
因為 valo 為匿名群組,彼此並不會知道,是否在群組內,邀請好友時,會統一送出,是否加入/已加入在對方的對話訊息中各自判斷。
1-2. 一般訊息

文字、檔案、圖片、影片 參考檔案列:
valo_chat.dart:chat_ui.Builders會有各項訊息的元件。agora.ChatClient.getInstance.chatManager.addMessageEvent- 監聽
我自己送出的訊息- 是否成功、失敗
- 成功,右訊息狀態 'V'
- 失敗,右訊息狀態 '!'(紅),並且
長按(onMessageLongPress)顯示Resend
- 監聽
1-3. 回覆、重送、複製訊息

長按(onMessageLongPress) 叫出
ValoChatMessageActionPanelManager:- 可以理解為
面板管理員,根據這則訊息,顯示需要顯示的項目- ex:
回覆、重送、複製
- ex:
- 可以理解為
- 目前
複製功能尚未實作。
存在的問題
原因: 消息面板,我是使用全域漂浮定位
- 只能抓到 距離頂部有多少
- 無法預先知道該元素多高
- 無法控制
層級(類似前端的 z-index)
造成目前現象:
- 只能定在 該訊息的
左上或右上 - 會浮在整個 APP
最上層 - 如果
有時間標籤連他的高,也會被算進去
處理方式:
- 需要深入尋找其他套件,或是研究、熟悉 Flutter 元件去製造
創新元件 - 同 1
- 在
show時,需要多加更精細的判斷,看這則是不是有 被掛上時間標籤,有的話減去固定高度
2. 上傳媒體
2-1. 相機模式

程式碼: media_service.dart::_CameraScreen
在 上傳媒體面板中的相機功能。
- 單點純拍照
- 長按錄影,直到手指放開為止
如何判別 純拍照、長按錄影?
onPointerDown: 點下去紀錄開始時間。
- 此時給一個
倒數者(200 毫秒)- 到點,就切換成
錄影模式。 - 還沒到,會被
onPointerUp攔截掉注銷。
- 到點,就切換成
onPointerUp: 錄影結束 or 純拍照。
過往
最過往是使用 image_picker 中的 camera 模式,但它不支援 錄影。
後面在 影片訊息開放後,相機也需要開放錄影,才比較符合需求,而尋覓了需多套件,參考競品,發現很多人家的 相機頁面,其實很多自己實現居多,例如 ig line 有很多濾鏡、人像辨識...等,未來這塊能尋覓 新套件 將這段替換掉,當時尋覓的新套件功能太重,設定太複雜而選擇自做。
2-2. 相簿上傳

程式碼:media_service.dart::pickMedia
- IOS 使用
image_picker打開 IOS 相簿。 - Android 平台,使用
file_picker選取圖片、影片,中間的檔案類型過濾,套件中有說明如何過濾,自行實現。
過往
image_picker 在 Android 平台支援度很差,所以 Android 平台,使用 file_picker。
2-3. 檔案上傳

程式碼:media_service.dart::pickDocument
使用 file_picker 選取圖片、影片,中間的檔案類型過濾,套件中有說明如何過濾,自行實現。