Merge pull request 'feature/chat' (#388) from feature/chat into develop

Reviewed-on: https://git.pthub.vn/Unity/perfect-world-unity/pulls/388
This commit is contained in:
cuongnv
2026-04-25 04:39:19 +00:00
8 changed files with 795 additions and 7 deletions
@@ -156,7 +156,7 @@ namespace BrewMonster.Scripts.ChatUI
void OnOpenChatPanelRequested(OpenChatPanelRequestedEvent _)
{
if (this == null) return;
OpenChatPanel();
OpenChatPanel(_.focusInputOnOpen);
}
private bool ShouldShowMessage(ChatMessageData data)
@@ -347,13 +347,18 @@ namespace BrewMonster.Scripts.ChatUI
}
public void OpenChatPanel()
{
OpenChatPanel(true);
}
public void OpenChatPanel(bool focusInputOnOpen)
{
if (chatPanelUIGO == null) return;
SetChatPanelAndBgVisible(true);
RefreshVisible();
_chatInput ??= GetComponent<ChatInputHandler>();
if (_chatInput != null && _chatInput.inputField != null)
if (focusInputOnOpen && _chatInput != null && _chatInput.inputField != null)
_chatInput.inputField.ActivateInputField();
}
@@ -392,5 +397,13 @@ namespace BrewMonster.Scripts.ChatUI
/// <summary>
/// Mini chat (hoặc HUD) publish để mở panel chat đầy đủ; <see cref="ChatSystemlUI"/> subscribe.
/// </summary>
public struct OpenChatPanelRequestedEvent { }
public struct OpenChatPanelRequestedEvent
{
public bool focusInputOnOpen;
public OpenChatPanelRequestedEvent(bool focusInputOnOpen)
{
this.focusInputOnOpen = focusInputOnOpen;
}
}
}
@@ -84,7 +84,7 @@ namespace BrewMonster.Scripts.ChatUI
if (!string.IsNullOrEmpty(chatDialogName) && CECUIManager.Instance != null)
CECUIManager.Instance.ShowUI(chatDialogName);
EventBus.Publish(new OpenChatPanelRequestedEvent());
EventBus.Publish(new OpenChatPanelRequestedEvent(false));
}
void OnChannelFilterChanged(ChatChannelFilterChangedEvent e)
@@ -187,6 +187,7 @@ RectTransform:
m_Children:
- {fileID: 2739455247741079987}
- {fileID: 1473246120053017968}
- {fileID: 3282421669272709967}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
@@ -234,6 +235,11 @@ MonoBehaviour:
m_EditorClassIdentifier:
inputField: {fileID: 3037472824809581303}
chatSystem: {fileID: 11400000, guid: 43f54723aa074c74e83e5be28975bee5, type: 2}
typingPreview:
typingPreviewRoot: {fileID: 4018402239503345071}
typingPreviewText: {fileID: 1616725709352662407}
typingPreviewRect: {fileID: 3282421669272709967}
previewVerticalOffset: 100
_spriteMap: {fileID: 11400000, guid: f634ecf63ca3d004f82af9b17c966fc9, type: 2}
channelButtons:
- channel: 0
@@ -1110,6 +1116,163 @@ MonoBehaviour:
m_OnValueChanged:
m_PersistentCalls:
m_Calls: []
--- !u!1 &2902411919389723293
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 9105702282600116830}
- component: {fileID: 8286996527838887664}
- component: {fileID: 1830860820497748550}
- component: {fileID: 4544532093443431984}
m_Layer: 5
m_Name: Placeholder
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &9105702282600116830
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2902411919389723293}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 3605044702849397252}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &8286996527838887664
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2902411919389723293}
m_CullTransparentMesh: 1
--- !u!114 &1830860820497748550
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2902411919389723293}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: "Nh\u1EADp n\u1ED9i dung..."
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
m_sharedMaterial: {fileID: 9092487103257209053, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 2150773298
m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 36
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 2
m_HorizontalAlignment: 1
m_VerticalAlignment: 256
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_TextWrappingMode: 0
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 0
m_ActiveFontFeatures: 6e72656b
m_enableExtraPadding: 1
checkPaddingRequired: 0
m_isRichText: 1
m_EmojiFallbackSupport: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!114 &4544532093443431984
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2902411919389723293}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreLayout: 1
m_MinWidth: -1
m_MinHeight: -1
m_PreferredWidth: -1
m_PreferredHeight: -1
m_FlexibleWidth: -1
m_FlexibleHeight: -1
m_LayoutPriority: 1
--- !u!1 &3095457626805744279
GameObject:
m_ObjectHideFlags: 0
@@ -1493,6 +1656,142 @@ MonoBehaviour:
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!1 &3569864358642720813
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6179475653333898123}
- component: {fileID: 3165768457449138107}
- component: {fileID: 4701185761014729773}
m_Layer: 5
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &6179475653333898123
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3569864358642720813}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 3605044702849397252}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &3165768457449138107
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3569864358642720813}
m_CullTransparentMesh: 1
--- !u!114 &4701185761014729773
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3569864358642720813}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: "\u200B"
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
m_sharedMaterial: {fileID: 9092487103257209053, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4281479730
m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 36
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 1
m_VerticalAlignment: 256
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_TextWrappingMode: 3
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 0
m_ActiveFontFeatures: 6e72656b
m_enableExtraPadding: 1
checkPaddingRequired: 0
m_isRichText: 1
m_EmojiFallbackSupport: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!1 &3646889256970119758
GameObject:
m_ObjectHideFlags: 0
@@ -1671,6 +1970,184 @@ MonoBehaviour:
isAlert: 0
m_InputValidator: {fileID: 0}
m_ShouldActivateOnSelect: 1
--- !u!1 &3775041254222000362
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4921631315982434735}
- component: {fileID: 682447300637418577}
- component: {fileID: 7576867370938653448}
- component: {fileID: 1616725709352662407}
m_Layer: 5
m_Name: InputField (TMP)
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &4921631315982434735
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3775041254222000362}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 3605044702849397252}
m_Father: {fileID: 3282421669272709967}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &682447300637418577
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3775041254222000362}
m_CullTransparentMesh: 1
--- !u!114 &7576867370938653448
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3775041254222000362}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 10911, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!114 &1616725709352662407
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3775041254222000362}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2da0c512f12947e489f739169773d7ca, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_WrapAround: 0
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
m_DisabledColor: {r: 1, g: 1, b: 1, a: 1}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_SelectedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_SelectedTrigger: Selected
m_DisabledTrigger: Disabled
m_Interactable: 0
m_TargetGraphic: {fileID: 7576867370938653448}
m_TextViewport: {fileID: 3605044702849397252}
m_TextComponent: {fileID: 4701185761014729773}
m_Placeholder: {fileID: 1830860820497748550}
m_VerticalScrollbar: {fileID: 0}
m_VerticalScrollbarEventHandler: {fileID: 0}
m_LayoutGroup: {fileID: 0}
m_ScrollSensitivity: 1
m_ContentType: 0
m_InputType: 0
m_AsteriskChar: 42
m_KeyboardType: 0
m_LineType: 0
m_HideMobileInput: 0
m_HideSoftKeyboard: 0
m_CharacterValidation: 0
m_RegexValue:
m_GlobalPointSize: 36
m_CharacterLimit: 0
m_OnEndEdit:
m_PersistentCalls:
m_Calls: []
m_OnSubmit:
m_PersistentCalls:
m_Calls: []
m_OnSelect:
m_PersistentCalls:
m_Calls: []
m_OnDeselect:
m_PersistentCalls:
m_Calls: []
m_OnTextSelection:
m_PersistentCalls:
m_Calls: []
m_OnEndTextSelection:
m_PersistentCalls:
m_Calls: []
m_OnValueChanged:
m_PersistentCalls:
m_Calls: []
m_OnTouchScreenKeyboardStatusChanged:
m_PersistentCalls:
m_Calls: []
m_CaretColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_CustomCaretColor: 0
m_SelectionColor: {r: 0.65882355, g: 0.80784315, b: 1, a: 0.7529412}
m_Text:
m_CaretBlinkRate: 0.85
m_CaretWidth: 1
m_ReadOnly: 0
m_RichText: 1
m_GlobalFontAsset: {fileID: 11400000, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
m_OnFocusSelectAll: 1
m_ResetOnDeActivation: 1
m_KeepTextSelectionVisible: 0
m_RestoreOriginalTextOnEscape: 1
m_isRichTextEditingAllowed: 0
m_LineLimit: 0
isAlert: 0
m_InputValidator: {fileID: 0}
m_ShouldActivateOnSelect: 1
--- !u!1 &3878366334053570553
GameObject:
m_ObjectHideFlags: 0
@@ -1869,6 +2346,82 @@ MonoBehaviour:
m_OnClick:
m_PersistentCalls:
m_Calls: []
--- !u!1 &4018402239503345071
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3282421669272709967}
- component: {fileID: 1622721548801034628}
- component: {fileID: 7848833373218203551}
m_Layer: 5
m_Name: Typing Preview
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
--- !u!224 &3282421669272709967
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4018402239503345071}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 4921631315982434735}
m_Father: {fileID: 806170753671297629}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 15, y: -100}
m_SizeDelta: {x: -30, y: 450.9249}
m_Pivot: {x: 0.5, y: 1}
--- !u!222 &1622721548801034628
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4018402239503345071}
m_CullTransparentMesh: 1
--- !u!114 &7848833373218203551
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4018402239503345071}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 0}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1 &4042949282556349356
GameObject:
m_ObjectHideFlags: 0
@@ -4063,6 +4616,58 @@ MonoBehaviour:
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!1 &6903426946426451281
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3605044702849397252}
- component: {fileID: 2373715959292045924}
m_Layer: 5
m_Name: Text Area
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &3605044702849397252
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6903426946426451281}
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 9105702282600116830}
- {fileID: 6179475653333898123}
m_Father: {fileID: 4921631315982434735}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: -0.50001526}
m_SizeDelta: {x: -20, y: -13}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &2373715959292045924
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6903426946426451281}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3312d7739989d2b4e91e6319e9a96d76, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Padding: {x: -8, y: -5, z: -8, w: -5}
m_Softness: {x: 0, y: 0}
--- !u!1 &6957797720283583814
GameObject:
m_ObjectHideFlags: 0
+28 -3
View File
@@ -3,14 +3,11 @@ using UnityEngine;
using TMPro;
using CSNetwork.GPDataType;
using System.Collections.Generic;
using BrewMonster;
using BrewMonster.Network;
using BrewMonster.Scripts.Chat;
using BrewMonster.Scripts.Chat.EmotionData;
using BrewMonster.Scripts.Managers;
using BrewMonster.UI;
using CSNetwork;
using PerfectWorld.Scripts.Managers;
namespace BrewMonster.Scripts.ChatUI
{
@@ -31,6 +28,9 @@ namespace BrewMonster.Scripts.ChatUI
public TMP_InputField inputField;
public ChatSystemSO chatSystem;
[Header("Typing Preview")]
[SerializeField] private TypingPreviewController typingPreview = new();
[Header("Emoji")]
[Tooltip("SO ánh xạ emotion → TMP sprite tag. Gán EmotionLibrarySpriteMap đã build từ Emotion Atlas Converter.")]
[SerializeField] EmotionLibrarySpriteMap _spriteMap;
@@ -110,6 +110,8 @@ namespace BrewMonster.Scripts.ChatUI
private float m_dwTickFarCry = 0;
private float m_dwTickFarCry2 = 0;
private Vector2 _inputBarBaseAnchoredPos;
private bool _cachedAnchors;
private void Awake()
{
@@ -172,6 +174,14 @@ namespace BrewMonster.Scripts.ChatUI
}
UpdateChatDropdownInteractable();
UpdateTypingPreviewFromInput();
}
private void Update()
{
// Keyboard open/close does not always trigger input value changed,
// so refresh preview gate every frame.
UpdateTypingPreviewFromInput();
}
// =====================================================
@@ -812,6 +822,8 @@ namespace BrewMonster.Scripts.ChatUI
{
inputField.text = "";
}
UpdateTypingPreviewFromInput();
}
private int GetEmotionSetForCurrentChannel()
@@ -877,6 +889,7 @@ namespace BrewMonster.Scripts.ChatUI
if (_syncingWireToDisplay)
{
_lastInputFieldText = newText;
UpdateTypingPreviewFromInput();
return;
}
@@ -884,6 +897,7 @@ namespace BrewMonster.Scripts.ChatUI
{
_lastInputFieldText = newText;
SyncChatWireBodyFromInput();
UpdateTypingPreviewFromInput();
return;
}
@@ -905,11 +919,13 @@ namespace BrewMonster.Scripts.ChatUI
inputField.ForceLabelUpdate();
_lastInputFieldText = fixedText;
SyncChatWireBodyFromInput();
UpdateTypingPreviewFromInput();
return;
}
_lastInputFieldText = newText;
SyncChatWireBodyFromInput();
UpdateTypingPreviewFromInput();
}
/// <summary>
@@ -981,6 +997,15 @@ namespace BrewMonster.Scripts.ChatUI
inputField.ActivateInputField();
}
void UpdateTypingPreviewFromInput()
{
if (inputField == null)
return;
string body = ExtractMessageBodyFromVisual(inputField.text ?? "");
typingPreview?.UpdatePreview(inputField.isFocused, body);
}
/// <summary>
/// C++: GetHostPlayer()->GetPack()->GetItemTotalNum(id) — đếm túi chính.
/// </summary>
+76
View File
@@ -0,0 +1,76 @@
using TMPro;
using UnityEngine;
namespace BrewMonster.Scripts.ChatUI
{
/// <summary>
/// Controls typing preview visibility/content and keyboard-anchored position.
/// Kept standalone so other chat/input UIs can reuse the same behavior.
/// </summary>
[System.Serializable]
public class TypingPreviewController
{
[Tooltip("Root của box xem trước nội dung đang gõ.")]
[SerializeField] private GameObject typingPreviewRoot;
[Tooltip("Text hiển thị nội dung đang gõ realtime.")]
[SerializeField] private TMP_InputField typingPreviewText;
[Tooltip("Rect của preview box để neo theo keyboard.")]
[SerializeField] private RectTransform typingPreviewRect;
[Tooltip("Khoảng cách dọc cộng thêm cho preview box.")]
[SerializeField] private float previewVerticalOffset = 8f;
private Vector2 _baseAnchoredPos;
private bool _cachedAnchor;
public void CacheInitialAnchor()
{
if (_cachedAnchor)
return;
if (typingPreviewRect != null)
_baseAnchoredPos = typingPreviewRect.anchoredPosition;
_cachedAnchor = true;
}
public void ApplyKeyboardOffset(float yOffset)
{
if (typingPreviewRect == null)
return;
CacheInitialAnchor();
var previewPos = _baseAnchoredPos;
previewPos.y += yOffset + previewVerticalOffset;
typingPreviewRect.anchoredPosition = previewPos;
}
public void UpdatePreview(bool isInputFocused, string body)
{
if (typingPreviewRoot == null || typingPreviewText == null)
return;
string previewBody = body ?? string.Empty;
bool keyboardVisible = IsMobileKeyboardVisible();
bool shouldShow = keyboardVisible && isInputFocused;
typingPreviewRoot.SetActive(shouldShow);
if (shouldShow)
typingPreviewText.text = previewBody;
}
bool IsMobileKeyboardVisible()
{
if (!Application.isMobilePlatform)
return false;
return GetVisibleKeyboardHeight() > 0f || TouchScreenKeyboard.visible;
}
float GetVisibleKeyboardHeight()
{
if (!TouchScreenKeyboard.visible)
return 0f;
Rect area = TouchScreenKeyboard.area;
return area.height > 0f ? area.height : 0f;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a9934ac12c563f746a3ba562e3de5bff
+60
View File
@@ -0,0 +1,60 @@
# Typing Preview - Summary
## Muc tieu da thuc hien
- Tach logic `typingPreview` ra class rieng de de tai su dung.
- Lien ket lai logic giua `ChatInputHandler` va `TypingPreviewController`.
- Dieu chinh co che hien/an theo yeu cau mobile keyboard.
## Cac file da cap nhat
- `Assets/Scripts/TypingPreviewController.cs`
- `Assets/Scripts/ChatInputHandler.cs`
## Noi dung da lam
### 1) Tach typing preview thanh class rieng
- Tao class `TypingPreviewController` de quan ly:
- Hien/an preview (`typingPreviewRoot`)
- Cap nhat text preview realtime (`typingPreviewText`)
- Dinh vi preview theo offset keyboard (`typingPreviewRect`, `previewVerticalOffset`)
### 2) Lien ket voi ChatInputHandler
- `ChatInputHandler` giu `SerializeField`:
- `TypingPreviewController typingPreview`
- Moi khi input thay doi text, `ChatInputHandler` lay message body (bo prefix kenh/whisper) roi day sang controller de cap nhat preview.
- Khi clear input, preview duoc cap nhat lai ngay de an dung trang thai.
### 3) Co che mobile keyboard (cap nhat moi nhat)
- Da chuyen logic check keyboard vao thang `TypingPreviewController`:
- `IsMobileKeyboardVisible()`
- `GetVisibleKeyboardHeight()`
- `ChatInputHandler` da bo cac ham keyboard-check khong con dung.
- `ChatInputHandler` chi can goi `typingPreview.UpdatePreview(isFocused, body)`.
- `ChatInputHandler.Update()` van refresh moi frame de bat kip luc keyboard mo/dong.
- Rule hien moi nhat:
- Keyboard mobile vua mo la preview show ngay (neu input dang focus), khong can cho co ky tu.
## Hanh vi hien tai
- Preview chi hien khi:
- Dang o mobile
- Keyboard dang mo
- Input dang focus
- Khong con yeu cau body phai khong rong (show ngay khi keyboard mo).
- Khi tat keyboard, preview an ngay.
- Khi mo lai keyboard, noi dung da go truoc do van con trong input va preview hien lai dung noi dung.
## Emoji tren preview
- Hien tai preview duoc set text truc tiep tu `body`, nen neu `body` co TMP sprite tag thi co the hien emoji.
- Luu y cau hinh component:
- `typingPreviewText` dang de kieu `TMP_InputField` trong `TypingPreviewController`.
- Neu muon on dinh cho muc dich "preview display", nen doi sang `TMP_Text` hoac `TextMeshProUGUI`.
## Ghi chu
- Da kiem tra lint sau cac lan sua, khong phat hien loi lint moi tren cac file da chinh.
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 85a85257c23e84e41ba29cbc51455178
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: