|
|
@ -61,6 +61,8 @@ import javafx.scene.input.DataFormat |
|
|
|
import wow.doge.chatto.control.MessageBox |
|
|
|
import javafx.scene.control.SelectionMode |
|
|
|
import scalafx.beans.property.BooleanProperty |
|
|
|
import javafx.scene.control.ListCell |
|
|
|
import java.time.Instant |
|
|
|
|
|
|
|
class ChatController @Inject() ( |
|
|
|
userService: UserService, |
|
|
@ -76,14 +78,14 @@ class ChatController @Inject() ( |
|
|
|
// @FXML private var chatTextArea: TextArea = _ |
|
|
|
@FXML private var chatInput: TextArea = _ |
|
|
|
@FXML private var usersVBox: VBox = _ |
|
|
|
@FXML var usersListView: JFXListView[UserBox2] = _ |
|
|
|
@FXML var chatListView: JFXListView[MessageBox] = _ |
|
|
|
@FXML var usersListView: JFXListView[ActiveUser] = _ |
|
|
|
@FXML var chatListView: JFXListView[Message] = _ |
|
|
|
@FXML private var curUsr: Label = _ |
|
|
|
@FXML private var lastActiveLabel: Label = _ |
|
|
|
@FXML private var isOnlineLabel: Label = _ |
|
|
|
@FXML private var selectedUserBox: HBox = _ |
|
|
|
|
|
|
|
private val usersBuffer = ObservableBuffer.empty[UserBox2] |
|
|
|
private val usersBuffer = ObservableBuffer.empty[ActiveUser] |
|
|
|
private val usersListProperty = BufferProperty(usersBuffer) |
|
|
|
|
|
|
|
/** |
|
|
@ -91,7 +93,7 @@ class ChatController @Inject() ( |
|
|
|
* Synchronized with the internal users list property. |
|
|
|
* Attemping to modify the internal list will throw an exception |
|
|
|
*/ |
|
|
|
val usersListROProp: ReadOnlyListProperty[UserBox2] = BufferProperty( |
|
|
|
val usersListROProp: ReadOnlyListProperty[ActiveUser] = BufferProperty( |
|
|
|
FXCollections.unmodifiableObservableList(usersListProperty()) |
|
|
|
) |
|
|
|
|
|
|
@ -103,7 +105,9 @@ class ChatController @Inject() ( |
|
|
|
super.didGainVisibilityFirstTime() |
|
|
|
this.stage.resizable = true |
|
|
|
chatMainPane.hgrow = Priority.ALWAYS |
|
|
|
|
|
|
|
chatListView.selectionModel().selectionMode = SelectionMode.MULTIPLE |
|
|
|
chatListView.setCellFactory(_ => new ChatListCell()) |
|
|
|
|
|
|
|
chatDataAdapter.set(FXBean(ChatData.empty)) |
|
|
|
|
|
|
@ -114,6 +118,8 @@ class ChatController @Inject() ( |
|
|
|
.isNull() |
|
|
|
}) |
|
|
|
|
|
|
|
// usersListView2.setCellFactory(lv => {}) |
|
|
|
|
|
|
|
// curUserKeys.add("content", "${_self.data().content()}") |
|
|
|
val chatDataAdapterKeys = KeyBindings() |
|
|
|
chatDataAdapterKeys.add("currentUser", "${_self.userName()}") |
|
|
@ -134,7 +140,7 @@ class ChatController @Inject() ( |
|
|
|
.addListener((_, _, newValue) => { |
|
|
|
Option(newValue).foreach(nv => { |
|
|
|
val maybeCDP = chatDataStore |
|
|
|
.get(nv.username) |
|
|
|
.get(nv.userName) |
|
|
|
val chatDataBean = maybeCDP |
|
|
|
.map(_.bean) |
|
|
|
.getOrElse { |
|
|
@ -143,9 +149,9 @@ class ChatController @Inject() ( |
|
|
|
} |
|
|
|
chatDataAdapter.set(chatDataBean) |
|
|
|
maybeCDP.foreach(cdp => { |
|
|
|
// lastActiveLabel.text <== cdp.lastActive |
|
|
|
lastActiveLabel.text <== cdp.lastActive |
|
|
|
isOnlineLabel.text <== cdp.isActive.asString() |
|
|
|
chatListView.items <== cdp.messageBubbles |
|
|
|
chatListView.items <== cdp.messages |
|
|
|
}) |
|
|
|
}) |
|
|
|
}) |
|
|
@ -155,32 +161,12 @@ class ChatController @Inject() ( |
|
|
|
new KeyCodeCombination(KeyCode.C, KeyCombination.ControlDown) |
|
|
|
copyMessageMenuItem.onAction = _ => { |
|
|
|
val content = new ClipboardContent() |
|
|
|
val x = chatListView.getSelectionModel().getSelectedItems().map(_.message) |
|
|
|
// chatListView.selectionModel().selectedItem().message |
|
|
|
Option(x).foreach(message => { |
|
|
|
content.putString(message.mkString("\n")) |
|
|
|
Clipboard.getSystemClipboard().setContent(content) |
|
|
|
}) |
|
|
|
// val message = cdp.messageList(selectedIndex) |
|
|
|
|
|
|
|
// val maybeCDP = chatDataStore.get(chatDataAdapter.get.bean.userName) |
|
|
|
// maybeCDP.foreach(cdp => { |
|
|
|
// // val message = Option(cdp.messageList().get(selectedIndex)).toRight { |
|
|
|
// // "Unexpected error - message not found" |
|
|
|
// // } |
|
|
|
// // message.map(msg => { |
|
|
|
// // // content.putString(msg) |
|
|
|
// // // clipboard.setContent(content) |
|
|
|
// // // val content = clipboard.content |
|
|
|
// // // content.putString(msg) |
|
|
|
// // // clipboard.content = content |
|
|
|
// // clipboard.putString(msg) |
|
|
|
// // }) |
|
|
|
// // message.left.map(err => logger.error(err)) |
|
|
|
// }) |
|
|
|
val messages = chatListView.selectionModel().selectedItems.map(_.message) |
|
|
|
content.putString(messages.mkString("\n")) |
|
|
|
Clipboard.getSystemClipboard().setContent(content) |
|
|
|
} |
|
|
|
val chatListMenu = new ContextMenu() |
|
|
|
|
|
|
|
val chatListMenu = new ContextMenu() |
|
|
|
chatListMenu.items += copyMessageMenuItem |
|
|
|
chatListView.contextMenu = chatListMenu |
|
|
|
|
|
|
@ -191,19 +177,18 @@ class ChatController @Inject() ( |
|
|
|
submitButton.disable <== validator.containsErrorsProperty() |
|
|
|
|
|
|
|
submitButton.onAction = (e) => { |
|
|
|
// val msgBox = ChatDataProperty.createMdMessageBox2(chatInput.text()) |
|
|
|
// chatListView.items() += msgBox |
|
|
|
if (!chatInput.text().equals("") && |
|
|
|
!chatInput.text().equals(" ") && |
|
|
|
!chatInput.text().equals("\n")) { |
|
|
|
val maybeCDP = chatDataStore.get(chatDataAdapter.get.bean.userName) |
|
|
|
|
|
|
|
maybeCDP.foreach(cdp => { |
|
|
|
cdp.messageBubbles += ChatDataProperty.createMdMessageBox3( |
|
|
|
appDataHandler.appData.credentials.username, |
|
|
|
cdp.username(), |
|
|
|
chatInput.text() |
|
|
|
) |
|
|
|
// cdp.messageBubbles += ChatDataProperty.createMdMessageBox3( |
|
|
|
// appDataHandler.appData.credentials.username, |
|
|
|
// cdp.username(), |
|
|
|
// chatInput.text() |
|
|
|
// ) |
|
|
|
cdp.messages += Message.empty.copy(message = chatInput.text()) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
@ -236,49 +221,44 @@ class ChatController @Inject() ( |
|
|
|
val maybeUserBoxes = maybeActiveUsers.map(users => { |
|
|
|
users.map(user => { |
|
|
|
val chatData = |
|
|
|
ChatData(user.userName, user, ObservableBuffer.empty[String]) |
|
|
|
ChatData(user.userName, user, ObservableBuffer.empty[Message]) |
|
|
|
chatDataStore.put(user.userName, new ChatDataProperty(chatData)) |
|
|
|
new UserBox2(user.userName, chatData) { |
|
|
|
this.styleClass ++= Seq("text-white") |
|
|
|
} |
|
|
|
}) |
|
|
|
}) |
|
|
|
val messageBox = ChatDataProperty.createMdMessageBox2( |
|
|
|
"""**Hello world qefwew yeeehay bwergqwevqcqe** |
|
|
|
|**Hello world qefwew yeeehay bwergqwevqcqe** |
|
|
|
| |
|
|
|
| Hello World |
|
|
|
""".stripMargin |
|
|
|
) |
|
|
|
// val messageBox = ChatDataProperty.createMdMessageBox2( |
|
|
|
// """**Hello world qefwew yeeehay bwergqwevqcqe** |
|
|
|
// |**Hello world qefwew yeeehay bwergqwevqcqe** |
|
|
|
// | |
|
|
|
// | Hello World |
|
|
|
// """.stripMargin |
|
|
|
// ) |
|
|
|
onFX { |
|
|
|
maybeUserBoxes.foreach(userBoxes => { |
|
|
|
usersBuffer ++= userBoxes |
|
|
|
}) |
|
|
|
// maybeUserBoxes.foreach(userBoxes => { |
|
|
|
// usersBuffer ++= userBoxes |
|
|
|
// }) |
|
|
|
maybeActiveUsers.foreach(users => usersBuffer ++= users) |
|
|
|
chatListView.items() ++= Seq( |
|
|
|
messageBox, |
|
|
|
ChatDataProperty.createMdMessageBox2("hello"), |
|
|
|
ChatDataProperty.createMdMessageBox2( |
|
|
|
""" 1. Hello world qefwew yeeehay bwergqwevqcqe |
|
|
|
|1. Hello world qefwew yeeehay bwergqwevqcqe |
|
|
|
|1. Hello world qefwew yeeehay bwergqwevqcqe |
|
|
|
|1. Hello world qefwew yeeehay bwergqwevqcqe""".stripMargin |
|
|
|
) |
|
|
|
// messageBox, |
|
|
|
// ChatDataProperty.createMdMessageBox2("hello"), |
|
|
|
// ChatDataProperty.createMdMessageBox2( |
|
|
|
// """ 1. Hello world qefwew yeeehay bwergqwevqcqe |
|
|
|
// |1. Hello world qefwew yeeehay bwergqwevqcqe |
|
|
|
// |1. Hello world qefwew yeeehay bwergqwevqcqe |
|
|
|
// |1. Hello world qefwew yeeehay bwergqwevqcqe""".stripMargin |
|
|
|
// ) |
|
|
|
) |
|
|
|
// .map(node => { |
|
|
|
// node.prefWidthProperty <== (chatListView.prefWidthProperty - 200) |
|
|
|
// node |
|
|
|
// }) |
|
|
|
// JFXSmoothScroll.smoothScrollingListView(chatListView, 0.1) |
|
|
|
} |
|
|
|
chatDataStore |
|
|
|
.map { case (key, value) => value } |
|
|
|
.foreach(cdp => { |
|
|
|
cdp.messageBubbles ++= Seq( |
|
|
|
ChatDataProperty.createMdMessageBox2("hi"), |
|
|
|
ChatDataProperty.createMdMessageBox2("hello"), |
|
|
|
ChatDataProperty.createMdMessageBox2("bye") |
|
|
|
cdp.messages ++= Seq( |
|
|
|
Message.empty.copy(message = "hi"), |
|
|
|
Message.empty.copy(message = "hello"), |
|
|
|
Message.empty.copy(message = "bye") |
|
|
|
) |
|
|
|
// .map(ChatDataProperty.createMdMessageBox) |
|
|
|
}) |
|
|
|
} |
|
|
|
} |
|
|
@ -304,21 +284,12 @@ class ChatController @Inject() ( |
|
|
|
this.stage.maximized = false |
|
|
|
applicationController.logout() |
|
|
|
} |
|
|
|
|
|
|
|
implicit class MyClipboardExtension(clipboard: Clipboard) { |
|
|
|
def putString(string: String) = { |
|
|
|
// val content = Option(clipboard.getContent(DataFormat.PLAIN_TEXT)) |
|
|
|
// .getOrElse(new ClipboardContent()) |
|
|
|
// content.putString(string) |
|
|
|
// clipboard.setContent(content) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
final case class ChatData( |
|
|
|
userName: String, |
|
|
|
activeUser: ActiveUser, |
|
|
|
messages: ObservableBuffer[String] |
|
|
|
messages: ObservableBuffer[Message] |
|
|
|
) { |
|
|
|
lazy val lastActiveString = |
|
|
|
activeUser.lastActive |
|
|
@ -328,69 +299,33 @@ final case class ChatData( |
|
|
|
} |
|
|
|
object ChatData { |
|
|
|
def empty = { |
|
|
|
ChatData("empty", ActiveUser.empty, ObservableBuffer.empty[String]) |
|
|
|
ChatData("empty", ActiveUser.empty, ObservableBuffer.empty[Message]) |
|
|
|
} |
|
|
|
} |
|
|
|
class ChatDataProperty(chatData: ChatData) { |
|
|
|
import ChatDataProperty._ |
|
|
|
val bean = FXBean(chatData) |
|
|
|
val username = bean.getStringProperty("userName") |
|
|
|
val isActive = bean.getBooleanProperty("activeUser.online") |
|
|
|
val lastActive = bean.getStringProperty("lastActiveString") |
|
|
|
lazy val messageBubbles = BufferProperty( |
|
|
|
chatData.messages.map(ChatDataProperty.createMdMessageBox2) |
|
|
|
) |
|
|
|
def messageList = messageBubbles().map(_.message) |
|
|
|
// lazy val messages = messagesBubbleProperty |
|
|
|
// .get() |
|
|
|
// .map(_.messageText) |
|
|
|
val messages = BufferProperty(chatData.messages) |
|
|
|
} |
|
|
|
object ChatDataProperty { |
|
|
|
|
|
|
|
final case class Message( |
|
|
|
fromUser: String, |
|
|
|
toUser: String, |
|
|
|
message: String, |
|
|
|
messageTime: Instant |
|
|
|
) |
|
|
|
object Message { |
|
|
|
lazy val markdownStyleSheet = |
|
|
|
getClass().getResource("/styles/markdown.css").toExternalForm() |
|
|
|
|
|
|
|
def createMdMessageBox(mdfxText: String) = { |
|
|
|
val mdfxNode = new BubbledMDFXNode(mdfxText); |
|
|
|
mdfxNode |
|
|
|
.getStylesheets() |
|
|
|
.add(markdownStyleSheet); |
|
|
|
mdfxNode.setBubbleSpec(BubbleSpec.FACE_RIGHT_CENTER); |
|
|
|
mdfxNode.setBackground( |
|
|
|
new Background(new BackgroundFill(Color.LIGHTSTEELBLUE, null, null)) |
|
|
|
); |
|
|
|
val box = new HBox(); |
|
|
|
mdfxNode.setMinWidth(100.0); |
|
|
|
box.setAlignment(Pos.TOP_RIGHT); |
|
|
|
box.children += mdfxNode; |
|
|
|
box |
|
|
|
} |
|
|
|
def empty = Message("", "", "", Instant.MIN) |
|
|
|
|
|
|
|
def createMdMessageBox2(mdfxText: String) = { |
|
|
|
val mdfxNode = new MDFXNode(mdfxText); |
|
|
|
mdfxNode |
|
|
|
.getStylesheets() |
|
|
|
.add(markdownStyleSheet) |
|
|
|
mdfxNode.setMaxWidth(500) |
|
|
|
mdfxNode.vgrow = Priority.ALWAYS |
|
|
|
mdfxNode.setAlignment(Pos.CENTER) |
|
|
|
mdfxNode.styleClass = Seq("chat-message-box") |
|
|
|
|
|
|
|
val box = new MessageBox("", "", mdfxText) |
|
|
|
box.setAlignment(Pos.CENTER_RIGHT) |
|
|
|
// box.maxWidth(500) |
|
|
|
box.hgrow = Priority.ALWAYS |
|
|
|
box.vgrow = Priority.ALWAYS |
|
|
|
box.children ++= Seq(mdfxNode) |
|
|
|
box.fillHeight = true |
|
|
|
box |
|
|
|
} |
|
|
|
|
|
|
|
def createMdMessageBox3( |
|
|
|
sender: String, |
|
|
|
receiver: String, |
|
|
|
mdfxText: String |
|
|
|
def createMdMessageBox( |
|
|
|
message: Message |
|
|
|
) = { |
|
|
|
val mdfxNode = new MDFXNode(mdfxText); |
|
|
|
val mdfxNode = new MDFXNode(message.message); |
|
|
|
mdfxNode |
|
|
|
.getStylesheets() |
|
|
|
.add(markdownStyleSheet) |
|
|
@ -399,7 +334,7 @@ object ChatDataProperty { |
|
|
|
mdfxNode.setAlignment(Pos.CENTER) |
|
|
|
mdfxNode.styleClass = Seq("chat-message-box") |
|
|
|
|
|
|
|
val box = new MessageBox(sender, receiver, mdfxText) |
|
|
|
val box = new HBox() |
|
|
|
box.setAlignment(Pos.CENTER_RIGHT) |
|
|
|
// box.maxWidth(500) |
|
|
|
box.hgrow = Priority.ALWAYS |
|
|
@ -408,5 +343,19 @@ object ChatDataProperty { |
|
|
|
box.fillHeight = true |
|
|
|
box |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
final class ChatListCell extends ListCell[Message] { |
|
|
|
private val messageBox = new MessageBox() |
|
|
|
override def updateItem(item: Message, empty: Boolean): Unit = { |
|
|
|
super.updateItem(item, empty) |
|
|
|
if (empty || item == null) { |
|
|
|
setText(null) |
|
|
|
setGraphic(null) |
|
|
|
} else { |
|
|
|
// messageBox.setItem(item) |
|
|
|
// setGraphic(messageBox) |
|
|
|
setGraphic(Message.createMdMessageBox(item)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |