WIP desktop client for Chatto reimplemented in ScalaFX and Sapphire Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

322 lines
11 KiB

package wow.doge.chatto.controller
import javafx.fxml.FXML
import javafx.scene.control.Label
import javafx.scene.control.Button
import javafx.scene.layout.FlowPane
import javafx.scene.control.TextArea
import javafx.scene.control.ListView
import javafx.scene.layout.HBox
import javafx.scene.layout.VBox
import scalafx.Includes._
import wow.doge.chatto.control.UserBox
import javafx.application.Platform
import javax.inject.Inject
import org.scalafx.extras._
import wow.doge.chatto.messagebuble.BubbledMDFXNode
import wow.doge.chatto.service.UserService
import scala.concurrent.ExecutionContext
import scala.concurrent.ExecutionContext.Implicits.global
import com.typesafe.scalalogging.LazyLogging
// import wow.doge.chatto.controller.LoginController.Person
import com.sfxcode.sapphire.core.value.FXBean
import wow.doge.chatto.AppDataHandler
import com.jfoenix.controls.JFXListView
import scala.async.Async.{async, await}
import javafx.scene.paint.Color
import scalafx.collections.ObservableBuffer
import javafx.beans.property.SimpleListProperty
import wow.doge.chatto.control.UserBox2
import javafx.beans.value.ChangeListener
import com.sfxcode.sapphire.core.value.KeyBindings
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 {
// @FXML private var label: Label = _
@FXML private var flowPane: FlowPane = _
@FXML private var submitButton: Button = _
@FXML private var logoutButton: Button = _
// @FXML private var chatTextArea: TextArea = _
@FXML private var chatInput: TextArea = _
@FXML private var usersVBox: VBox = _
@FXML var usersListView: JFXListView[UserBox2] = _
@FXML var chatListView: JFXListView[HBox] = _
@FXML private var curUsr: Label = _
@FXML private var dataContent: Label = _
// applicationController.show
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")
// 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 chatDataAdapter = FXBeanAdapter[ChatData](this)
override def didGainVisibilityFirstTime(): Unit = {
super.didGainVisibilityFirstTime()
// val ub = new UserBox()
this.stage.resizable = true
// ub.messageLabel.text = "Hi there"
// ub.messageLabel.id =
// ub.userRadioButton.text = "User 1"
// usersVBox.children.clear()
// usersVBox.children += ub
// println("test")
// println(s"Result = ${func()}")
// offFX(println("hello from new thread"))
// chatTextArea.visible <== !chatInput.text.isEmpty
// chatTextArea.text <== chatInput.text
// for (r <- userService.func2()) yield (logger.info(s"${r.body}"))
// val person = Person(0, 10, "Billy")
// val bean = FXBean[Person](person)
// ub.messageLabel.text <== bean.getStringProperty("name")
// bean.getStringProperty("name") <== chatInput.text
// bean.getStringProperty("name")() = "Lester"
// println(bean.getValue("name"))
// println(bean.getStringProperty("name")())
// bean.
// bean.updateValue("name", "Lester")
// println(bean.bean)
// val curUserBean = FXBean[User](User("None"))
// logoutButton.onAction = (e) =>
// usersListView
// .getSelectionModel()
// .selectedItemProperty()
// .addListener((_, _, newValue) => {
// curUsr.text() = newValue.usernameLabel.text()
// })
// 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)
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)
// 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()
// .usernameLabel
// .text
usersListView.items <== usersListProperty
}
override def didGainVisibility(): Unit = {
super.didGainVisibility()
chatInput.requestFocus()
async {
val willBeUsers = userService
.getUsers(appDataHandler.appData.credentials)
.map(_.body)
val willBeActiveUsers = userService
.getActiveUsers(appDataHandler.appData.credentials)
.map(_.body)
val maybeUsers = await(willBeUsers)
val maybeActiveUsers = await(willBeActiveUsers)
// maybeActiveUsers.foreach(println)
logger.debug(s"$maybeActiveUsers")
val maybeUserBoxes = maybeActiveUsers.map(users => {
// usersBuffer ++= users
users.map(user => {
// usersBuffer += FXBean(User(user))
// val ub = new UserBox()
// ub.messageLabel.text = "Hi there"
// ub.userRadioButton.text = user
// ub
// new Rectangle {
// fill <== when(hover) choose (Color.Red)
// }
// val hb = new HBox
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)
// }
// fill <== when(this.hover) choose (Color.RED) otherwise (Color.BLUE)
}
})
})
// maybeUserBoxes.map(userBoxes => {
// // chatDataBuffer ++= userBoxes
// usersListProperty ++= userBoxes
// })
val messageBox = ChatDataProperty.createMdMessageBox("*hello!*")
onFX {
// 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
}
}
}
def func() = {
val x = offFXAndWait {
2 + 3
}
x
}
def actionLogout = onFX {
offFXAndWait {
appDataHandler.clearCredentials()
println(appDataHandler.appData)
}
// 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)
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
}
}