From 8402c2f59e61b6cb5ab2dca2582be53117caaeea Mon Sep 17 00:00:00 2001 From: Rohan Sircar Date: Wed, 20 May 2020 10:46:48 +0530 Subject: [PATCH] Chat data property binding implemented --- src/main/resources/fxml/Chat.fxml | 7 +- .../doge/chatto/ApplicationController.scala | 13 ++ .../wow/doge/chatto/control/UserBox2.scala | 7 +- .../chatto/controller/ChatController.scala | 171 +++++++++++++++--- .../wow/doge/chatto/service/UserService.scala | 3 +- 5 files changed, 170 insertions(+), 31 deletions(-) diff --git a/src/main/resources/fxml/Chat.fxml b/src/main/resources/fxml/Chat.fxml index 780ad91..055cb68 100644 --- a/src/main/resources/fxml/Chat.fxml +++ b/src/main/resources/fxml/Chat.fxml @@ -26,10 +26,11 @@
- + -
diff --git a/src/main/scala/wow/doge/chatto/ApplicationController.scala b/src/main/scala/wow/doge/chatto/ApplicationController.scala index a3d6fc0..6753bd5 100644 --- a/src/main/scala/wow/doge/chatto/ApplicationController.scala +++ b/src/main/scala/wow/doge/chatto/ApplicationController.scala @@ -24,6 +24,9 @@ import org.scalafx.extras._ import wow.doge.chatto.service.UserService import javax.inject._ import javafx.application.Platform +import com.sfxcode.sapphire.core.controller.SceneControllerDidChangeEvent +import javax.enterprise.event.Observes +import com.sfxcode.sapphire.core.controller.SceneControllerWillChangeEvent @Named @ApplicationScoped class ApplicationController extends DefaultWindowController { @@ -62,6 +65,16 @@ class ApplicationController extends DefaultWindowController { replaceSceneContent(newMainViewController) } + def testListener(@Observes event: SceneControllerWillChangeEvent) = { + logger.info("test success 1") + // logger.info(s"${event.newController}") + } + + def testListener2(@Observes event: SceneControllerDidChangeEvent) = { + logger.info("test success 2") + // logger.info(s"${event.newController}") + } + override def applicationWillStop(): Unit = async { super.applicationWillStop() println("stopping") diff --git a/src/main/scala/wow/doge/chatto/control/UserBox2.scala b/src/main/scala/wow/doge/chatto/control/UserBox2.scala index df0aae0..bade024 100644 --- a/src/main/scala/wow/doge/chatto/control/UserBox2.scala +++ b/src/main/scala/wow/doge/chatto/control/UserBox2.scala @@ -3,9 +3,12 @@ package wow.doge.chatto.control import javafx.scene.layout.HBox import javafx.scene.control.Label import scalafx.Includes._ +import wow.doge.chatto.controller.ChatData +import com.sfxcode.sapphire.core.value.FXBean -class UserBox2(_username: String) extends HBox() { - val usernameLabel = new Label(_username) +class UserBox2(val username: String, val chatData: ChatData) extends HBox() { + val usernameLabel = new Label(username) +// lazy val chatDataBean = FXBean[ChatData](chatData) this.children ++= Seq { usernameLabel } diff --git a/src/main/scala/wow/doge/chatto/controller/ChatController.scala b/src/main/scala/wow/doge/chatto/controller/ChatController.scala index 2abbf38..ec14a43 100644 --- a/src/main/scala/wow/doge/chatto/controller/ChatController.scala +++ b/src/main/scala/wow/doge/chatto/controller/ChatController.scala @@ -33,13 +33,20 @@ import com.sfxcode.sapphire.core.value.FXBeanAdapter import scalafx.collections.ObservableMap import com.sfxcode.sapphire.core.value.BeanConversions import javafx.util.converter.DateStringConverter +import javafx.beans.binding.Bindings +import wow.doge.chatto.service.ActiveUser +import scala.collection.mutable +import scala.collection.concurrent.TrieMap +import wow.doge.chatto.messagebuble.BubbleSpec +import javafx.scene.layout.Background +import javafx.scene.layout.BackgroundFill +import javafx.geometry.Pos class ChatController @Inject() ( userService: UserService, appDataHandler: AppDataHandler ) extends AbstractViewController - with LazyLogging - with BeanConversions { + with LazyLogging { // @FXML private var label: Label = _ @FXML private var flowPane: FlowPane = _ @@ -49,16 +56,21 @@ class ChatController @Inject() ( @FXML private var chatInput: TextArea = _ @FXML private var usersVBox: VBox = _ @FXML var usersListView: JFXListView[UserBox2] = _ - @FXML private var chatListView: JFXListView[HBox] = _ + @FXML var chatListView: JFXListView[HBox] = _ @FXML private var curUsr: Label = _ @FXML private var dataContent: Label = _ // applicationController.show - private val usersBuffer = ObservableBuffer[FXBean[User]]() - private val chatDataBuffer = ObservableMap[String, FXBean[User]]() + private val usersListProperty = new SimpleListProperty( + ObservableBuffer[UserBox2]() + ) + private val chatDataBuffer = ObservableBuffer[UserBox2]() + private val chatDataStore: mutable.Map[String, ChatDataProperty] = + TrieMap() - private lazy val curUserKeys = KeyBindings("curUser") + // private lazy val curUserKeys = KeyBindings("curUser") // bindings.add("person", "Person ${_self.name()} with age of ${_self.age()} is active: ${_self.isActive()}") - private lazy val curUserAdapter = FXBeanAdapter[User](this) + // private lazy val curUserAdapter = FXBeanAdapter[User](this) + private lazy val chatDataAdapter = FXBeanAdapter[ChatData](this) override def didGainVisibilityFirstTime(): Unit = { super.didGainVisibilityFirstTime() @@ -99,28 +111,53 @@ class ChatController @Inject() ( // .addListener((_, _, newValue) => { // curUsr.text() = newValue.usernameLabel.text() // }) - curUserKeys.add("content", "${_self.data().content()}") + // curUserKeys.add("content", "${_self.data().content()}") + val chatDataAdapterKeys = KeyBindings() + // chatDataAdapterKeys.add("currentUser", "${_self.userName()}") + // chatDataAdapterKeys.add( + // "lastActive", + // "${_self.lastActiveString()}" + // ) + // chatDataAdapterKeys.add( + // "online", + // "${_self.onlineString()}" + // ) // curUserAdapter.addDateConverter() - curUserAdapter.addBindings(curUserKeys) - + // curUserAdapter.addBindings(curUserKeys) + chatDataAdapter.addBindings(chatDataAdapterKeys) + // curUsr.text <== chatDataAdapter.beanProperty + // .getOrElse(FXBean(ChatData.empty)) + // .getStringProperty("lastActiveString") usersListView .getSelectionModel() .selectedItemProperty() .addListener((_, _, newValue) => { if (newValue != null) { - val dataBean = - FXBean(User(newValue.usernameLabel.text(), Data("test data"))) - curUserAdapter - .set(dataBean) + // val dataBean = + // FXBean(User(newValue.usernameLabel.text(), Data("test data"))) + // curUserAdapter + // .set(dataBean) + // chatDataAdapter.set(newValue.chatDataBean) + val y = chatDataStore + .get(newValue.username) + val x = y + .map(_.bean) + .getOrElse { + logger.error("Error null") + FXBean(ChatData.empty) + } + chatDataAdapter.set(x) + y.map(z => chatListView.items <== z.prop) } }) // curUsr.text <== usersListView // .getSelectionModel() // .getSelectedItem() - // .username + // .usernameLabel // .text + usersListView.items <== usersListProperty } override def didGainVisibility(): Unit = { @@ -140,7 +177,7 @@ class ChatController @Inject() ( // maybeActiveUsers.foreach(println) logger.debug(s"$maybeActiveUsers") - val maybeUsersBoxes = maybeUsers.map(users => { + val maybeUserBoxes = maybeActiveUsers.map(users => { // usersBuffer ++= users users.map(user => { // usersBuffer += FXBean(User(user)) @@ -152,7 +189,21 @@ class ChatController @Inject() ( // fill <== when(hover) choose (Color.Red) // } // val hb = new HBox - new UserBox2(user) { + val chatData = + ChatData(user.userName, user, ObservableBuffer.empty[String]) + // chatDataStore.updateWith(user.userName)(maybeCD => + // maybeCD.map(cd => { + // cd.messagesStringProperty += + // }) + // ) + chatDataStore.put(user.userName, new ChatDataProperty(chatData)) + chatDataStore + .get(user.userName) + .map(cdp => { + cdp.prop ++= Seq("hi", "hello", "bye") + .map(s => ChatDataProperty.createMdMessageBox(s)) + }) + new UserBox2(user.userName, chatData) { // this.children += new Label { // textProperty() = user // // textFillProperty <== when(this.hover) choose (Color.RED) otherwise (Color.BLUE) @@ -161,12 +212,22 @@ class ChatController @Inject() ( } }) }) + // maybeUserBoxes.map(userBoxes => { + // // chatDataBuffer ++= userBoxes + // usersListProperty ++= userBoxes + // }) + val messageBox = ChatDataProperty.createMdMessageBox("*hello!*") onFX { - maybeUsersBoxes.map(userBoxes => { - usersListView.items() ++= userBoxes - // val x = new SimpleListProperty(ObservableBuffer(userBoxes)) - // usersListView.items <== x + // maybeUserBoxes.map(userBoxes => { + // chatDataBuffer ++= userBoxes + // // usersListView.items() ++= userBoxes + // // val x = new SimpleListProperty(ObservableBuffer(userBoxes)) + // // usersListView.items <== x + // }) + maybeUserBoxes.map(userBoxes => { + usersListProperty ++= userBoxes }) + chatListView.items() += messageBox } } } @@ -177,17 +238,26 @@ class ChatController @Inject() ( x } - def actionLogout = { + def actionLogout = onFX { offFXAndWait { appDataHandler.clearCredentials() println(appDataHandler.appData) } - curUserAdapter.set(User.empty) + // curUserAdapter.set(User.empty) + chatDataAdapter.set(FXBean(ChatData.empty)) usersListView.items().clear() chatListView.items().clear() + chatDataBuffer.clear() + chatDataStore.clear() + usersListProperty.clear() applicationController.logout() println(appDataHandler.appData) } + +} +object ChatController { + lazy val markdownStyleSheet = + getClass().getResource("/styles/markdown.css").toExternalForm() } final case class Person(id: Int, age: Int, name: String) @@ -195,5 +265,58 @@ final case class Data(content: String) final case class User(curUser: String, data: Data) object User { def empty = User("", Data("")) + // Bindings.createObjectBinding() +} +// final case class ActiveUser( +// userName: String, +// online: Boolean, +// lastActive: String +// ) +// object ActiveUser { +// def empty = ActiveUser("empty", false, "empty") +// } +final case class ChatData( + userName: String, + activeUser: ActiveUser, + messages: ObservableBuffer[String] +) { + lazy val lastActiveString = + activeUser.lastActive + .map(_.toString()) + .getOrElse("User has not logged in yet") + lazy val onlineString = activeUser.online.toString() +} +object ChatData { + def empty = { + ChatData("empty", ActiveUser.empty, ObservableBuffer.empty[String]) + } +} +class ChatDataProperty(chatData: ChatData) { + import ChatDataProperty._ + val bean = FXBean(chatData) + val usernameProperty = bean.getStringProperty("userName") + val isActiveProperty = bean.getBooleanProperty("activeUser.online") + val lastActiveProperty = bean.getStringProperty("lastActiveString") + val messagesStringProperty = new SimpleListProperty(chatData.messages) + val prop = new SimpleListProperty(ObservableBuffer.empty[HBox]) + // val x = messagesStringProperty.map(message => createMdMessageBox(message)) + // prop <== messagesStringProperty.map(message => createMdMessageBox(message)) + // prop <== new SimpleListProperty(x) +} +object ChatDataProperty { + def createMdMessageBox(mdfxText: String) = { + val mdfxNode = new BubbledMDFXNode(mdfxText); + mdfxNode + .getStylesheets() + .add(ChatController.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 + } } -// final case class chatData() diff --git a/src/main/scala/wow/doge/chatto/service/UserService.scala b/src/main/scala/wow/doge/chatto/service/UserService.scala index 8d450ce..95cb8b3 100644 --- a/src/main/scala/wow/doge/chatto/service/UserService.scala +++ b/src/main/scala/wow/doge/chatto/service/UserService.scala @@ -97,6 +97,5 @@ final case class ActiveUser( ) object ActiveUser { - val z = ZonedDateTime.now() - z.toInstant().toString() + def empty = ActiveUser("empty", false, None) }