├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── itstack │ │ └── naive │ │ └── chat │ │ └── ui │ │ ├── Application.java │ │ ├── util │ │ ├── AutoSizeTool.java │ │ ├── CacheUtil.java │ │ ├── DateUtil.java │ │ └── Ids.java │ │ └── view │ │ ├── UIObject.java │ │ ├── chat │ │ ├── ChatController.java │ │ ├── ChatEventDefine.java │ │ ├── ChatInit.java │ │ ├── ChatView.java │ │ ├── IChatEvent.java │ │ ├── IChatMethod.java │ │ ├── data │ │ │ ├── GroupsData.java │ │ │ ├── RemindCount.java │ │ │ ├── TalkBoxData.java │ │ │ └── TalkData.java │ │ └── element │ │ │ ├── group_bar_chat │ │ │ ├── ElementInfoBox.java │ │ │ └── ElementTalk.java │ │ │ └── group_bar_friend │ │ │ ├── ElementFriendGroup.java │ │ │ ├── ElementFriendGroupList.java │ │ │ ├── ElementFriendLuck.java │ │ │ ├── ElementFriendLuckUser.java │ │ │ ├── ElementFriendSubscription.java │ │ │ ├── ElementFriendTag.java │ │ │ ├── ElementFriendUser.java │ │ │ └── ElementFriendUserList.java │ │ ├── face │ │ ├── FaceController.java │ │ ├── FaceEventDefine.java │ │ ├── FaceInit.java │ │ ├── FaceView.java │ │ └── IFaceMethod.java │ │ └── login │ │ ├── ILoginEvent.java │ │ ├── ILoginMethod.java │ │ ├── LoginController.java │ │ ├── LoginEventDefine.java │ │ ├── LoginInit.java │ │ └── LoginView.java └── resources │ └── fxml │ ├── chat │ ├── chat.fxml │ ├── css │ │ ├── chat.css │ │ ├── chat_bar.css │ │ ├── css-info.md │ │ ├── group_bar_chat │ │ │ ├── chat_information.css │ │ │ ├── chat_operation.css │ │ │ ├── chat_search.css │ │ │ ├── chat_talk.css │ │ │ ├── chat_tool.css │ │ │ ├── chat_touch.css │ │ │ ├── chat_txt.css │ │ │ └── group_bar_chat.css │ │ └── group_bar_friend │ │ │ ├── chat_content.css │ │ │ ├── chat_friend.css │ │ │ ├── chat_friend_group.css │ │ │ ├── chat_friend_luck.css │ │ │ ├── chat_friend_user.css │ │ │ ├── chat_operation.css │ │ │ ├── chat_search.css │ │ │ └── group_bar_friend.css │ └── img │ │ ├── head │ │ ├── 01_100.png │ │ ├── 01_45.png │ │ ├── 01_50.png │ │ ├── 02_100.png │ │ ├── 02_50.png │ │ ├── 03_100.png │ │ ├── 03_50.png │ │ ├── 04_100.png │ │ ├── 04_50.png │ │ ├── 05_50.png │ │ ├── 06_50.png │ │ ├── 07_50.png │ │ ├── 08_50.png │ │ ├── 09_50.png │ │ ├── 10_50.png │ │ ├── 11_50.png │ │ ├── 12_50.png │ │ ├── default.png │ │ ├── group_1.png │ │ ├── group_2.png │ │ ├── group_3.png │ │ ├── hamster.png │ │ └── logo.png │ │ └── system │ │ ├── add_0.png │ │ ├── add_1.png │ │ ├── chat_0.png │ │ ├── chat_1.png │ │ ├── chat_2.png │ │ ├── close_0.png │ │ ├── close_1.png │ │ ├── face_0.png │ │ ├── face_1.png │ │ ├── friend_0.png │ │ ├── friend_1.png │ │ ├── friend_2.png │ │ ├── friend_group_50.png │ │ ├── friend_luck_50.png │ │ ├── head_default.png │ │ ├── head_default_5050.png │ │ ├── location_0.png │ │ ├── location_1.png │ │ ├── location_2.png │ │ ├── min_0.png │ │ ├── min_1.png │ │ ├── more_0.png │ │ ├── more_1.png │ │ ├── search_0.png │ │ ├── set_0.png │ │ ├── set_1.png │ │ ├── set_2.png │ │ └── talk_delete.png │ ├── face │ ├── css │ │ └── face.css │ ├── face.fxml │ └── img │ │ ├── f_01.png │ │ ├── f_02.png │ │ ├── f_03.png │ │ ├── f_04.png │ │ ├── f_05.png │ │ ├── f_11.png │ │ ├── f_12.png │ │ ├── f_13.png │ │ ├── f_14.png │ │ ├── f_15.png │ │ ├── f_21.png │ │ ├── f_22.png │ │ ├── f_23.png │ │ ├── f_24.png │ │ └── f_25.png │ └── login │ ├── css │ └── login.css │ ├── img │ └── system │ │ ├── bugstack_logo.jpg │ │ ├── bugstack_logo.png │ │ ├── close_0.png │ │ ├── close_1.png │ │ ├── head_default_100.png │ │ ├── head_default_128.png │ │ ├── head_default_5050.png │ │ ├── min_0.png │ │ ├── min_1.png │ │ └── show.png │ └── login.fxml └── test └── java └── org └── itstack └── navice └── test └── ApiTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # :heart:《Netty+JavaFx实战:仿桌面版微信聊天》| UI工程 2 | 3 | [![stars](https://badgen.net/github/stars/itstack-naive-chat/itstack-naive-chat-ui?icon=github&color=4ab8a1)](https://github.com/itstack-naive-chat/itstack-naive-chat-ui) [![forks](https://badgen.net/github/forks/itstack-naive-chat/itstack-naive-chat-ui?icon=github&color=4ab8a1)](https://github.com/itstack-naive-chat/itstack-naive-chat-ui) [](http://chat.itstack.org) [](https://itstack.org/_media/qrcode.png?x-oss-process=style/may) 4 | 5 | > 本项目是作者小傅哥使用技术栈```JavaFx```、```Netty4.x```、```SpringBoot```、```Mysql```等,搭建的仿桌面版微信聊天工程实现通信核心功能。如果本项目能为您提供帮助,请给予支持(关注、点赞、分享)! 6 | 7 | > **作者:** 小傅哥,Java Developer,[:trophy: CSDN 博客专家](https://bugstack.blog.csdn.net),[:bug: 虫洞 · 科技栈](https://bugstack.cn) 8 | 9 | **学习链接:** 10 | 11 | - [《Netty+JavaFx实战:仿桌面版微信聊天》](https://chat.itstack.org) 12 | 13 | **赏个鸡腿🍗** 14 | 15 | ![](https://bugstack.cn/assets/images/tip.jpg) 16 | 17 | ---- 18 | 19 | ## 一、简述 20 | 21 | 此工程是使用JavaFx开发的UI端,在我们的UI端中提供了;登录框体、聊天框体,同时在聊天框体中有大量的行为交互界面以及接口和事件。最终我的UI端使用Maven打包的方式向外提供Jar包,以此来达到UI界面与业务行为流程分离。并且用户可以很方便的在我们的框架结构下进行扩展。 22 | 23 | ## 二、Maven配置 24 | 25 | ```xml 26 | 27 | org.itstack 28 | itstack-naive-chat-ui 29 | 1.0.0-SNAPSHOT 30 | 31 | ``` 32 | 33 | ## 三、页面展示 34 | 35 | ### 1. 登录页面 36 | 37 | ![登陆页面](http://chat.itstack.org/assets/img/2020/ui-00.png) 38 | 39 | ### 2. 聊天页面 40 | 41 | ![聊天页面](http://chat.itstack.org/assets/img/2020/ui-01.png) 42 | 43 | ### 3. 添加好友 44 | 45 | ![添加好友](http://chat.itstack.org/assets/img/2020/ui-02.png) 46 | 47 | ### 4. 消息提醒 48 | 49 | ![消息提醒](http://chat.itstack.org/assets/img/2020/ui-05.png) 50 | 51 | ## 四、功能 52 | 53 | ### 1. 登录窗体 54 | 55 | - **接口** 56 | 57 | | 序号 | 方法名 | 描述 | 58 | | :---: | :--- | :--- | 59 | | 1 | void doShow() | 打开登陆窗口 | 60 | | 2 | void doLoginError() | 登录失败提醒 | 61 | | 3 | void doLoginSuccess() | 登陆成功;跳转聊天窗口(关闭登陆窗口,打开新窗口) | 62 | 63 | - **事件** 64 | 65 | | 序号 | 事件名 | 描述 | 66 | | :---: | :--- | :--- | 67 | | 1 | void doLoginCheck(String userId, String userPassword) | 登陆验证 | 68 | 69 | 70 | ### 2. 聊天窗体 71 | 72 | - **接口** 73 | 74 | | 序号 | 接口名 | 描述 | 75 | | :---: | :--- | :--- | 76 | | 1 | void doShow() | 打开窗口 | 77 | | 2 | void setUserInfo(String userId, String userNickName, String userHead) | 设置登陆用户ID、昵称、头像 | 78 | | 3 | void addTalkBox(int talkIdx, Integer talkType, String talkId, String talkName, String talkHead, String talkSketch, Date talkDate, Boolean selected) | 填充对话框列表 | 79 | | 4 | void addTalkMsgUserLeft(String talkId, String msg, Date msgData, Boolean idxFirst, Boolean selected, Boolean isRemind) | 填充对话框消息-好友[别人的消息] | 80 | | 5 | void addTalkMsgGroupLeft(String talkId, String userId, String userNickName, String userHead, String msg, Date msgDate, Boolean idxFirst, Boolean selected, Boolean isRemind) | 填充对话框消息-群组[别人的消息] | 81 | | 6 | void addTalkMsgRight(String talkId, String msg, Date msgData, Boolean idxFirst, Boolean selected, Boolean isRemind) | 填充对话框消息[自己的消息] | 82 | | 7 | void addFriendGroup(String groupId, String groupName, String groupHead) | 好友列表添加‘群组’ | 83 | | 8 | void addFriendUser(boolean selected, String userId, String userNickName, String userHead) | 好友列表添加‘用户’ | 84 | | 9 | void addLuckFriend(String userId, String userNickName, String userHead, Integer status) | 缘分好友(默认添加10个好友) | 85 | 86 | - **事件** 87 | 88 | | 序号 | 事件名 | 描述 | 89 | | :---: | :--- | :--- | 90 | | 1 | void doQuit() | 聊天窗口退出操作 | 91 | | 2 | void doSendMsg(String userId, String talkId, Integer talkType, String msg, Date msgDate) | 发送消息按钮 | 92 | | 3 | void doEventAddTalkUser(String userId, String userFriendId) | 事件处理;开启与好友发送消息 [点击发送消息时候触发 -> 添加到对话框、选中、展示对话列表] | 93 | | 4 | void doEventAddTalkGroup(String userId, String groupId) | 事件处理;开启与群组发送消息 | 94 | | 5 | void doEventDelTalkUser(String userId, String talkId) | 事件处理;删除指定对话框 | 95 | | 6 | void addFriendLuck(String userId, ListView listView) | 事件处理;查询有缘用户添加到列表 | 96 | | 7 | void doFriendLuckSearch(String userId, String text) | 事件处理;好友搜索[搜索后结果调用添加:addLuckFriend] | 97 | | 8 | void doEventAddLuckUser(String userId, String friendId) | 添加好友事件 | 98 | 99 | ---- 100 | 101 | 如果本项目能为您提供帮助,请给予支持(关注、点赞、分享)! -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.itstack 8 | itstack-naive-chat-ui 9 | 1.0.0-SNAPSHOT 10 | jar 11 | 12 | 13 | 14 | org.slf4j 15 | slf4j-api 16 | 1.7.25 17 | 18 | 19 | 20 | 21 | itstack-naive-chat-ui 22 | 23 | 24 | 25 | maven-compiler-plugin 26 | 2.3.2 27 | 28 | 1.8 29 | 1.8 30 | UTF-8 31 | 32 | 33 | 34 | 35 | maven-resources-plugin 36 | 2.4.3 37 | 38 | UTF-8 39 | 40 | 41 | 42 | 43 | maven-source-plugin 44 | 2.0.4 45 | 46 | 47 | attach-sources 48 | 49 | jar 50 | 51 | 52 | 53 | 54 | 55 | com.zenjava 56 | javafx-maven-plugin 57 | 8.8.3 58 | 59 | org.itstack.naive.chat.ui.Application 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/Application.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui; 2 | 3 | import javafx.scene.control.ListView; 4 | import javafx.scene.layout.Pane; 5 | import javafx.stage.Stage; 6 | import org.itstack.naive.chat.ui.view.chat.element.group_bar_friend.ElementFriendLuckUser; 7 | import org.itstack.naive.chat.ui.view.chat.ChatController; 8 | import org.itstack.naive.chat.ui.view.chat.IChatEvent; 9 | import org.itstack.naive.chat.ui.view.chat.IChatMethod; 10 | import org.itstack.naive.chat.ui.view.login.ILoginMethod; 11 | import org.itstack.naive.chat.ui.view.login.LoginController; 12 | 13 | import java.util.Date; 14 | 15 | /** 16 | * 窗口 Stage 17 | * -场景 Scene 18 | * -布局 stackPane 19 | * -控件 Button 20 | */ 21 | public class Application extends javafx.application.Application { 22 | 23 | @Override 24 | public void start(Stage primaryStage) throws Exception { 25 | 26 | IChatMethod chat = new ChatController(new IChatEvent() { 27 | @Override 28 | public void doQuit() { 29 | System.out.println("退出操作!"); 30 | } 31 | 32 | @Override 33 | public void doSendMsg(String userId, String talkId, Integer talkType, String msg, Integer msgType, Date msgDate) { 34 | System.out.println("发送消息"); 35 | System.out.println("userId:" + userId); 36 | System.out.println("talkType[0好友/1群组]:" + talkType); 37 | System.out.println("talkId:" + talkId); 38 | System.out.println("msg:" + msg); 39 | System.out.println("msgType[0文字消息/1固定表情]:" + msgType); 40 | } 41 | 42 | @Override 43 | public void doEventAddTalkUser(String userId, String userFriendId) { 44 | System.out.println("填充到聊天窗口[好友] userFriendId:" + userFriendId); 45 | } 46 | 47 | @Override 48 | public void doEventAddTalkGroup(String userId, String groupId) { 49 | System.out.println("填充到聊天窗口[群组] groupId:" + groupId); 50 | } 51 | 52 | @Override 53 | public void doEventDelTalkUser(String userId, String talkId) { 54 | System.out.println("删除对话框:" + talkId); 55 | } 56 | 57 | @Override 58 | public void addFriendLuck(String userId, ListView listView) { 59 | System.out.println("新的朋友"); 60 | // 添加朋友 61 | listView.getItems().add(new ElementFriendLuckUser("1000005", "比丘卡", "05_50", 0).pane()); 62 | listView.getItems().add(new ElementFriendLuckUser("1000006", "兰兰", "06_50", 1).pane()); 63 | listView.getItems().add(new ElementFriendLuckUser("1000007", "Alexa", "07_50", 2).pane()); 64 | } 65 | 66 | @Override 67 | public void doFriendLuckSearch(String userId, String text) { 68 | System.out.println("搜索好友:" + text); 69 | } 70 | 71 | @Override 72 | public void doEventAddLuckUser(String userId, String friendId) { 73 | System.out.println("添加好友:" + friendId); 74 | } 75 | }); 76 | 77 | 78 | chat.doShow(); 79 | chat.setUserInfo("1000001", "拎包冲", "02_50"); 80 | // 模拟测试 81 | chat.addTalkBox(-1, 0, "1000004", "哈尼克兔", "04_50", null, null, false); 82 | chat.addTalkMsgUserLeft("1000004", "沉淀、分享、成长,让自己和他人都有所收获!", 0, new Date(), true, false, true); 83 | chat.addTalkMsgUserLeft("1000004", "f_23", 1, new Date(), true, false, true); 84 | 85 | chat.addTalkMsgRight("1000004", "今年过年是放假时间最长的了!", 0, new Date(), true, true, false); 86 | 87 | chat.addTalkBox(-1, 0, "1000002", "铁锤", "03_50", "秋风扫过树叶落,哪有棋盘哪有我", new Date(), false); 88 | chat.addTalkMsgUserLeft("1000002", "秋风扫过树叶落,哪有棋盘哪有我", 0, new Date(), true, false, true); 89 | chat.addTalkMsgRight("1000002", "我Q,传说中的老头杀?", 0, new Date(), true, true, false); 90 | 91 | // 群组 92 | chat.addFriendGroup("5307397", "虫洞技术栈(1区)", "group_1"); 93 | chat.addFriendGroup("5307392", "CSDN 社区专家", "group_2"); 94 | chat.addFriendGroup("5307399", "洗脚城VIP", "group_3"); 95 | 96 | // 群组 - 对话框 97 | chat.addTalkBox(0, 1, "5307397", "虫洞技术栈(1区)", "group_1", "", new Date(), true); 98 | chat.addTalkMsgRight("5307397", "你炸了我的山", 0, new Date(), true, true, false); 99 | chat.addTalkMsgRight("5307397", "f_14", 1, new Date(), true, true, false); 100 | chat.addTalkMsgGroupLeft("5307397", "1000002", "拎包冲", "01_50", "推我过忘川", 0, new Date(), true, false, true); 101 | chat.addTalkMsgGroupLeft("5307397", "1000003", "铁锤", "03_50", "奈河桥边的姑娘", 0, new Date(), true, false, true); 102 | chat.addTalkMsgGroupLeft("5307397", "1000004", "哈尼克兔", "04_50", "等我回头看", 0, new Date(), true, false, true); 103 | chat.addTalkMsgGroupLeft("5307397", "1000004", "哈尼克兔", "04_50", "f_25", 1, new Date(), true, false, true); 104 | 105 | // 好友 106 | chat.addFriendUser(false, "1000004", "哈尼克兔", "04_50"); 107 | chat.addFriendUser(false, "1000001", "拎包冲", "02_50"); 108 | chat.addFriendUser(false, "1000002", "铁锤", "03_50"); 109 | chat.addFriendUser(true, "1000003", "小傅哥 | bugstack.cn", "01_50"); 110 | 111 | 112 | ILoginMethod login = new LoginController((userId, userPassword) -> { 113 | System.out.println("登陆 userId:" + userId + "userPassword:" + userPassword); 114 | }, chat); 115 | // login.doShow(); 116 | } 117 | 118 | public static void main(String[] args) { 119 | launch(args); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/util/AutoSizeTool.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.util; 2 | 3 | /** 4 | * 博 客:http://bugstack.cn 5 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 6 | * create by 小傅哥 on @2019 7 | */ 8 | public class AutoSizeTool { 9 | 10 | public static double getWidth(String msg) { 11 | int len = msg.length(); 12 | double width = 0; 13 | for (int i = 0; i < len; i++) { 14 | if (isChinese(msg.charAt(i))) { 15 | width += 16; 16 | } else { 17 | width += 16; 18 | } 19 | } 20 | 21 | width += 22; // 补全前后空格 22 | 23 | if (width > 450) { 24 | return 450; 25 | } 26 | 27 | return width < 50 ? 50 : width; 28 | } 29 | 30 | public static double getHeight(String msg) { 31 | int len = msg.length(); 32 | double width = 0; 33 | for (int i = 0; i < len; i++) { 34 | if (isChinese(msg.charAt(i))) { 35 | width += 16; 36 | } else { 37 | width += 16; 38 | } 39 | } 40 | 41 | width += 22; // 补全前后空格 42 | 43 | double remainder = width % 450; 44 | int line = (int) (width / 450); 45 | 46 | if (remainder != 0) { 47 | line = line + 1; 48 | } 49 | 50 | double autoHeight = line * 24 + 10; 51 | 52 | return autoHeight < 30 ? 30 : autoHeight; 53 | 54 | } 55 | 56 | private static boolean isChinese(char c) { 57 | Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); 58 | return ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS 59 | || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS 60 | || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A 61 | || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION 62 | || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION 63 | || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/util/CacheUtil.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.util; 2 | 3 | import org.itstack.naive.chat.ui.view.chat.element.group_bar_chat.ElementTalk; 4 | 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | /** 9 | * 博 客:http://bugstack.cn 10 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 11 | * create by 小傅哥 on @2020 12 | */ 13 | public class CacheUtil { 14 | 15 | // 对话框组 16 | public static Map talkMap = new ConcurrentHashMap(16); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/util/DateUtil.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.util; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Calendar; 5 | import java.util.Date; 6 | 7 | /** 8 | * 博 客:http://bugstack.cn 9 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 10 | * create by 小傅哥 on @2020 11 | */ 12 | public class DateUtil { 13 | 14 | SimpleDateFormat nowBegin = new SimpleDateFormat("yyyy-MM-dd 00:00:00"); 15 | SimpleDateFormat nowEnd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 16 | 17 | 18 | public static String simpleDate(Date date) { 19 | boolean today = isToday(date); 20 | if (today) return new SimpleDateFormat("HH:mm").format(date); 21 | return new SimpleDateFormat("yy/MM/dd").format(date); 22 | } 23 | 24 | private static boolean isToday(Date date) { 25 | Calendar c1 = Calendar.getInstance(); 26 | c1.setTime(date); 27 | int year1 = c1.get(Calendar.YEAR); 28 | int month1 = c1.get(Calendar.MONTH) + 1; 29 | int day1 = c1.get(Calendar.DAY_OF_MONTH); 30 | Calendar c2 = Calendar.getInstance(); 31 | c2.setTime(new Date()); 32 | int year2 = c2.get(Calendar.YEAR); 33 | int month2 = c2.get(Calendar.MONTH) + 1; 34 | int day2 = c2.get(Calendar.DAY_OF_MONTH); 35 | return year1 == year2 && month1 == month2 && day1 == day2; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/util/Ids.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.util; 2 | 3 | /** 4 | * 博 客:http://bugstack.cn 5 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 6 | * create by 小傅哥 on @2020 7 | *

8 | * 组件ID 9 | */ 10 | public class Ids { 11 | 12 | /** 13 | * 对话框元素,好友对话列表框元素 14 | */ 15 | public static class ElementTalkId { 16 | public static String createTalkPaneId(String id) { 17 | return "ElementTalkId_createTalkPaneId_" + id; 18 | } 19 | 20 | public static String analysisTalkPaneId(String id) { 21 | return id.split("_")[2]; 22 | } 23 | 24 | public static String createInfoBoxListId(String id) { 25 | return "ElementTalkId_createInfoBoxListId_" + id; 26 | } 27 | 28 | public static String analysisInfoBoxListId(String id) { 29 | return id.split("_")[2]; 30 | } 31 | 32 | public static String createMsgDataId(String id) { 33 | return "ElementTalkId_createMsgDataId_" + id; 34 | } 35 | 36 | public static String analysisMsgDataId(String id) { 37 | return id.split("_")[2]; 38 | } 39 | 40 | public static String createMsgSketchId(String id) { 41 | return "ElementTalkId_createMsgSketchId_" + id; 42 | } 43 | 44 | public static String analysisMsgSketchId(String id) { 45 | return id.split("_")[2]; 46 | } 47 | 48 | public static String createFriendGroupId(String id) { 49 | return "ElementTalkId_createFriendGroupId_" + id; 50 | } 51 | 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/UIObject.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view; 2 | 3 | import javafx.scene.Cursor; 4 | import javafx.scene.Parent; 5 | import javafx.scene.control.ListView; 6 | import javafx.scene.layout.Pane; 7 | import javafx.stage.Stage; 8 | 9 | /** 10 | * 博 客:http://bugstack.cn 11 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 12 | * create by 小傅哥 on @2020 13 | */ 14 | public abstract class UIObject extends Stage { 15 | 16 | protected Parent root; 17 | private double xOffset; 18 | private double yOffset; 19 | 20 | public T $(String id, Class clazz) { 21 | return (T) root.lookup("#" + id); 22 | } 23 | 24 | public void clearViewListSelectedAll(ListView... listViews) { 25 | for (ListView listView : listViews) { 26 | listView.getSelectionModel().clearSelection(); 27 | } 28 | } 29 | 30 | public void move() { 31 | root.setOnMousePressed(event -> { 32 | xOffset = getX() - event.getScreenX(); 33 | yOffset = getY() - event.getScreenY(); 34 | root.setCursor(Cursor.CLOSED_HAND); 35 | }); 36 | root.setOnMouseDragged(event -> { 37 | setX(event.getScreenX() + xOffset); 38 | setY(event.getScreenY() + yOffset); 39 | }); 40 | root.setOnMouseReleased(event -> { 41 | root.setCursor(Cursor.DEFAULT); 42 | }); 43 | } 44 | 45 | public double x(){ 46 | return getX(); 47 | } 48 | 49 | public double y(){ 50 | return getY(); 51 | } 52 | 53 | public double width(){ 54 | return getWidth(); 55 | } 56 | 57 | public double height(){ 58 | return getHeight(); 59 | } 60 | 61 | // 初始化页面 62 | public abstract void initView(); 63 | 64 | // 初始化事件定义 65 | public abstract void initEventDefine(); 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/ChatController.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat; 2 | 3 | import javafx.collections.ObservableList; 4 | import javafx.scene.Node; 5 | import javafx.scene.control.Button; 6 | import javafx.scene.control.Label; 7 | import javafx.scene.control.ListView; 8 | import javafx.scene.layout.Pane; 9 | import org.itstack.naive.chat.ui.util.CacheUtil; 10 | import org.itstack.naive.chat.ui.util.Ids; 11 | import org.itstack.naive.chat.ui.view.chat.data.TalkData; 12 | import org.itstack.naive.chat.ui.view.chat.data.GroupsData; 13 | import org.itstack.naive.chat.ui.view.chat.data.RemindCount; 14 | import org.itstack.naive.chat.ui.view.chat.element.group_bar_chat.ElementInfoBox; 15 | import org.itstack.naive.chat.ui.view.chat.element.group_bar_chat.ElementTalk; 16 | import org.itstack.naive.chat.ui.view.chat.element.group_bar_friend.ElementFriendGroup; 17 | import org.itstack.naive.chat.ui.view.chat.element.group_bar_friend.ElementFriendLuckUser; 18 | import org.itstack.naive.chat.ui.view.chat.element.group_bar_friend.ElementFriendUser; 19 | 20 | import java.util.Date; 21 | 22 | /** 23 | * 博 客:http://bugstack.cn 24 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 25 | * create by 小傅哥 on @2020 26 | */ 27 | public class ChatController extends ChatInit implements IChatMethod { 28 | 29 | private ChatView chatView; 30 | private ChatEventDefine chatEventDefine; 31 | 32 | public ChatController(IChatEvent chatEvent) { 33 | super(chatEvent); 34 | } 35 | 36 | @Override 37 | public void initView() { 38 | chatView = new ChatView(this, chatEvent); 39 | } 40 | 41 | @Override 42 | public void initEventDefine() { 43 | chatEventDefine = new ChatEventDefine(this, chatEvent, this); 44 | } 45 | 46 | @Override 47 | public void doShow() { 48 | super.show(); 49 | } 50 | 51 | @Override 52 | public void setUserInfo(String userId, String userNickName, String userHead) { 53 | super.userId = userId; 54 | super.userNickName = userNickName; 55 | super.userHead = userHead; 56 | Button button = $("bar_portrait", Button.class); 57 | button.setStyle(String.format("-fx-background-image: url('/fxml/chat/img/head/%s.png')", userHead)); 58 | } 59 | 60 | @Override 61 | public void addTalkBox(int talkIdx, Integer talkType, String talkId, String talkName, String talkHead, String talkSketch, Date talkDate, Boolean selected) { 62 | // 填充到对话框 63 | ListView talkList = $("talkList", ListView.class); 64 | // 判断会话框是否有该对象 65 | ElementTalk elementTalk = CacheUtil.talkMap.get(talkId); 66 | if (null != elementTalk) { 67 | Node talkNode = talkList.lookup("#" + Ids.ElementTalkId.createTalkPaneId(talkId)); 68 | if (null == talkNode) { 69 | talkList.getItems().add(talkIdx, elementTalk.pane()); 70 | // 填充对话框消息栏 71 | fillInfoBox(elementTalk, talkName); 72 | } 73 | if (selected) { 74 | // 设置选中 75 | talkList.getSelectionModel().select(elementTalk.pane()); 76 | } 77 | // 填充对话框消息栏 78 | fillInfoBox(elementTalk, talkName); 79 | return; 80 | } 81 | // 初始化对话框元素 82 | ElementTalk talkElement = new ElementTalk(talkId, talkType, talkName, talkHead, talkSketch, talkDate); 83 | CacheUtil.talkMap.put(talkId, talkElement); 84 | // 填充到对话框 85 | ObservableList items = talkList.getItems(); 86 | Pane talkElementPane = talkElement.pane(); 87 | if (talkIdx >= 0) { 88 | items.add(talkIdx, talkElementPane); // 添加到第一个位置 89 | } else { 90 | items.add(talkElementPane); // 顺序添加 91 | } 92 | if (selected) { 93 | talkList.getSelectionModel().select(talkElementPane); 94 | } 95 | // 对话框元素点击事件 96 | talkElementPane.setOnMousePressed(event -> { 97 | // 填充消息栏 98 | fillInfoBox(talkElement, talkName); 99 | // 清除消息提醒 100 | Label msgRemind = talkElement.msgRemind(); 101 | msgRemind.setUserData(new RemindCount(0)); 102 | msgRemind.setVisible(false); 103 | }); 104 | // 鼠标事件[移入/移出] 105 | talkElementPane.setOnMouseEntered(event -> { 106 | talkElement.delete().setVisible(true); 107 | }); 108 | talkElementPane.setOnMouseExited(event -> { 109 | talkElement.delete().setVisible(false); 110 | }); 111 | // 填充对话框消息栏 112 | fillInfoBox(talkElement, talkName); 113 | // 从对话框中删除 114 | talkElement.delete().setOnMouseClicked(event -> { 115 | talkList.getItems().remove(talkElementPane); 116 | $("info_pane_box", Pane.class).getChildren().clear(); 117 | $("info_pane_box", Pane.class).setUserData(null); 118 | $("info_name", Label.class).setText(""); 119 | talkElement.infoBoxList().getItems().clear(); 120 | talkElement.clearMsgSketch(); 121 | chatEvent.doEventDelTalkUser(super.userId, talkId); 122 | }); 123 | } 124 | 125 | /** 126 | * 私有方法 127 | * 填充对话框消息内容 128 | * 129 | * @param talkElement 对话框元素 130 | * @param talkName 对话框名称 131 | */ 132 | private void fillInfoBox(ElementTalk talkElement, String talkName) { 133 | String talkId = talkElement.pane().getUserData().toString(); 134 | // 填充对话列表 135 | Pane info_pane_box = $("info_pane_box", Pane.class); 136 | String boxUserId = (String) info_pane_box.getUserData(); 137 | // 判断是否已经填充[talkId],当前已填充则返回 138 | if (talkId.equals(boxUserId)) return; 139 | ListView listView = talkElement.infoBoxList(); 140 | info_pane_box.setUserData(talkId); 141 | info_pane_box.getChildren().clear(); 142 | info_pane_box.getChildren().add(listView); 143 | // 对话框名称 144 | Label info_name = $("info_name", Label.class); 145 | info_name.setText(talkName); 146 | } 147 | 148 | @Override 149 | public void addTalkMsgUserLeft(String talkId, String msg, Integer msgType, Date msgDate, Boolean idxFirst, Boolean selected, Boolean isRemind) { 150 | ElementTalk talkElement = CacheUtil.talkMap.get(talkId); 151 | ListView listView = talkElement.infoBoxList(); 152 | TalkData talkUserData = (TalkData) listView.getUserData(); 153 | Pane left = new ElementInfoBox().left(talkUserData.getTalkName(), talkUserData.getTalkHead(), msg, msgType); 154 | // 消息填充 155 | listView.getItems().add(left); 156 | // 滚动条 157 | listView.scrollTo(left); 158 | talkElement.fillMsgSketch(0 == msgType ? msg : "[表情]", msgDate); 159 | // 设置位置&选中 160 | chatView.updateTalkListIdxAndSelected(0, talkElement.pane(), talkElement.msgRemind(), idxFirst, selected, isRemind); 161 | } 162 | 163 | @Override 164 | public void addTalkMsgGroupLeft(String talkId, String userId, String userNickName, String userHead, String msg, Integer msgType, Date msgDate, Boolean idxFirst, Boolean selected, Boolean isRemind) { 165 | // 自己的消息抛弃 166 | if (super.userId.equals(userId)) return; 167 | ElementTalk talkElement = CacheUtil.talkMap.get(talkId); 168 | if (null == talkElement) { 169 | GroupsData groupsData = (GroupsData) $(Ids.ElementTalkId.createFriendGroupId(talkId), Pane.class).getUserData(); 170 | if (null == groupsData) return; 171 | addTalkBox(0, 1, talkId, groupsData.getGroupName(), groupsData.getGroupHead(), userNickName + ":" + msg, msgDate, false); 172 | talkElement = CacheUtil.talkMap.get(talkId); 173 | // 事件通知(开启与群组发送消息) 174 | chatEvent.doEventAddTalkGroup(super.userId, talkId); 175 | } 176 | ListView listView = talkElement.infoBoxList(); 177 | Pane left = new ElementInfoBox().left(userNickName, userHead, msg, msgType); 178 | // 消息填充 179 | listView.getItems().add(left); 180 | // 滚动条 181 | listView.scrollTo(left); 182 | talkElement.fillMsgSketch(0 == msgType ? userNickName + ":" + msg : userNickName + ":[表情]", msgDate); 183 | // 设置位置&选中 184 | chatView.updateTalkListIdxAndSelected(1, talkElement.pane(), talkElement.msgRemind(), idxFirst, selected, isRemind); 185 | } 186 | 187 | @Override 188 | public void addTalkMsgRight(String talkId, String msg, Integer msgType, Date msgData, Boolean idxFirst, Boolean selected, Boolean isRemind) { 189 | ElementTalk talkElement = CacheUtil.talkMap.get(talkId); 190 | ListView listView = talkElement.infoBoxList(); 191 | Pane right = new ElementInfoBox().right(userNickName, userHead, msg, msgType); 192 | // 消息填充 193 | listView.getItems().add(right); 194 | // 滚动条 195 | listView.scrollTo(right); 196 | talkElement.fillMsgSketch(0 == msgType ? msg : "[表情]", msgData); 197 | // 设置位置&选中 198 | chatView.updateTalkListIdxAndSelected(0, talkElement.pane(), talkElement.msgRemind(), idxFirst, selected, isRemind); 199 | } 200 | 201 | @Override 202 | public void addFriendGroup(String groupId, String groupName, String groupHead) { 203 | ElementFriendGroup elementFriendGroup = new ElementFriendGroup(groupId, groupName, groupHead); 204 | Pane pane = elementFriendGroup.pane(); 205 | // 添加到群组列表 206 | ListView groupListView = $("groupListView", ListView.class); 207 | ObservableList items = groupListView.getItems(); 208 | items.add(pane); 209 | groupListView.setPrefHeight(80 * items.size()); 210 | $("friendGroupList", Pane.class).setPrefHeight(80 * items.size()); 211 | 212 | // 群组,内容框[初始化,未装载],承载群组信息内容,点击按钮时候填充 213 | Pane detailContent = new Pane(); 214 | detailContent.setPrefSize(850, 560); 215 | detailContent.getStyleClass().add("friendGroupDetailContent"); 216 | ObservableList children = detailContent.getChildren(); 217 | 218 | Button sendMsgButton = new Button(); 219 | sendMsgButton.setId(groupId); 220 | sendMsgButton.getStyleClass().add("friendGroupSendMsgButton"); 221 | sendMsgButton.setPrefSize(176, 50); 222 | sendMsgButton.setLayoutX(337); 223 | sendMsgButton.setLayoutY(450); 224 | sendMsgButton.setText("发送消息"); 225 | chatEventDefine.doEventOpenFriendGroupSendMsg(sendMsgButton, groupId, groupName, groupHead); 226 | children.add(sendMsgButton); 227 | 228 | // 添加监听事件 229 | pane.setOnMousePressed(event -> { 230 | clearViewListSelectedAll($("friendList", ListView.class), $("userListView", ListView.class)); 231 | chatView.setContentPaneBox(groupId, groupName, detailContent); 232 | }); 233 | chatView.setContentPaneBox(groupId, groupName, detailContent); 234 | } 235 | 236 | @Override 237 | public void addFriendUser(boolean selected, String userFriendId, String userFriendNickName, String userFriendHead) { 238 | ElementFriendUser friendUser = new ElementFriendUser(userFriendId, userFriendNickName, userFriendHead); 239 | Pane pane = friendUser.pane(); 240 | // 添加到好友列表 241 | ListView userListView = $("userListView", ListView.class); 242 | ObservableList items = userListView.getItems(); 243 | items.add(pane); 244 | userListView.setPrefHeight(80 * items.size()); 245 | $("friendUserList", Pane.class).setPrefHeight(80 * items.size()); 246 | // 选中 247 | if (selected) { 248 | userListView.getSelectionModel().select(pane); 249 | } 250 | 251 | // 好友,内容框[初始化,未装载],承载好友信息内容,点击按钮时候填充 252 | Pane detailContent = new Pane(); 253 | detailContent.setPrefSize(850, 560); 254 | detailContent.getStyleClass().add("friendUserDetailContent"); 255 | ObservableList children = detailContent.getChildren(); 256 | 257 | Button sendMsgButton = new Button(); 258 | sendMsgButton.setId(userFriendId); 259 | sendMsgButton.getStyleClass().add("friendUserSendMsgButton"); 260 | sendMsgButton.setPrefSize(176, 50); 261 | sendMsgButton.setLayoutX(337); 262 | sendMsgButton.setLayoutY(450); 263 | sendMsgButton.setText("发送消息"); 264 | chatEventDefine.doEventOpenFriendUserSendMsg(sendMsgButton, userFriendId, userFriendNickName, userFriendHead); 265 | children.add(sendMsgButton); 266 | // 添加监听事件 267 | pane.setOnMousePressed(event -> { 268 | clearViewListSelectedAll($("friendList", ListView.class), $("groupListView", ListView.class)); 269 | chatView.setContentPaneBox(userFriendId, userFriendNickName, detailContent); 270 | }); 271 | chatView.setContentPaneBox(userFriendId, userFriendNickName, detailContent); 272 | } 273 | 274 | @Override 275 | public void addLuckFriend(String userId, String userNickName, String userHead, Integer status) { 276 | ElementFriendLuckUser friendLuckUser = new ElementFriendLuckUser(userId, userNickName, userHead, status); 277 | Pane pane = friendLuckUser.pane(); 278 | // 添加到好友列表 279 | ListView friendLuckListView = $("friendLuckListView", ListView.class); 280 | ObservableList items = friendLuckListView.getItems(); 281 | items.add(pane); 282 | // 点击事件 283 | friendLuckUser.statusLabel().setOnMousePressed(event -> { 284 | chatEvent.doEventAddLuckUser(super.userId, userId); 285 | }); 286 | } 287 | 288 | @Override 289 | public double getToolFaceX() { 290 | return x() + width() - 960; 291 | } 292 | 293 | @Override 294 | public double getToolFaceY() { 295 | return y() + height() - 180; 296 | } 297 | 298 | } 299 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/ChatEventDefine.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat; 2 | 3 | import javafx.event.EventHandler; 4 | import javafx.scene.control.*; 5 | import javafx.scene.input.KeyCode; 6 | import javafx.scene.input.MouseEvent; 7 | import javafx.scene.layout.Pane; 8 | import org.itstack.naive.chat.ui.view.chat.data.TalkBoxData; 9 | import org.itstack.naive.chat.ui.view.face.FaceController; 10 | 11 | import java.util.Date; 12 | 13 | /** 14 | * 博 客:http://bugstack.cn 15 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 16 | * create by 小傅哥 on @2020 17 | *

18 | * 事件定义 19 | */ 20 | public class ChatEventDefine { 21 | 22 | private ChatInit chatInit; 23 | private IChatEvent chatEvent; 24 | private IChatMethod chatMethod; 25 | 26 | public ChatEventDefine(ChatInit chatInit, IChatEvent chatEvent, IChatMethod chatMethod) { 27 | this.chatInit = chatInit; 28 | this.chatEvent = chatEvent; 29 | this.chatMethod = chatMethod; 30 | 31 | chatInit.move(); 32 | min(); // 最小化 33 | quit(); // 退出 34 | barChat(); // 聊天 35 | barFriend(); // 好友 36 | doEventTextSend(); // 发送消息事件[键盘] 37 | doEventTouchSend(); // 发送消息事件[按钮] 38 | doEventToolFace(); // 表情窗体 39 | } 40 | 41 | // 最小化 42 | private void min() { 43 | chatInit.$("group_bar_chat_min", Button.class).setOnAction(event -> { 44 | chatInit.setIconified(true); 45 | }); 46 | chatInit.$("group_bar_friend_min", Button.class).setOnAction(event -> { 47 | chatInit.setIconified(true); 48 | }); 49 | } 50 | 51 | // 退出 52 | private void quit() { 53 | chatInit.$("group_bar_chat_close", Button.class).setOnAction(event -> { 54 | chatEvent.doQuit(); 55 | chatInit.close(); 56 | System.exit(0); 57 | }); 58 | chatInit.$("group_bar_friend_close", Button.class).setOnAction(event -> { 59 | chatEvent.doQuit(); 60 | chatInit.close(); 61 | System.exit(0); 62 | }); 63 | } 64 | 65 | // 聊天 66 | private void barChat() { 67 | Button bar_chat = chatInit.$("bar_chat", Button.class); 68 | Pane group_bar_chat = chatInit.$("group_bar_chat", Pane.class); 69 | bar_chat.setOnAction(event -> { 70 | switchBarChat(bar_chat, group_bar_chat, true); 71 | switchBarFriend(chatInit.$("bar_friend", Button.class), chatInit.$("group_bar_friend", Pane.class), false); 72 | }); 73 | bar_chat.setOnMouseEntered(event -> { 74 | boolean visible = group_bar_chat.isVisible(); 75 | if (visible) return; 76 | bar_chat.setStyle("-fx-background-image: url('/fxml/chat/img/system/chat_1.png')"); 77 | }); 78 | bar_chat.setOnMouseExited(event -> { 79 | boolean visible = group_bar_chat.isVisible(); 80 | if (visible) return; 81 | bar_chat.setStyle("-fx-background-image: url('/fxml/chat/img/system/chat_0.png')"); 82 | }); 83 | } 84 | 85 | // 好友 86 | private void barFriend() { 87 | Button bar_friend = chatInit.$("bar_friend", Button.class); 88 | Pane group_bar_friend = chatInit.$("group_bar_friend", Pane.class); 89 | bar_friend.setOnAction(event -> { 90 | switchBarChat(chatInit.$("bar_chat", Button.class), chatInit.$("group_bar_chat", Pane.class), false); 91 | switchBarFriend(bar_friend, group_bar_friend, true); 92 | }); 93 | bar_friend.setOnMouseEntered(event -> { 94 | boolean visible = group_bar_friend.isVisible(); 95 | if (visible) return; 96 | bar_friend.setStyle("-fx-background-image: url('/fxml/chat/img/system/friend_1.png')"); 97 | }); 98 | bar_friend.setOnMouseExited(event -> { 99 | boolean visible = group_bar_friend.isVisible(); 100 | if (visible) return; 101 | bar_friend.setStyle("-fx-background-image: url('/fxml/chat/img/system/friend_0.png')"); 102 | }); 103 | } 104 | 105 | // 切换:bar_chat 106 | private void switchBarChat(Button bar_chat, Pane group_bar_chat, boolean toggle) { 107 | if (toggle) { 108 | bar_chat.setStyle("-fx-background-image: url('/fxml/chat/img/system/chat_2.png')"); 109 | group_bar_chat.setVisible(true); 110 | } else { 111 | bar_chat.setStyle("-fx-background-image: url('/fxml/chat/img/system/chat_0.png')"); 112 | group_bar_chat.setVisible(false); 113 | } 114 | } 115 | 116 | // 切换:bar_friend 117 | private void switchBarFriend(Button bar_friend, Pane group_bar_friend, boolean toggle) { 118 | if (toggle) { 119 | bar_friend.setStyle("-fx-background-image: url('/fxml/chat/img/system/friend_2.png')"); 120 | group_bar_friend.setVisible(true); 121 | } else { 122 | bar_friend.setStyle("-fx-background-image: url('/fxml/chat/img/system/friend_0.png')"); 123 | group_bar_friend.setVisible(false); 124 | } 125 | } 126 | 127 | // 好友;开启与好友发送消息 [点击发送消息时候触发 -> 添加到对话框、选中、展示对话列表] 128 | public void doEventOpenFriendUserSendMsg(Button sendMsgButton, String userFriendId, String userFriendNickName, String userFriendHead) { 129 | sendMsgButton.setOnAction(event -> { 130 | // 1. 添加好友到对话框 131 | chatMethod.addTalkBox(0, 0, userFriendId, userFriendNickName, userFriendHead, null, null, true); 132 | // 2. 切换到对话框窗口 133 | switchBarChat(chatInit.$("bar_chat", Button.class), chatInit.$("group_bar_chat", Pane.class), true); 134 | switchBarFriend(chatInit.$("bar_friend", Button.class), chatInit.$("group_bar_friend", Pane.class), false); 135 | // 3. 事件处理;填充到对话框 136 | chatEvent.doEventAddTalkUser(chatInit.userId, userFriendId); 137 | }); 138 | } 139 | 140 | // 群组;开启与群组发送消息 141 | public void doEventOpenFriendGroupSendMsg(Button sendMsgButton, String groupId, String groupName, String groupHead) { 142 | sendMsgButton.setOnAction(event -> { 143 | // 1. 添加好友到对话框 144 | chatMethod.addTalkBox(0, 1, groupId, groupName, groupHead, null, null, true); 145 | // 2. 切换到对话框窗口 146 | switchBarChat(chatInit.$("bar_chat", Button.class), chatInit.$("group_bar_chat", Pane.class), true); 147 | switchBarFriend(chatInit.$("bar_friend", Button.class), chatInit.$("group_bar_friend", Pane.class), false); 148 | // 3. 事件处理;填充到对话框 149 | chatEvent.doEventAddTalkGroup(chatInit.userId, groupId); 150 | }); 151 | } 152 | 153 | // 发送消息事件[键盘] 154 | private void doEventTextSend() { 155 | TextArea txt_input = chatInit.$("txt_input", TextArea.class); 156 | txt_input.setOnKeyPressed(event -> { 157 | if (event.getCode().equals(KeyCode.ENTER)) { 158 | doEventSendMsg(); 159 | } 160 | }); 161 | } 162 | 163 | // 发送消息事件[按钮] 164 | private void doEventTouchSend() { 165 | Label touch_send = chatInit.$("touch_send", Label.class); 166 | touch_send.setOnMousePressed(event -> { 167 | doEventSendMsg(); 168 | }); 169 | } 170 | 171 | private void doEventSendMsg() { 172 | TextArea txt_input = chatInit.$("txt_input", TextArea.class); 173 | MultipleSelectionModel selectionModel = chatInit.$("talkList", ListView.class).getSelectionModel(); 174 | Pane selectedItem = (Pane) selectionModel.getSelectedItem(); 175 | // 对话信息 176 | TalkBoxData talkBoxData = (TalkBoxData) selectedItem.getUserData(); 177 | String msg = txt_input.getText(); 178 | if (null == msg || "".equals(msg) || "".equals(msg.trim())) { 179 | return; 180 | } 181 | Date msgDate = new Date(); 182 | // 发送消息 183 | chatEvent.doSendMsg(chatInit.userId, talkBoxData.getTalkId(), talkBoxData.getTalkType(), msg, 0, msgDate); 184 | // 发送事件给自己添加消息 185 | chatMethod.addTalkMsgRight(talkBoxData.getTalkId(), msg, 0, msgDate, true, true, false); 186 | txt_input.clear(); 187 | } 188 | 189 | // 表情 190 | private void doEventToolFace() { 191 | FaceController face = new FaceController(chatInit, chatInit, chatEvent, chatMethod); 192 | Button tool_face = chatInit.$("tool_face", Button.class); 193 | tool_face.setOnMousePressed(event -> { 194 | face.doShowFace(chatMethod.getToolFaceX(), chatMethod.getToolFaceY()); 195 | }); 196 | } 197 | 198 | } 199 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/ChatInit.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat; 2 | 3 | import javafx.fxml.FXMLLoader; 4 | import javafx.scene.Parent; 5 | import javafx.scene.Scene; 6 | import javafx.scene.control.TextArea; 7 | import javafx.scene.image.Image; 8 | import javafx.scene.paint.Color; 9 | import javafx.stage.StageStyle; 10 | import org.itstack.naive.chat.ui.view.UIObject; 11 | 12 | import java.io.IOException; 13 | 14 | /** 15 | * 博 客:http://bugstack.cn 16 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 17 | * create by 小傅哥 on @2020 18 | */ 19 | public abstract class ChatInit extends UIObject { 20 | 21 | private static final String RESOURCE_NAME = "/fxml/chat/chat.fxml"; 22 | 23 | public String userId; // 用户ID 24 | public String userNickName; // 用户昵称 25 | public String userHead; // 用户头像 26 | 27 | public IChatEvent chatEvent; 28 | 29 | public TextArea txt_input; // 输入框 30 | 31 | ChatInit(IChatEvent chatEvent) { 32 | this.chatEvent = chatEvent; 33 | try { 34 | root = FXMLLoader.load(getClass().getResource(RESOURCE_NAME)); 35 | } catch (IOException e) { 36 | e.printStackTrace(); 37 | } 38 | Scene scene = new Scene(root); 39 | scene.setFill(Color.TRANSPARENT); 40 | setScene(scene); 41 | initStyle(StageStyle.TRANSPARENT); 42 | setResizable(false); 43 | this.getIcons().add(new Image("/fxml/chat/img/head/logo.png")); 44 | obtain(); 45 | initView(); 46 | initEventDefine(); 47 | } 48 | 49 | private void obtain() { 50 | // 可以预加载 51 | txt_input = $("txt_input", TextArea.class); 52 | } 53 | 54 | public Parent root(){ 55 | return super.root; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/ChatView.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat; 2 | 3 | import javafx.collections.ObservableList; 4 | import javafx.scene.Node; 5 | import javafx.scene.control.Label; 6 | import javafx.scene.control.ListView; 7 | import javafx.scene.control.TextField; 8 | import javafx.scene.input.KeyCode; 9 | import javafx.scene.layout.Pane; 10 | import org.itstack.naive.chat.ui.view.chat.data.RemindCount; 11 | import org.itstack.naive.chat.ui.view.chat.data.TalkBoxData; 12 | import org.itstack.naive.chat.ui.view.chat.element.group_bar_friend.*; 13 | 14 | /** 15 | * 博 客:http://bugstack.cn 16 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 17 | * create by 小傅哥 on @2020 18 | *

19 | * 聊天窗口展示与事件 20 | */ 21 | public class ChatView { 22 | 23 | private ChatInit chatInit; 24 | private IChatEvent chatEvent; 25 | 26 | public ChatView(ChatInit chatInit, IChatEvent chatEvent) { 27 | this.chatInit = chatInit; 28 | this.chatEvent = chatEvent; 29 | 30 | //1. 好友列表添加工具方法‘新的朋友’ 31 | initAddFriendLuck(); 32 | //2. 好友列表添加‘公众号’ 33 | addFriendSubscription(); 34 | //3. 好友群组框体 35 | addFriendGroupList(); 36 | //4. 好友框体 37 | addFriendUserList(); 38 | } 39 | 40 | /** 41 | * 好友列表添加工具方法‘新的朋友’ 42 | */ 43 | private void initAddFriendLuck() { 44 | ListView friendList = chatInit.$("friendList", ListView.class); 45 | ObservableList items = friendList.getItems(); 46 | 47 | ElementFriendTag elementFriendTag = new ElementFriendTag("新的朋友"); 48 | items.add(elementFriendTag.pane()); 49 | 50 | ElementFriendLuck element = new ElementFriendLuck(); 51 | Pane pane = element.pane(); 52 | items.add(pane); 53 | 54 | // 面板填充和事件 55 | pane.setOnMousePressed(event -> { 56 | Pane friendLuckPane = element.friendLuckPane(); 57 | setContentPaneBox("itstack-naive-chat-ui-chat-friend-luck", "新的朋友", friendLuckPane); 58 | chatInit.clearViewListSelectedAll(chatInit.$("userListView", ListView.class), chatInit.$("groupListView", ListView.class)); 59 | ListView listView = element.friendLuckListView(); 60 | listView.getItems().clear(); 61 | chatEvent.addFriendLuck(chatInit.userId, listView); 62 | }); 63 | 64 | // 搜索框事件 65 | TextField friendLuckSearch = element.friendLuckSearch(); 66 | 67 | // 键盘事件;搜索好友 68 | friendLuckSearch.setOnKeyPressed(event -> { 69 | if (event.getCode().equals(KeyCode.ENTER)) { 70 | String text = friendLuckSearch.getText(); 71 | if (null == text) text = ""; 72 | if (text.length() > 30) text = text.substring(0, 30); 73 | text = text.trim(); 74 | chatEvent.doFriendLuckSearch(chatInit.userId, text); 75 | // 搜索清空元素 76 | element.friendLuckListView().getItems().clear(); 77 | } 78 | }); 79 | 80 | } 81 | 82 | /** 83 | * 好友列表添加‘公众号’ 84 | */ 85 | private void addFriendSubscription() { 86 | ListView friendList = chatInit.$("friendList", ListView.class); 87 | ObservableList items = friendList.getItems(); 88 | 89 | ElementFriendTag elementFriendTag = new ElementFriendTag("公众号"); 90 | items.add(elementFriendTag.pane()); 91 | 92 | ElementFriendSubscription element = new ElementFriendSubscription(); 93 | Pane pane = element.pane(); 94 | items.add(pane); 95 | 96 | pane.setOnMousePressed(event -> { 97 | chatInit.clearViewListSelectedAll(chatInit.$("userListView", ListView.class), chatInit.$("groupListView", ListView.class)); 98 | Pane subPane = element.subPane(); 99 | setContentPaneBox("itstack-naive-chat-ui-chat-friend-subscription", "公众号", subPane); 100 | }); 101 | } 102 | 103 | /** 104 | * 好友群组框体 105 | */ 106 | private void addFriendGroupList() { 107 | ListView friendList = chatInit.$("friendList", ListView.class); 108 | ObservableList items = friendList.getItems(); 109 | 110 | ElementFriendTag elementFriendTag = new ElementFriendTag("群聊"); 111 | items.add(elementFriendTag.pane()); 112 | 113 | ElementFriendGroupList element = new ElementFriendGroupList(); 114 | Pane pane = element.pane(); 115 | items.add(pane); 116 | } 117 | 118 | /** 119 | * 好友框体 120 | */ 121 | private void addFriendUserList() { 122 | ListView friendList = chatInit.$("friendList", ListView.class); 123 | ObservableList items = friendList.getItems(); 124 | 125 | ElementFriendTag elementFriendTag = new ElementFriendTag("好友"); 126 | items.add(elementFriendTag.pane()); 127 | 128 | ElementFriendUserList element = new ElementFriendUserList(); 129 | Pane pane = element.pane(); 130 | items.add(pane); 131 | } 132 | 133 | /** 134 | * group_bar_chat:填充对话列表 & 对话框名称 135 | * 136 | * @param id 用户、群组等ID 137 | * @param name 用户、群组等名称 138 | * @param node 展现面板 139 | */ 140 | void setContentPaneBox(String id, String name, Node node) { 141 | // 填充对话列表 142 | Pane content_pane_box = chatInit.$("content_pane_box", Pane.class); 143 | content_pane_box.setUserData(id); 144 | content_pane_box.getChildren().clear(); 145 | content_pane_box.getChildren().add(node); 146 | // 对话框名称 147 | Label info_name = chatInit.$("content_name", Label.class); 148 | info_name.setText(name); 149 | } 150 | 151 | /** 152 | * 更新对话框列表元素位置指定并选中[在聊天消息发送时触达] 153 | */ 154 | /** 155 | * @param talkType 对话框类型[0好友、1群组] 156 | * @param talkElementPane 对话框元素面板 157 | * @param msgRemindLabel 消息提醒标签 158 | * @param idxFirst 是否设置首位 159 | * @param selected 是否选中 160 | * @param isRemind 是否提醒 161 | */ 162 | void updateTalkListIdxAndSelected(int talkType, Pane talkElementPane, Label msgRemindLabel, Boolean idxFirst, Boolean selected, Boolean isRemind) { 163 | // 对话框ID、好友ID 164 | TalkBoxData talkBoxData = (TalkBoxData) talkElementPane.getUserData(); 165 | // 填充到对话框 166 | ListView talkList = chatInit.$("talkList", ListView.class); 167 | // 对话空为空,初始化[置顶、选中、提醒] 168 | if (talkList.getItems().isEmpty()) { 169 | if (idxFirst) { 170 | talkList.getItems().add(0, talkElementPane); 171 | } 172 | if (selected) { 173 | // 设置对话框[√选中] 174 | talkList.getSelectionModel().select(talkElementPane); 175 | } 176 | isRemind(msgRemindLabel, talkType, isRemind); 177 | return; 178 | } 179 | // 对话空不为空,判断第一个元素是否当前聊天Pane 180 | Pane firstPane = talkList.getItems().get(0); 181 | // 判断元素是否在首位,如果是首位可返回不需要重新设置首位 182 | if (talkBoxData.getTalkId().equals(((TalkBoxData) firstPane.getUserData()).getTalkId())) { 183 | Pane selectedItem = talkList.getSelectionModel().getSelectedItem(); 184 | // 选中判断;如果第一个元素已经选中[说明正在会话],那么清空消息提醒 185 | if (null == selectedItem){ 186 | isRemind(msgRemindLabel, talkType, isRemind); 187 | return; 188 | } 189 | TalkBoxData selectedItemUserData = (TalkBoxData) selectedItem.getUserData(); 190 | if (null != selectedItemUserData && talkBoxData.getTalkId().equals(selectedItemUserData.getTalkId())) { 191 | clearRemind(msgRemindLabel); 192 | } else { 193 | isRemind(msgRemindLabel, talkType, isRemind); 194 | } 195 | return; 196 | } 197 | if (idxFirst) { 198 | talkList.getItems().remove(talkElementPane); 199 | talkList.getItems().add(0, talkElementPane); 200 | } 201 | if (selected) { 202 | // 设置对话框[√选中] 203 | talkList.getSelectionModel().select(talkElementPane); 204 | } 205 | isRemind(msgRemindLabel, talkType, isRemind); 206 | } 207 | 208 | /** 209 | * 消息提醒 210 | * 211 | * @param msgRemindLabel 消息面板 212 | */ 213 | private void isRemind(Label msgRemindLabel, int talkType, Boolean isRemind) { 214 | if (!isRemind) return; 215 | msgRemindLabel.setVisible(true); 216 | // 群组直接展示小红点 217 | if (1 == talkType) { 218 | return; 219 | } 220 | RemindCount remindCount = (RemindCount) msgRemindLabel.getUserData(); 221 | // 超过10个展示省略号 222 | if (remindCount.getCount() > 99) { 223 | msgRemindLabel.setText("···"); 224 | return; 225 | } 226 | int count = remindCount.getCount() + 1; 227 | msgRemindLabel.setUserData(new RemindCount(count)); 228 | msgRemindLabel.setText(String.valueOf(count)); 229 | } 230 | 231 | private void clearRemind(Label msgRemindLabel) { 232 | msgRemindLabel.setVisible(false); 233 | msgRemindLabel.setUserData(new RemindCount(0)); 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/IChatEvent.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat; 2 | 3 | import javafx.scene.control.ListView; 4 | import javafx.scene.layout.Pane; 5 | 6 | import java.util.Date; 7 | 8 | /** 9 | * 博 客:http://bugstack.cn 10 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 11 | * create by 小傅哥 on @2020 12 | */ 13 | public interface IChatEvent { 14 | 15 | /** 16 | * 聊天窗口退出操作 17 | */ 18 | void doQuit(); 19 | 20 | /** 21 | * 发送消息按钮 22 | * 23 | * @param userId 用户Id 24 | * @param talkId 对话Id(好友ID/群组ID) 25 | * @param talkType 对话框类型;0好友、1群组 26 | * @param msg 发送消息内容 27 | * @param msgType 消息类型;0文字消息、1固定表情 28 | * @param msgDate 发送消息时间 29 | */ 30 | void doSendMsg(String userId, String talkId, Integer talkType, String msg, Integer msgType, Date msgDate); 31 | 32 | /** 33 | * 事件处理;开启与好友发送消息 [点击发送消息时候触发 -> 添加到对话框、选中、展示对话列表] 34 | * 35 | * @param userId 用户ID 36 | * @param userFriendId 好友ID 37 | */ 38 | void doEventAddTalkUser(String userId, String userFriendId); 39 | 40 | /** 41 | * 事件处理;开启与群组发送消息 42 | * 43 | * @param userId 用户ID 44 | * @param groupId 群组ID 45 | */ 46 | void doEventAddTalkGroup(String userId, String groupId); 47 | 48 | /** 49 | * 事件处理;删除指定对话框 50 | * 51 | * @param userId 用户ID 52 | * @param talkId 对话框ID 53 | */ 54 | void doEventDelTalkUser(String userId, String talkId); 55 | 56 | /** 57 | * 事件处理;查询有缘用户添加到列表 58 | * 59 | * @param userId 用户ID 60 | * @param listView 用户列表[非必需使用,同步接口可使用] 61 | */ 62 | void addFriendLuck(String userId, ListView listView); 63 | 64 | /** 65 | * 事件处理;好友搜索[搜索后结果调用添加:addLuckFriend] 66 | * 67 | * @param userId 用户ID 68 | * @param text 搜索关键字 69 | */ 70 | void doFriendLuckSearch(String userId, String text); 71 | 72 | /** 73 | * 添加好友事件 74 | * 75 | * @param userId 个人ID 76 | * @param friendId 好友ID 77 | */ 78 | void doEventAddLuckUser(String userId, String friendId); 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/IChatMethod.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * 博 客:http://bugstack.cn 7 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 8 | * create by 小傅哥 on @2020 9 | */ 10 | public interface IChatMethod { 11 | 12 | 13 | /** 14 | * 打开窗口 15 | */ 16 | void doShow(); 17 | 18 | /** 19 | * 设置登陆用户头像 20 | * 21 | * @param userId 用户ID 22 | * @param userNickName 用户昵称 23 | * @param userHead 头像图片名称 24 | */ 25 | void setUserInfo(String userId, String userNickName, String userHead); 26 | 27 | /** 28 | * 填充对话框列表 29 | * 30 | * @param talkIdx 对话框位置;首位0、默认-1 31 | * @param talkType 对话框类型;好友0、群组1 32 | * @param talkId 对话框ID,1v1聊天ID、1vn聊天ID 33 | * @param talkName 对话框名称 34 | * @param talkHead 对话框头像 35 | * @param talkSketch 对话框通信简述(聊天内容最后一组信息) 36 | * @param talkDate 对话框通信时间 37 | * @param selected 选中[true/false] 38 | */ 39 | void addTalkBox(int talkIdx, Integer talkType, String talkId, String talkName, String talkHead, String talkSketch, Date talkDate, Boolean selected); 40 | 41 | /** 42 | * 填充对话框消息-好友[别人的消息] 43 | * 44 | * @param talkId 对话框ID[用户ID] 45 | * @param msg 消息 46 | * @param msgType 消息类型;0文字消息、1固定表情 47 | * @param msgData 时间 48 | * @param idxFirst 是否设置首位 49 | * @param selected 是否选中 50 | * @param isRemind 是否提醒 51 | */ 52 | void addTalkMsgUserLeft(String talkId, String msg, Integer msgType, Date msgData, Boolean idxFirst, Boolean selected, Boolean isRemind); 53 | 54 | /** 55 | * 填充对话框消息-群组[别人的消息] 56 | * 57 | * @param talkId 对话框ID[群组ID] 58 | * @param userId 用户ID[群员] 59 | * @param userNickName 用户昵称 60 | * @param userHead 用户头像 61 | * @param msg 消息 62 | * @param msgType 消息类型;0文字消息、1固定表情 63 | * @param msgDate 时间 64 | * @param idxFirst 是否设置首位 65 | * @param selected 是否选中 66 | * @param isRemind 是否提醒 67 | */ 68 | void addTalkMsgGroupLeft(String talkId, String userId, String userNickName, String userHead, String msg, Integer msgType, Date msgDate, Boolean idxFirst, Boolean selected, Boolean isRemind); 69 | 70 | /** 71 | * 填充对话框消息[自己的消息] 72 | * 73 | * @param talkId 对话框ID[用户ID] 74 | * @param msg 消息 75 | * @param msgType 消息类型;0文字消息、1固定表情 76 | * @param msgData 时间 77 | * @param idxFirst 是否设置首位 78 | * @param selected 是否选中 79 | * @param isRemind 是否提醒 80 | */ 81 | void addTalkMsgRight(String talkId, String msg, Integer msgType, Date msgData, Boolean idxFirst, Boolean selected, Boolean isRemind); 82 | 83 | /** 84 | * 好友列表添加‘群组’ 85 | * 86 | * @param groupId 群组ID 87 | * @param groupName 群组名称 88 | * @param groupHead 群组头像 89 | */ 90 | void addFriendGroup(String groupId, String groupName, String groupHead); 91 | 92 | /** 93 | * 好友列表添加‘用户’ 94 | * 95 | * @param selected 选中;true/false 96 | * @param userId 好友ID 97 | * @param userNickName 好友昵称 98 | * @param userHead 好友头像 99 | */ 100 | void addFriendUser(boolean selected, String userId, String userNickName, String userHead); 101 | 102 | /** 103 | * 缘分好友 | 默认添加10个好友 104 | * 105 | * @param userId 好友ID 106 | * @param userNickName 好友昵称 107 | * @param userHead 好友头像 108 | * @param status 状态;0添加、1允许、2已添加 109 | */ 110 | void addLuckFriend(String userId, String userNickName, String userHead, Integer status); 111 | 112 | /** 113 | * 工具栏表情框体,位置:X 114 | */ 115 | double getToolFaceX(); 116 | 117 | /** 118 | * 工具栏表情框体,位置:Y 119 | */ 120 | double getToolFaceY(); 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/data/GroupsData.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.data; 2 | 3 | /** 4 | * 博 客:http://bugstack.cn 5 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 6 | * create by 小傅哥 on @2020 7 | * 8 | * 群组数据(ElementFriendGroup) 9 | */ 10 | public class GroupsData { 11 | 12 | private String groupId; // 群组ID 13 | private String groupName; // 群组名称 14 | private String groupHead; // 群组头像 15 | 16 | public GroupsData() { 17 | } 18 | 19 | public GroupsData(String groupId, String groupName, String groupHead) { 20 | this.groupId = groupId; 21 | this.groupName = groupName; 22 | this.groupHead = groupHead; 23 | } 24 | 25 | public String getGroupId() { 26 | return groupId; 27 | } 28 | 29 | public void setGroupId(String groupId) { 30 | this.groupId = groupId; 31 | } 32 | 33 | public String getGroupName() { 34 | return groupName; 35 | } 36 | 37 | public void setGroupName(String groupName) { 38 | this.groupName = groupName; 39 | } 40 | 41 | public String getGroupHead() { 42 | return groupHead; 43 | } 44 | 45 | public void setGroupHead(String groupHead) { 46 | this.groupHead = groupHead; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/data/RemindCount.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.data; 2 | 3 | /** 4 | * 博 客:http://bugstack.cn 5 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 6 | * create by 小傅哥 on @2020 7 | */ 8 | public class RemindCount { 9 | 10 | private int count = 0; // 消息提醒条数 11 | 12 | public RemindCount() { 13 | } 14 | 15 | public RemindCount(int count) { 16 | this.count = count; 17 | } 18 | 19 | public int getCount() { 20 | return count; 21 | } 22 | 23 | public void setCount(int count) { 24 | this.count = count; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/data/TalkBoxData.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.data; 2 | 3 | /** 4 | * 博 客:http://bugstack.cn 5 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 6 | * create by 小傅哥 on @2020 7 | */ 8 | public class TalkBoxData { 9 | 10 | private String talkId; // 对话Id 11 | private Integer talkType; // 对话类型 12 | private String talkName; // 对话名称 13 | private String talkHead; // 对话头像 14 | 15 | public TalkBoxData() { 16 | } 17 | 18 | public TalkBoxData(String talkId, Integer talkType, String talkName, String talkHead) { 19 | this.talkId = talkId; 20 | this.talkType = talkType; 21 | this.talkName = talkName; 22 | this.talkHead = talkHead; 23 | } 24 | 25 | public Integer getTalkType() { 26 | return talkType; 27 | } 28 | 29 | public void setTalkType(Integer talkType) { 30 | this.talkType = talkType; 31 | } 32 | 33 | public String getTalkId() { 34 | return talkId; 35 | } 36 | 37 | public void setTalkId(String talkId) { 38 | this.talkId = talkId; 39 | } 40 | 41 | public String getTalkName() { 42 | return talkName; 43 | } 44 | 45 | public void setTalkName(String talkName) { 46 | this.talkName = talkName; 47 | } 48 | 49 | public String getTalkHead() { 50 | return talkHead; 51 | } 52 | 53 | public void setTalkHead(String talkHead) { 54 | this.talkHead = talkHead; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/data/TalkData.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.data; 2 | 3 | /** 4 | * 博 客:http://bugstack.cn 5 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 6 | * create by 小傅哥 on @2020 7 | * 8 | * 对话框用户数据 9 | */ 10 | public class TalkData { 11 | 12 | private String talkName; 13 | private String talkHead; 14 | 15 | public TalkData(){} 16 | 17 | public TalkData(String talkName, String talkHead) { 18 | this.talkName = talkName; 19 | this.talkHead = talkHead; 20 | } 21 | 22 | public String getTalkName() { 23 | return talkName; 24 | } 25 | 26 | public void setTalkName(String talkName) { 27 | this.talkName = talkName; 28 | } 29 | 30 | public String getTalkHead() { 31 | return talkHead; 32 | } 33 | 34 | public void setTalkHead(String talkHead) { 35 | this.talkHead = talkHead; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/element/group_bar_chat/ElementInfoBox.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.element.group_bar_chat; 2 | 3 | import javafx.collections.ObservableList; 4 | import javafx.scene.Node; 5 | import javafx.scene.control.Label; 6 | import javafx.scene.control.TextArea; 7 | import javafx.scene.layout.Pane; 8 | import org.itstack.naive.chat.ui.util.AutoSizeTool; 9 | 10 | /** 11 | * 博 客:http://bugstack.cn 12 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 13 | * create by 小傅哥 on @2019 14 | */ 15 | public class ElementInfoBox { 16 | 17 | private Pane pane; 18 | 19 | private Pane head; // 头像 20 | private Label nikeName; // 昵称区 21 | private Label infoContentArrow; // 内容箭头 22 | private TextArea infoContent; // 内容 23 | 24 | /** 25 | * 好友消息 26 | * @param userNickName 27 | * @param userHead 28 | * @param msg 29 | * @param msgType 30 | * @return 31 | */ 32 | public Pane left(String userNickName, String userHead, String msg, Integer msgType) { 33 | 34 | double autoHeight = AutoSizeTool.getHeight(msg); 35 | double autoWidth = AutoSizeTool.getWidth(msg); 36 | 37 | pane = new Pane(); 38 | pane.setPrefSize(500, 50 + autoHeight); 39 | pane.getStyleClass().add("infoBoxElement"); 40 | ObservableList children = pane.getChildren(); 41 | 42 | // 头像 43 | head = new Pane(); 44 | head.setPrefSize(50, 50); 45 | head.setLayoutX(15); 46 | head.setLayoutY(15); 47 | head.getStyleClass().add("box_head"); 48 | head.setStyle(String.format("-fx-background-image: url('/fxml/chat/img/head/%s.png')", userHead)); 49 | children.add(head); 50 | 51 | // 昵称 52 | nikeName = new Label(); 53 | nikeName.setPrefSize(450, 20); 54 | nikeName.setLayoutX(75); 55 | nikeName.setLayoutY(5); 56 | nikeName.setText(userNickName); // "小傅哥 | bugstack.cn" 57 | nikeName.getStyleClass().add("box_nikeName"); 58 | children.add(nikeName); 59 | 60 | // 箭头 61 | infoContentArrow = new Label(); 62 | infoContentArrow.setPrefSize(5, 20); 63 | infoContentArrow.setLayoutX(75); 64 | infoContentArrow.setLayoutY(30); 65 | infoContentArrow.getStyleClass().add("box_infoContent_arrow"); 66 | children.add(infoContentArrow); 67 | 68 | switch (msgType){ 69 | case 0: 70 | // 内容 71 | infoContent = new TextArea(); 72 | infoContent.setPrefWidth(autoWidth); 73 | infoContent.setPrefHeight(autoHeight); 74 | infoContent.setLayoutX(80); 75 | infoContent.setLayoutY(30); 76 | infoContent.setWrapText(true); 77 | infoContent.setEditable(false); 78 | infoContent.setText(msg); 79 | infoContent.getStyleClass().add("box_infoContent_left"); 80 | children.add(infoContent); 81 | break; 82 | case 1: 83 | Label infoContentFace = new Label(); 84 | infoContentFace.setPrefWidth(60); 85 | infoContentFace.setPrefHeight(40); 86 | infoContentFace.setLayoutX(80); 87 | infoContentFace.setLayoutY(30); 88 | infoContentFace.setStyle(String.format("-fx-background-image: url('/fxml/face/img/%s.png');-fx-background-position: center center;-fx-background-repeat: no-repeat;-fx-background-color: #ffffff;-fx-border-width: 0 1px 1px 0;-fx-border-radius: 2px;-fx-background-radius: 2px;", msg)); 89 | children.add(infoContentFace); 90 | break; 91 | } 92 | 93 | return pane; 94 | } 95 | 96 | /** 97 | * 个人消息 98 | * 99 | * @param userNickName 用户昵称 100 | * @param userHead 用户头像 101 | * @param msg 消息 102 | * @param msgType 类型;0文字消息、1固定表情 103 | * @return 104 | */ 105 | public Pane right(String userNickName, String userHead, String msg, Integer msgType) { 106 | 107 | double autoHeight = AutoSizeTool.getHeight(msg); 108 | double autoWidth = AutoSizeTool.getWidth(msg); 109 | 110 | pane = new Pane(); 111 | pane.setPrefSize(500, 50 + autoHeight); 112 | pane.setLayoutX(853); 113 | pane.setLayoutY(0); 114 | pane.getStyleClass().add("infoBoxElement"); 115 | ObservableList children = pane.getChildren(); 116 | 117 | // 头像 118 | head = new Pane(); 119 | head.setPrefSize(50, 50); 120 | head.setLayoutX(770); 121 | head.setLayoutY(15); 122 | head.getStyleClass().add("box_head"); 123 | head.setStyle(String.format("-fx-background-image: url('/fxml/chat/img/head/%s.png')", userHead)); 124 | children.add(head); 125 | 126 | // 箭头 127 | infoContentArrow = new Label(); 128 | infoContentArrow.setPrefSize(5, 20); 129 | infoContentArrow.setLayoutX(755); 130 | infoContentArrow.setLayoutY(15); 131 | infoContentArrow.getStyleClass().add("box_infoContent_arrow"); 132 | children.add(infoContentArrow); 133 | 134 | switch (msgType){ 135 | case 0: 136 | // 内容:文字 137 | infoContent = new TextArea(); 138 | infoContent.setPrefWidth(autoWidth); 139 | infoContent.setPrefHeight(autoHeight); 140 | infoContent.setLayoutX(755 - autoWidth); 141 | infoContent.setLayoutY(15); 142 | infoContent.setWrapText(true); 143 | infoContent.setEditable(false); 144 | infoContent.setText(msg); 145 | infoContent.getStyleClass().add("box_infoContent_right"); 146 | children.add(infoContent); 147 | break; 148 | case 1: 149 | Label infoContentFace = new Label(); 150 | infoContentFace.setPrefWidth(60); 151 | infoContentFace.setPrefHeight(40); 152 | infoContentFace.setLayoutX(755 - 60); 153 | infoContentFace.setLayoutY(15); 154 | infoContentFace.setStyle(String.format("-fx-background-image: url('/fxml/face/img/%s.png');-fx-background-position: center center;-fx-background-repeat: no-repeat;-fx-background-color: #9eea6a;-fx-border-width: 0 1px 1px 0;-fx-border-radius: 2px;-fx-background-radius: 2px;", msg)); 155 | children.add(infoContentFace); 156 | break; 157 | } 158 | 159 | return pane; 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/element/group_bar_chat/ElementTalk.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.element.group_bar_chat; 2 | 3 | import javafx.collections.ObservableList; 4 | import javafx.scene.Node; 5 | import javafx.scene.control.Button; 6 | import javafx.scene.control.Label; 7 | import javafx.scene.control.ListView; 8 | import javafx.scene.layout.Pane; 9 | import org.itstack.naive.chat.ui.util.DateUtil; 10 | import org.itstack.naive.chat.ui.util.Ids; 11 | import org.itstack.naive.chat.ui.view.chat.data.TalkData; 12 | import org.itstack.naive.chat.ui.view.chat.data.RemindCount; 13 | import org.itstack.naive.chat.ui.view.chat.data.TalkBoxData; 14 | 15 | import java.util.Date; 16 | 17 | /** 18 | * 博 客:http://bugstack.cn 19 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 20 | * create by 小傅哥 on @2019 21 | *

22 | * 对话框元素,好友对话列表框元素 23 | */ 24 | public class ElementTalk { 25 | 26 | private Pane pane; 27 | 28 | private Label head; 29 | private Label nikeName; // 昵称区域 30 | private Label msgSketch; // 信息简述 31 | private Label msgData; // 信息时间 32 | private Label msgRemind; // 消息提醒 33 | private Button delete; // 删除对话框按钮 34 | 35 | private ListView infoBoxList; // 初始化填充消息对话框 36 | 37 | public ElementTalk(String talkId, Integer talkType, String talkName, String talkHead, String talkSketch, Date talkDate) { 38 | pane = new Pane(); 39 | pane.setId(Ids.ElementTalkId.createTalkPaneId(talkId)); 40 | pane.setUserData(new TalkBoxData(talkId, talkType, talkName, talkHead)); 41 | pane.setPrefSize(270, 80); 42 | pane.getStyleClass().add("talkElement"); 43 | ObservableList children = pane.getChildren(); 44 | 45 | // 头像区域 46 | head = new Label(); 47 | head.setPrefSize(50, 50); 48 | head.setLayoutX(15); 49 | head.setLayoutY(15); 50 | head.getStyleClass().add("element_head"); 51 | head.setStyle(String.format("-fx-background-image: url('/fxml/chat/img/head/%s.png')", talkHead)); 52 | children.add(head); 53 | 54 | // 昵称区域 55 | nikeName = new Label(); 56 | nikeName.setPrefSize(140, 25); 57 | nikeName.setLayoutX(80); 58 | nikeName.setLayoutY(15); 59 | nikeName.setText(talkName); 60 | nikeName.getStyleClass().add("element_nikeName"); 61 | children.add(nikeName); 62 | 63 | // 信息简述 64 | msgSketch = new Label(); 65 | msgSketch.setId(Ids.ElementTalkId.createMsgSketchId(talkId)); 66 | msgSketch.setPrefSize(200, 25); 67 | msgSketch.setLayoutX(80); 68 | msgSketch.setLayoutY(40); 69 | msgSketch.getStyleClass().add("element_msgSketch"); 70 | children.add(msgSketch); 71 | 72 | // 信息时间 73 | msgData = new Label(); 74 | msgData.setId(Ids.ElementTalkId.createMsgDataId(talkId)); 75 | msgData.setPrefSize(60, 25); 76 | msgData.setLayoutX(220); 77 | msgData.setLayoutY(15); 78 | msgData.getStyleClass().add("element_msgData"); 79 | children.add(msgData); 80 | // 填充;信息简述 & 信息时间 81 | fillMsgSketch(talkSketch, talkDate); 82 | 83 | // 消息提醒 84 | msgRemind = new Label(); 85 | msgRemind.setPrefSize(15, 15); 86 | msgRemind.setLayoutX(60); 87 | msgRemind.setLayoutY(5); 88 | msgRemind.setUserData(new RemindCount()); 89 | msgRemind.setText(""); 90 | msgRemind.setVisible(false); 91 | msgRemind.getStyleClass().add("element_msgRemind"); 92 | children.add(msgRemind); 93 | 94 | // 删除对话框按钮 95 | delete = new Button(); 96 | delete.setVisible(false); 97 | delete.setPrefSize(4, 4); 98 | delete.setLayoutY(26); 99 | delete.setLayoutX(-8); 100 | delete.getStyleClass().add("element_delete"); 101 | children.add(delete); 102 | 103 | // 消息框[初始化,未装载],承载对话信息内容,点击按钮时候填充 104 | infoBoxList = new ListView<>(); 105 | infoBoxList.setId(Ids.ElementTalkId.createInfoBoxListId(talkId)); 106 | infoBoxList.setUserData(new TalkData(talkName, talkHead)); 107 | infoBoxList.setPrefSize(850, 560); 108 | infoBoxList.getStyleClass().add("infoBoxStyle"); 109 | } 110 | 111 | public Pane pane() { 112 | return pane; 113 | } 114 | 115 | public ListView infoBoxList() { 116 | return infoBoxList; 117 | } 118 | 119 | public Button delete() { 120 | return delete; 121 | } 122 | 123 | public void fillMsgSketch(String talkSketch, Date talkDate) { 124 | if (null != talkSketch) { 125 | if (talkSketch.length() > 30) talkSketch = talkSketch.substring(0, 30); 126 | msgSketch.setText(talkSketch); 127 | } 128 | if (null == talkDate) talkDate = new Date(); 129 | // 格式化信息 130 | String talkSimpleDate = DateUtil.simpleDate(talkDate); 131 | msgData.setText(talkSimpleDate); 132 | } 133 | 134 | public void clearMsgSketch() { 135 | msgSketch.setText(""); 136 | } 137 | 138 | public Label msgRemind() { 139 | return msgRemind; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/element/group_bar_friend/ElementFriendGroup.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.element.group_bar_friend; 2 | 3 | import javafx.collections.ObservableList; 4 | import javafx.scene.Node; 5 | import javafx.scene.control.Label; 6 | import javafx.scene.layout.Pane; 7 | import org.itstack.naive.chat.ui.util.Ids; 8 | import org.itstack.naive.chat.ui.view.chat.data.GroupsData; 9 | 10 | /** 11 | * 博 客:http://bugstack.cn 12 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 13 | * create by 小傅哥 on @2020 14 | */ 15 | public class ElementFriendGroup { 16 | 17 | private Pane groupPane; 18 | 19 | public ElementFriendGroup(String groupId, String groupName, String groupHead) { 20 | // 群组底板(存储群ID) 21 | groupPane = new Pane(); 22 | groupPane.setId(Ids.ElementTalkId.createFriendGroupId(groupId)); 23 | groupPane.setUserData(new GroupsData(groupId, groupName, groupHead)); 24 | groupPane.setPrefWidth(250); 25 | groupPane.setPrefHeight(70); 26 | groupPane.getStyleClass().add("elementFriendGroup"); 27 | ObservableList children = groupPane.getChildren(); 28 | // 头像区域 29 | Label groupHeadLabel = new Label(); 30 | groupHeadLabel.setPrefSize(50, 50); 31 | groupHeadLabel.setLayoutX(15); 32 | groupHeadLabel.setLayoutY(10); 33 | groupHeadLabel.getStyleClass().add("elementFriendGroup_head"); 34 | groupHeadLabel.setStyle(String.format("-fx-background-image: url('/fxml/chat/img/head/%s.png')", groupHead)); 35 | children.add(groupHeadLabel); 36 | // 名称区域 37 | Label groupNameLabel = new Label(); 38 | groupNameLabel.setPrefSize(200, 40); 39 | groupNameLabel.setLayoutX(80); 40 | groupNameLabel.setLayoutY(15); 41 | groupNameLabel.setText(groupName); 42 | groupNameLabel.getStyleClass().add("elementFriendGroup_name"); 43 | children.add(groupNameLabel); 44 | } 45 | 46 | public Pane pane() { 47 | return groupPane; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/element/group_bar_friend/ElementFriendGroupList.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.element.group_bar_friend; 2 | 3 | import javafx.collections.ObservableList; 4 | import javafx.scene.Node; 5 | import javafx.scene.control.ListView; 6 | import javafx.scene.layout.Pane; 7 | 8 | 9 | /** 10 | * 博 客:http://bugstack.cn 11 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 12 | * create by 小傅哥 on @2020 13 | *

14 | * 组件;群组 15 | */ 16 | public class ElementFriendGroupList { 17 | 18 | private Pane pane; 19 | private ListView groupListView; // 群组列表 20 | 21 | public ElementFriendGroupList() { 22 | pane = new Pane(); 23 | pane.setId("friendGroupList"); 24 | pane.setPrefWidth(314); 25 | pane.setPrefHeight(0);// 自动计算;groupListView.setPrefHeight(70 * items.size() + 10); 26 | pane.setLayoutX(-10); 27 | pane.getStyleClass().add("elementFriendGroupList"); 28 | ObservableList children = pane.getChildren(); 29 | 30 | groupListView = new ListView<>(); 31 | groupListView.setId("groupListView"); 32 | groupListView.setPrefWidth(314); 33 | groupListView.setPrefHeight(0); // 自动计算;groupListView.setPrefHeight(70 * items.size() + 10); 34 | groupListView.setLayoutX(-10); 35 | groupListView.getStyleClass().add("elementFriendGroupList_listView"); 36 | children.add(groupListView); 37 | } 38 | 39 | public Pane pane() { 40 | return pane; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/element/group_bar_friend/ElementFriendLuck.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.element.group_bar_friend; 2 | 3 | import javafx.collections.ObservableList; 4 | import javafx.geometry.Insets; 5 | import javafx.scene.Node; 6 | import javafx.scene.control.Label; 7 | import javafx.scene.control.ListView; 8 | import javafx.scene.control.TextField; 9 | import javafx.scene.layout.Pane; 10 | 11 | /** 12 | * 博 客:http://bugstack.cn 13 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 14 | * create by 小傅哥 on @2020 15 | *

16 | * 组件;好友缘分 | 添加好友 17 | */ 18 | public class ElementFriendLuck { 19 | 20 | private Pane pane; 21 | 22 | private Label head; // 头像 23 | private Label name; // 名称 24 | 25 | private Pane friendLuckPane; // 用户面板 26 | private TextField friendLuckSearch; // 用户搜索 27 | private ListView friendLuckListView; // 用户列表[待添加好友用户] 28 | 29 | public ElementFriendLuck() { 30 | pane = new Pane(); 31 | pane.setId("elementFriendLuck"); 32 | pane.setPrefSize(270, 70); 33 | pane.getStyleClass().add("elementFriendLuck"); 34 | ObservableList children = pane.getChildren(); 35 | 36 | // 头像区域 37 | head = new Label(); 38 | head.setPrefSize(50, 50); 39 | head.setLayoutX(15); 40 | head.setLayoutY(10); 41 | head.getStyleClass().add("elementFriendLuck_head"); 42 | children.add(head); 43 | 44 | // 名称区域 45 | name = new Label(); 46 | name.setPrefSize(200, 40); 47 | name.setLayoutX(80); 48 | name.setLayoutY(15); 49 | name.setText("新的朋友"); 50 | name.getStyleClass().add("elementFriendLuck_name"); 51 | children.add(name); 52 | 53 | // 初始化框体区域[搜索好友框、展现框] 54 | friendLuckPane = new Pane(); 55 | friendLuckPane.setPrefSize(850, 560); 56 | friendLuckPane.getStyleClass().add("friendLuckPane"); 57 | ObservableList friendLuckPaneChildren = friendLuckPane.getChildren(); 58 | 59 | friendLuckSearch = new TextField(); 60 | friendLuckSearch.setPrefSize(600,50); 61 | friendLuckSearch.setLayoutX(125); 62 | friendLuckSearch.setLayoutY(25); 63 | friendLuckSearch.setPromptText("搜一搜"); 64 | friendLuckSearch.setPadding(new Insets(10)); 65 | friendLuckSearch.getStyleClass().add("friendLuckSearch"); 66 | friendLuckPaneChildren.add(friendLuckSearch); 67 | 68 | // 用户列表框[初始化,未装载] 69 | friendLuckListView = new ListView<>(); 70 | friendLuckListView.setId("friendLuckListView"); 71 | friendLuckListView.setPrefSize(850, 460); 72 | friendLuckListView.setLayoutY(75); 73 | friendLuckListView.getStyleClass().add("friendLuckListView"); 74 | friendLuckPaneChildren.add(friendLuckListView); 75 | 76 | } 77 | 78 | public Pane pane() { 79 | return pane; 80 | } 81 | 82 | public Pane friendLuckPane() { 83 | return friendLuckPane; 84 | } 85 | 86 | public TextField friendLuckSearch() { 87 | return friendLuckSearch; 88 | } 89 | 90 | public ListView friendLuckListView() { 91 | return friendLuckListView; 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/element/group_bar_friend/ElementFriendLuckUser.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.element.group_bar_friend; 2 | 3 | import javafx.collections.ObservableList; 4 | import javafx.scene.Node; 5 | import javafx.scene.control.Label; 6 | import javafx.scene.layout.Pane; 7 | 8 | /** 9 | * 博 客:http://bugstack.cn 10 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 11 | * create by 小傅哥 on @2020 12 | */ 13 | public class ElementFriendLuckUser { 14 | 15 | private Pane pane; // 用户底板 16 | 17 | private Label idLabel; // 展示用户ID 18 | private Label headLabel; // 头像区域 19 | private Label nameLabel; // 名称区域 20 | private Label statusLabel;// 状态;0添加/1接受 21 | private Label line; // 底线 22 | 23 | /** 24 | * 构造函数 25 | * 26 | * @param userId 用户ID 27 | * @param userNickName 用户昵称 28 | * @param userHead 用户头像 29 | * @param status 状态;0/1/2 30 | */ 31 | public ElementFriendLuckUser(String userId, String userNickName, String userHead, Integer status) { 32 | pane = new Pane(); 33 | pane.setUserData(userId); 34 | pane.setPrefWidth(250); 35 | pane.setPrefHeight(70); 36 | pane.getStyleClass().add("elementFriendLuckUser"); 37 | ObservableList children = pane.getChildren(); 38 | // 头像区域 39 | headLabel = new Label(); 40 | headLabel.setPrefSize(50, 50); 41 | headLabel.setLayoutX(125); 42 | headLabel.setLayoutY(10); 43 | headLabel.getStyleClass().add("elementFriendLuckUser_head"); 44 | headLabel.setStyle(String.format("-fx-background-image: url('/fxml/chat/img/head/%s.png')", userHead)); 45 | children.add(headLabel); 46 | 47 | // 名称区域 48 | nameLabel = new Label(); 49 | nameLabel.setPrefSize(200, 30); 50 | nameLabel.setLayoutX(190); 51 | nameLabel.setLayoutY(10); 52 | nameLabel.setText(userNickName); 53 | nameLabel.getStyleClass().add("elementFriendLuckUser_name"); 54 | children.add(nameLabel); 55 | 56 | // ID区域 57 | idLabel = new Label(); 58 | idLabel.setPrefSize(200, 20); 59 | idLabel.setLayoutX(190); 60 | idLabel.setLayoutY(40); 61 | idLabel.setText(userId); 62 | idLabel.getStyleClass().add("elementFriendLuckUser_id"); 63 | children.add(idLabel); 64 | 65 | // 底线 66 | line = new Label(); 67 | line.setPrefSize(582,1); 68 | line.setLayoutX(125); 69 | line.setLayoutY(50); 70 | line.getStyleClass().add("elementFriendLuck_line"); 71 | children.add(line); 72 | 73 | // 状态区域 74 | statusLabel = new Label(); 75 | statusLabel.setPrefSize(56, 30); 76 | statusLabel.setLayoutX(650); 77 | statusLabel.setLayoutY(20); 78 | String statusText = "添加"; 79 | if (1 == status){ 80 | statusText = "允许"; 81 | } else if (2 == status){ 82 | statusText = "已添加"; 83 | } 84 | statusLabel.setText(statusText); 85 | statusLabel.setUserData(status); 86 | statusLabel.getStyleClass().add("elementFriendLuckUser_statusLabel_" + status); 87 | children.add(statusLabel); 88 | } 89 | 90 | public Pane pane() { 91 | return pane; 92 | } 93 | 94 | // 添加按钮 95 | public Label statusLabel() { 96 | return statusLabel; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/element/group_bar_friend/ElementFriendSubscription.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.element.group_bar_friend; 2 | 3 | import javafx.collections.ObservableList; 4 | import javafx.scene.Node; 5 | import javafx.scene.control.Button; 6 | import javafx.scene.control.Label; 7 | import javafx.scene.control.TableView; 8 | import javafx.scene.image.Image; 9 | import javafx.scene.layout.Pane; 10 | import javafx.scene.text.TextAlignment; 11 | 12 | import javax.swing.text.html.ImageView; 13 | 14 | /** 15 | * 博 客:http://bugstack.cn 16 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 17 | * create by 小傅哥 on @2020 18 | * 19 | * 组件;公众号 20 | */ 21 | public class ElementFriendSubscription { 22 | 23 | private Pane pane; 24 | 25 | private Label head; // 头像 26 | private Label name; // 名称 27 | 28 | private Pane subPane; // 公众号面板 29 | 30 | public ElementFriendSubscription(){ 31 | pane = new Pane(); 32 | pane.setPrefSize(270, 70); 33 | pane.getStyleClass().add("elementFriendSubscription"); 34 | ObservableList children = pane.getChildren(); 35 | 36 | // 头像区域 37 | head = new Label(); 38 | head.setPrefSize(50, 50); 39 | head.setLayoutX(15); 40 | head.setLayoutY(10); 41 | head.getStyleClass().add("elementFriendSubscription_head"); 42 | children.add(head); 43 | 44 | // 名称区域 45 | name = new Label(); 46 | name.setPrefSize(200,40); 47 | name.setLayoutX(80); 48 | name.setLayoutY(15); 49 | name.setText("公众号"); 50 | name.getStyleClass().add("elementFriendSubscription_name"); 51 | children.add(name); 52 | 53 | // 初始化未装载 54 | subPane = new Pane(); 55 | subPane.setPrefSize(850, 560); 56 | subPane.setStyle("-fx-background-color:transparent;"); 57 | ObservableList subPaneChildren = subPane.getChildren(); 58 | 59 | Button gzh_button = new Button(); 60 | gzh_button.setPrefSize(65,65); 61 | gzh_button.setLayoutX(110); 62 | gzh_button.setLayoutY(30); 63 | gzh_button.setStyle("-fx-background-color: transparent;" + 64 | "-fx-background-radius: 0px;" + 65 | "-fx-border-width: 50px;" + 66 | "-fx-background-image: url('/fxml/login/img/system/bugstack_logo.png');"); 67 | subPaneChildren.add(gzh_button); 68 | 69 | Label gzh_label = new Label(); 70 | gzh_label.setPrefSize(150,20); 71 | gzh_label.setLayoutX(95); 72 | gzh_label.setLayoutY(100); 73 | gzh_label.setText("bugstack虫洞栈"); 74 | gzh_label.setStyle("-fx-background-color: transparent;-fx-border-width: 0; -fx-text-fill: #999999;" + 75 | "-fx-font-size: 14px;"); 76 | gzh_label.setTextAlignment(TextAlignment.CENTER); 77 | subPaneChildren.add(gzh_label); 78 | 79 | } 80 | 81 | public Pane pane() { 82 | return pane; 83 | } 84 | 85 | public Pane subPane() { 86 | return subPane; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/element/group_bar_friend/ElementFriendTag.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.element.group_bar_friend; 2 | 3 | import javafx.collections.ObservableList; 4 | import javafx.scene.Node; 5 | import javafx.scene.control.Button; 6 | import javafx.scene.layout.Pane; 7 | 8 | /** 9 | * 博 客:http://bugstack.cn 10 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 11 | * create by 小傅哥 on @2020 12 | * 13 | * 占位标签;新的朋友、公众号、群组、好友 14 | */ 15 | public class ElementFriendTag { 16 | 17 | private Pane pane; 18 | 19 | public ElementFriendTag(String tagText){ 20 | pane = new Pane(); 21 | pane.setPrefSize(270, 24); 22 | pane.setStyle("-fx-background-color: transparent;"); 23 | ObservableList children = pane.getChildren(); 24 | 25 | Button label = new Button(); 26 | label.setPrefSize(260,24); 27 | label.setLayoutX(5); 28 | label.setText(tagText); 29 | label.getStyleClass().add("element_friend_tag"); 30 | children.add(label); 31 | 32 | } 33 | 34 | public Pane pane() { 35 | return pane; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/element/group_bar_friend/ElementFriendUser.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.element.group_bar_friend; 2 | 3 | import javafx.collections.ObservableList; 4 | import javafx.scene.Node; 5 | import javafx.scene.control.Label; 6 | import javafx.scene.layout.Pane; 7 | 8 | /** 9 | * 博 客:http://bugstack.cn 10 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 11 | * create by 小傅哥 on @2020 12 | */ 13 | public class ElementFriendUser { 14 | 15 | private Pane pane; // 用户底板(存储用户ID) 16 | 17 | private Label headLabel; // 头像区域 18 | private Label nameLabel; // 名称区域 19 | 20 | public ElementFriendUser(String userId, String userNickName, String userHead){ 21 | // 用户底板(存储用户ID) 22 | pane = new Pane(); 23 | pane.setId(userId); 24 | pane.setPrefWidth(250); 25 | pane.setPrefHeight(70); 26 | pane.getStyleClass().add("elementFriendUser"); 27 | ObservableList children = pane.getChildren(); 28 | // 头像区域 29 | headLabel = new Label(); 30 | headLabel.setPrefSize(50, 50); 31 | headLabel.setLayoutX(15); 32 | headLabel.setLayoutY(10); 33 | headLabel.getStyleClass().add("elementFriendUser_head"); 34 | headLabel.setStyle(String.format("-fx-background-image: url('/fxml/chat/img/head/%s.png')", userHead)); 35 | children.add(headLabel); 36 | // 名称区域 37 | nameLabel = new Label(); 38 | nameLabel.setPrefSize(200, 40); 39 | nameLabel.setLayoutX(80); 40 | nameLabel.setLayoutY(15); 41 | nameLabel.setText(userNickName); 42 | nameLabel.getStyleClass().add("elementFriendUser_name"); 43 | children.add(nameLabel); 44 | } 45 | 46 | public Pane pane() { 47 | return pane; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/chat/element/group_bar_friend/ElementFriendUserList.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.chat.element.group_bar_friend; 2 | 3 | import javafx.collections.ObservableList; 4 | import javafx.scene.Node; 5 | import javafx.scene.control.ListView; 6 | import javafx.scene.layout.Pane; 7 | 8 | /** 9 | * 博 客:http://bugstack.cn 10 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 11 | * create by 小傅哥 on @2020 12 | * 13 | * 组件;好友集合框体 14 | */ 15 | public class ElementFriendUserList { 16 | 17 | private Pane pane; 18 | private ListView userListView; // 好友列表 19 | 20 | public ElementFriendUserList(){ 21 | pane = new Pane(); 22 | pane.setId("friendUserList"); 23 | pane.setPrefWidth(314); 24 | pane.setPrefHeight(0);// 自动计算;userListView.setPrefHeight(70 * items.size() + 10); 25 | pane.setLayoutX(-10); 26 | pane.getStyleClass().add("elementFriendUserList"); 27 | ObservableList children = pane.getChildren(); 28 | 29 | userListView = new ListView<>(); 30 | userListView.setId("userListView"); 31 | userListView.setPrefWidth(314); 32 | userListView.setPrefHeight(0); // 自动计算;userListView.setPrefHeight(70 * items.size() + 10); 33 | userListView.setLayoutX(-10); 34 | userListView.getStyleClass().add("elementFriendUser_listView"); 35 | children.add(userListView); 36 | } 37 | 38 | public Pane pane() { 39 | return pane; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/face/FaceController.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.face; 2 | 3 | import org.itstack.naive.chat.ui.view.UIObject; 4 | import org.itstack.naive.chat.ui.view.chat.ChatInit; 5 | import org.itstack.naive.chat.ui.view.chat.IChatEvent; 6 | import org.itstack.naive.chat.ui.view.chat.IChatMethod; 7 | 8 | /** 9 | * 微信公众号:bugstack虫洞栈 | 欢迎关注学习专题案例 10 | * 论坛:http://bugstack.cn 11 | * Create by 小傅哥 on @2019 12 | */ 13 | public class FaceController extends FaceInit implements IFaceMethod { 14 | 15 | private FaceView faceView; 16 | 17 | public FaceController(UIObject obj, ChatInit chatInit, IChatEvent chatEvent, IChatMethod chatMethod) { 18 | super(obj); 19 | this.chatInit = chatInit; 20 | this.chatEvent = chatEvent; 21 | this.chatMethod = chatMethod; 22 | } 23 | 24 | @Override 25 | public void initView() { 26 | faceView = new FaceView(this); 27 | } 28 | 29 | @Override 30 | public void initEventDefine() { 31 | new FaceEventDefine(this); 32 | } 33 | 34 | @Override 35 | public void doShowFace(Double x, Double y) { 36 | setX(x + 230 * (1 - 0.618)); // 设置位置X 37 | setY(y - 160); // 设置位置Y 38 | show(); // 展示窗口 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/face/FaceEventDefine.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.face; 2 | 3 | import javafx.scene.Node; 4 | 5 | /** 6 | * 微信公众号:bugstack虫洞栈 | 欢迎关注学习专题案例 7 | * 论坛:http://bugstack.cn 8 | * Create by 小傅哥 on @2019 9 | */ 10 | public class FaceEventDefine { 11 | 12 | private FaceInit faceInit; 13 | 14 | public FaceEventDefine(FaceInit faceInit) { 15 | this.faceInit = faceInit; 16 | 17 | hideFace(); 18 | } 19 | 20 | private void hideFace(){ 21 | faceInit.root().setOnMouseExited(event -> { 22 | faceInit.hide(); 23 | }); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/face/FaceInit.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.face; 2 | 3 | import javafx.fxml.FXMLLoader; 4 | import javafx.scene.Parent; 5 | import javafx.scene.Scene; 6 | import javafx.scene.layout.Pane; 7 | import javafx.scene.paint.Color; 8 | import javafx.stage.Modality; 9 | import javafx.stage.StageStyle; 10 | import org.itstack.naive.chat.ui.view.UIObject; 11 | import org.itstack.naive.chat.ui.view.chat.ChatInit; 12 | import org.itstack.naive.chat.ui.view.chat.IChatEvent; 13 | import org.itstack.naive.chat.ui.view.chat.IChatMethod; 14 | 15 | import java.io.IOException; 16 | 17 | /** 18 | * 微信公众号:bugstack虫洞栈 | 欢迎关注学习专题案例 19 | * 论坛:http://bugstack.cn 20 | * Create by 小傅哥 on @2019 21 | */ 22 | public abstract class FaceInit extends UIObject { 23 | 24 | private static final String RESOURCE_NAME = "/fxml/face/face.fxml"; 25 | 26 | public Pane rootPane; 27 | 28 | public ChatInit chatInit; 29 | public IChatEvent chatEvent; 30 | public IChatMethod chatMethod; 31 | 32 | FaceInit(final UIObject obj) { 33 | try { 34 | root = FXMLLoader.load(getClass().getResource(RESOURCE_NAME)); 35 | } catch (IOException e) { 36 | e.printStackTrace(); 37 | } 38 | Scene scene = new Scene(root); 39 | scene.setFill(Color.TRANSPARENT); 40 | setScene(scene); 41 | initStyle(StageStyle.TRANSPARENT); 42 | setResizable(false); 43 | // 模态窗口 44 | initModality(Modality.APPLICATION_MODAL); 45 | initOwner(obj); 46 | // 初始化页面&事件 47 | obtain(); 48 | initView(); 49 | initEventDefine(); 50 | } 51 | 52 | private void obtain() { 53 | rootPane = $("face", Pane.class); 54 | } 55 | 56 | public Parent root(){ 57 | return super.root; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/face/FaceView.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.face; 2 | 3 | 4 | import javafx.collections.ObservableList; 5 | import javafx.scene.Node; 6 | import javafx.scene.control.Label; 7 | import javafx.scene.control.ListView; 8 | import javafx.scene.control.MultipleSelectionModel; 9 | import javafx.scene.layout.Pane; 10 | import org.itstack.naive.chat.ui.view.chat.data.TalkBoxData; 11 | 12 | import java.util.Date; 13 | 14 | /** 15 | * 微信公众号:bugstack虫洞栈 | 欢迎关注学习专题案例 16 | * 论坛:http://bugstack.cn 17 | * Create by 小傅哥 on @2019 18 | */ 19 | public class FaceView { 20 | 21 | private FaceInit faceInit; 22 | 23 | public FaceView(FaceInit faceInit) { 24 | this.faceInit = faceInit; 25 | // 初始化表情 26 | initFaces(); 27 | } 28 | 29 | // 初始化表情 30 | private void initFaces() { 31 | 32 | Pane rootPane = faceInit.rootPane; 33 | ObservableList children = rootPane.getChildren(); 34 | 35 | Label f01 = new Label(); 36 | f01.setUserData("f_01"); 37 | f01.setLayoutX(20); 38 | f01.setLayoutY(20); 39 | f01.setPrefWidth(30); 40 | f01.setPrefHeight(30); 41 | f01.setStyle("-fx-background-image: url('/fxml/face/img/f_01.png')"); 42 | f01.getStyleClass().add("look"); 43 | 44 | Label f02 = new Label(); 45 | f02.setUserData("f_02"); 46 | f02.setLayoutX(60); 47 | f02.setLayoutY(20); 48 | f02.setPrefWidth(30); 49 | f02.setPrefHeight(30); 50 | f02.setStyle("-fx-background-image: url('/fxml/face/img/f_02.png')"); 51 | f02.getStyleClass().add("look"); 52 | 53 | Label f03 = new Label(); 54 | f03.setUserData("f_03"); 55 | f03.setLayoutX(100); 56 | f03.setLayoutY(20); 57 | f03.setPrefWidth(30); 58 | f03.setPrefHeight(30); 59 | f03.setStyle("-fx-background-image: url('/fxml/face/img/f_03.png')"); 60 | f03.getStyleClass().add("look"); 61 | 62 | Label f04 = new Label(); 63 | f04.setUserData("f_04"); 64 | f04.setLayoutX(140); 65 | f04.setLayoutY(20); 66 | f04.setPrefWidth(30); 67 | f04.setPrefHeight(30); 68 | f04.setStyle("-fx-background-image: url('/fxml/face/img/f_04.png')"); 69 | f04.getStyleClass().add("look"); 70 | 71 | Label f05 = new Label(); 72 | f05.setUserData("f_05"); 73 | f05.setLayoutX(180); 74 | f05.setLayoutY(20); 75 | f05.setPrefWidth(30); 76 | f05.setPrefHeight(30); 77 | f05.setStyle("-fx-background-image: url('/fxml/face/img/f_05.png')"); 78 | f05.getStyleClass().add("look"); 79 | 80 | Label f11 = new Label(); 81 | f11.setUserData("f_11"); 82 | f11.setLayoutX(20); 83 | f11.setLayoutY(70); 84 | f11.setPrefWidth(30); 85 | f11.setPrefHeight(30); 86 | f11.setStyle("-fx-background-image: url('/fxml/face/img/f_11.png')"); 87 | f11.getStyleClass().add("look"); 88 | 89 | Label f12 = new Label(); 90 | f12.setUserData("f_12"); 91 | f12.setLayoutX(60); 92 | f12.setLayoutY(70); 93 | f12.setPrefWidth(30); 94 | f12.setPrefHeight(30); 95 | f12.setStyle("-fx-background-image: url('/fxml/face/img/f_12.png')"); 96 | f12.getStyleClass().add("look"); 97 | 98 | Label f13 = new Label(); 99 | f13.setUserData("f_13"); 100 | f13.setLayoutX(100); 101 | f13.setLayoutY(70); 102 | f13.setPrefWidth(30); 103 | f13.setPrefHeight(30); 104 | f13.setStyle("-fx-background-image: url('/fxml/face/img/f_13.png')"); 105 | f13.getStyleClass().add("look"); 106 | 107 | Label f14 = new Label(); 108 | f14.setUserData("f_14"); 109 | f14.setLayoutX(140); 110 | f14.setLayoutY(70); 111 | f14.setPrefWidth(30); 112 | f14.setPrefHeight(30); 113 | f14.setStyle("-fx-background-image: url('/fxml/face/img/f_14.png')"); 114 | f14.getStyleClass().add("look"); 115 | 116 | Label f15 = new Label(); 117 | f15.setUserData("f_15"); 118 | f15.setLayoutX(180); 119 | f15.setLayoutY(70); 120 | f15.setPrefWidth(30); 121 | f15.setPrefHeight(30); 122 | f15.setStyle("-fx-background-image: url('/fxml/face/img/f_15.png')"); 123 | f15.getStyleClass().add("look"); 124 | 125 | Label f21 = new Label(); 126 | f21.setUserData("f_21"); 127 | f21.setLayoutX(20); 128 | f21.setLayoutY(120); 129 | f21.setPrefWidth(30); 130 | f21.setPrefHeight(30); 131 | f21.setStyle("-fx-background-image: url('/fxml/face/img/f_21.png')"); 132 | f21.getStyleClass().add("look"); 133 | 134 | Label f22 = new Label(); 135 | f22.setUserData("f_22"); 136 | f22.setLayoutX(60); 137 | f22.setLayoutY(120); 138 | f22.setPrefWidth(30); 139 | f22.setPrefHeight(30); 140 | f22.setStyle("-fx-background-image: url('/fxml/face/img/f_22.png')"); 141 | f22.getStyleClass().add("look"); 142 | 143 | Label f23 = new Label(); 144 | f23.setUserData("f_23"); 145 | f23.setLayoutX(100); 146 | f23.setLayoutY(120); 147 | f23.setPrefWidth(30); 148 | f23.setPrefHeight(30); 149 | f23.setStyle("-fx-background-image: url('/fxml/face/img/f_23.png')"); 150 | f23.getStyleClass().add("look"); 151 | 152 | Label f24 = new Label(); 153 | f24.setUserData("f_24"); 154 | f24.setLayoutX(140); 155 | f24.setLayoutY(120); 156 | f24.setPrefWidth(30); 157 | f24.setPrefHeight(30); 158 | f24.setStyle("-fx-background-image: url('/fxml/face/img/f_24.png')"); 159 | f24.getStyleClass().add("look"); 160 | 161 | Label f25 = new Label(); 162 | f25.setUserData("f_25"); 163 | f25.setLayoutX(180); 164 | f25.setLayoutY(120); 165 | f25.setPrefWidth(30); 166 | f25.setPrefHeight(30); 167 | f25.setStyle("-fx-background-image: url('/fxml/face/img/f_25.png')"); 168 | f25.getStyleClass().add("look"); 169 | 170 | children.addAll(f01, f02, f03, f04, f05, f11, f12, f13, f14, f15, f21, f22, f23, f24, f25); 171 | 172 | for (Node next : children) { 173 | next.setOnMouseClicked(event -> { 174 | MultipleSelectionModel selectionModel = faceInit.chatInit.$("talkList", ListView.class).getSelectionModel(); 175 | Pane selectedItem = (Pane) selectionModel.getSelectedItem(); 176 | // 对话信息 177 | TalkBoxData talkBoxData = (TalkBoxData) selectedItem.getUserData(); 178 | Date msgDate = new Date(); 179 | String faceId = (String) next.getUserData(); 180 | faceInit.chatMethod.addTalkMsgRight(talkBoxData.getTalkId(), faceId, 1, msgDate, true, true, false); 181 | // 发送消息 182 | faceInit.chatEvent.doSendMsg(faceInit.chatInit.userId, talkBoxData.getTalkId(), talkBoxData.getTalkType(), faceId, 1, msgDate); 183 | }); 184 | } 185 | 186 | } 187 | 188 | } 189 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/face/IFaceMethod.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.face; 2 | 3 | /** 4 | * 微信公众号:bugstack虫洞栈 | 欢迎关注学习专题案例 5 | * 论坛:http://bugstack.cn 6 | * Create by 小傅哥 on @2019 7 | */ 8 | public interface IFaceMethod { 9 | 10 | void doShowFace(Double x, Double y); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/login/ILoginEvent.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.login; 2 | 3 | /** 4 | * 博 客:http://bugstack.cn 5 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 6 | * create by 小傅哥 on @2020 7 | * 8 | * 登陆窗口实现,外部给予实现 9 | */ 10 | public interface ILoginEvent { 11 | 12 | /** 13 | * 登陆验证 14 | * @param userId 用户ID 15 | * @param userPassword 用户密码 16 | */ 17 | void doLoginCheck(String userId, String userPassword); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/login/ILoginMethod.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.login; 2 | 3 | /** 4 | * 博 客:http://bugstack.cn 5 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 6 | * create by 付政委 on @2020 7 | *

8 | * 窗口方法,给予外部调用 9 | */ 10 | public interface ILoginMethod { 11 | 12 | /** 13 | * 打开登陆窗口 14 | */ 15 | void doShow(); 16 | 17 | /** 18 | * 登陆失败 19 | */ 20 | void doLoginError(); 21 | 22 | /** 23 | * 登陆成功;跳转聊天窗口[关闭登陆窗口,打开新窗口] 24 | */ 25 | void doLoginSuccess(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/login/LoginController.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.login; 2 | 3 | import org.itstack.naive.chat.ui.view.chat.IChatMethod; 4 | 5 | /** 6 | * 博 客:http://bugstack.cn 7 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 8 | * create by 小傅哥 on @2020 9 | */ 10 | public class LoginController extends LoginInit implements ILoginMethod { 11 | 12 | private IChatMethod chat; 13 | private LoginView loginView; 14 | private LoginEventDefine loginEventDefine; 15 | 16 | public LoginController(ILoginEvent loginEvent, IChatMethod chat) { 17 | super(loginEvent); 18 | this.chat = chat; 19 | } 20 | 21 | @Override 22 | public void initView() { 23 | loginView = new LoginView(this, loginEvent); 24 | } 25 | 26 | @Override 27 | public void initEventDefine() { 28 | loginEventDefine = new LoginEventDefine(this, loginEvent, this); 29 | } 30 | 31 | @Override 32 | public void doShow() { 33 | super.show(); 34 | } 35 | 36 | @Override 37 | public void doLoginError() { 38 | // TODO 登陆失败提示 39 | } 40 | 41 | @Override 42 | public void doLoginSuccess() { 43 | // 关闭原窗口 44 | close(); 45 | // 打开聊天窗口 46 | chat.doShow(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/login/LoginEventDefine.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.login; 2 | 3 | /** 4 | * 博 客:http://bugstack.cn 5 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 6 | * create by 小傅哥 on @2020 7 | */ 8 | public class LoginEventDefine { 9 | 10 | private LoginInit loginInit; 11 | private ILoginEvent loginEvent; 12 | private ILoginMethod loginMethod; 13 | 14 | public LoginEventDefine(LoginInit loginInit, ILoginEvent loginEvent, ILoginMethod loginMethod) { 15 | this.loginInit = loginInit; 16 | this.loginEvent = loginEvent; 17 | this.loginMethod = loginMethod; 18 | 19 | loginInit.move(); 20 | min(); 21 | quit(); 22 | doEventLogin(); 23 | } 24 | 25 | // 事件;最小化 26 | private void min() { 27 | loginInit.login_min.setOnAction(event -> { 28 | loginInit.setIconified(true); 29 | }); 30 | } 31 | 32 | // 事件;退出 33 | private void quit() { 34 | loginInit.login_close.setOnAction(event -> { 35 | loginInit.close(); 36 | System.exit(0); 37 | }); 38 | } 39 | 40 | // 事件;登陆 41 | private void doEventLogin() { 42 | loginInit.login_button.setOnAction(event -> { 43 | loginEvent.doLoginCheck(loginInit.userId.getText(), loginInit.userPassword.getText()); 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/login/LoginInit.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.login; 2 | 3 | import javafx.fxml.FXMLLoader; 4 | import javafx.scene.Scene; 5 | import javafx.scene.control.Button; 6 | import javafx.scene.control.PasswordField; 7 | import javafx.scene.control.TextField; 8 | import javafx.scene.image.Image; 9 | import javafx.scene.paint.Color; 10 | import javafx.stage.StageStyle; 11 | import org.itstack.naive.chat.ui.view.UIObject; 12 | 13 | import java.io.IOException; 14 | 15 | /** 16 | * 博 客:http://bugstack.cn 17 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 18 | * create by 小傅哥 on @2020 19 | */ 20 | public abstract class LoginInit extends UIObject { 21 | 22 | private static final String RESOURCE_NAME = "/fxml/login/login.fxml"; 23 | 24 | protected ILoginEvent loginEvent; 25 | 26 | public Button login_min; // 登陆窗口最小化 27 | public Button login_close; // 登陆窗口退出 28 | public Button login_button; // 登陆按钮 29 | public TextField userId; // 用户账户窗口 30 | public PasswordField userPassword;// 用户密码窗口 31 | 32 | LoginInit(ILoginEvent loginEvent) { 33 | this.loginEvent = loginEvent; 34 | try { 35 | root = FXMLLoader.load(getClass().getResource(RESOURCE_NAME)); 36 | } catch (IOException e) { 37 | e.printStackTrace(); 38 | } 39 | Scene scene = new Scene(root); 40 | scene.setFill(Color.TRANSPARENT); 41 | setScene(scene); 42 | initStyle(StageStyle.TRANSPARENT); 43 | setResizable(false); 44 | this.getIcons().add(new Image("/fxml/chat/img/head/logo.png")); 45 | obtain(); 46 | initView(); 47 | initEventDefine(); 48 | } 49 | 50 | private void obtain() { 51 | login_min = $("login_min", Button.class); 52 | login_close = $("login_close", Button.class); 53 | login_button = $("login_button", Button.class); 54 | userId = $("userId", TextField.class); 55 | userPassword = $("userPassword", PasswordField.class); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/org/itstack/naive/chat/ui/view/login/LoginView.java: -------------------------------------------------------------------------------- 1 | package org.itstack.naive.chat.ui.view.login; 2 | 3 | /** 4 | * 博 客:http://bugstack.cn 5 | * 公众号:bugstack虫洞栈 | 沉淀、分享、成长,让自己和他人都能有所收获! 6 | * create by 小傅哥 on @2020 7 | * 8 | * 页面展示元素和事件定义 9 | */ 10 | public class LoginView { 11 | 12 | private LoginInit loginInit; 13 | private ILoginEvent loginEvent; 14 | 15 | public LoginView(LoginInit loginInit, ILoginEvent loginEvent) { 16 | this.loginInit = loginInit; 17 | this.loginEvent = loginEvent; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/main/resources/fxml/chat/chat.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 |