updated UI

This commit is contained in:
Rohan Sircar 2020-05-25 23:14:06 +05:30
parent 8402c2f59e
commit 640b2507eb
19 changed files with 746 additions and 379 deletions

View File

@ -45,13 +45,14 @@ libraryDependencies ++= Seq(
"org.json4s" %% "json4s-jackson" % "3.6.8", "org.json4s" %% "json4s-jackson" % "3.6.8",
"org.scala-lang.modules" %% "scala-async" % "0.10.0", "org.scala-lang.modules" %% "scala-async" % "0.10.0",
"org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided, "org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided,
// "org.kordamp.ikonli" %% "ikonli-javafx" % "11.4.0", "org.kordamp.ikonli" % "ikonli-javafx" % "11.4.0",
// "org.kordamp.ikonli" %% "ikonli-fontawesome-pack" % "11.4.0", "org.kordamp.ikonli" % "ikonli-fontawesome-pack" % "11.4.0",
// "org.kordamp.ikonli" %% "ikonli-fontawesome5-pack" % "11.4.0", "org.kordamp.ikonli" % "ikonli-fontawesome5-pack" % "11.4.0",
"org.jsoup" % "jsoup" % "1.13.1", "org.jsoup" % "jsoup" % "1.13.1",
"com.sandec" % "mdfx" % "0.1.6", "com.sandec" % "mdfx" % "0.1.6",
"com.softwaremill.sttp.client" %% "async-http-client-backend-future" % "2.1.1", "com.softwaremill.sttp.client" %% "async-http-client-backend-future" % "2.1.1",
"com.softwaremill.quicklens" %% "quicklens" % "1.5.0" "com.softwaremill.quicklens" %% "quicklens" % "1.5.0",
"net.synedra" % "validatorfx" % "0.1.11"
) )
libraryDependencies += "org.asynchttpclient" % "async-http-client" % "2.12.1" libraryDependencies += "org.asynchttpclient" % "async-http-client" % "2.12.1"
libraryDependencies += "com.softwaremill.macwire" %% "macros" % "2.3.3" libraryDependencies += "com.softwaremill.macwire" %% "macros" % "2.3.3"
@ -66,6 +67,9 @@ libraryDependencies += "org.kordamp.bootstrapfx" % "bootstrapfx-core" % "0.2.4"
// https://mvnrepository.com/artifact/org.json4s/json4s-ext // https://mvnrepository.com/artifact/org.json4s/json4s-ext
libraryDependencies += "org.json4s" %% "json4s-ext" % "3.6.8" libraryDependencies += "org.json4s" %% "json4s-ext" % "3.6.8"
// https://mvnrepository.com/artifact/org.jsoup/jsoup
libraryDependencies += "org.jsoup" % "jsoup" % "1.13.1"
enablePlugins(BuildInfoPlugin) enablePlugins(BuildInfoPlugin)
buildInfoPackage := "wow.doge.chatto" buildInfoPackage := "wow.doge.chatto"

View File

@ -1,49 +1,54 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8"?>
<?import com.jfoenix.controls.JFXListView ?> <?import com.jfoenix.controls.JFXListView?>
<?import javafx.geometry.Insets ?> <?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button ?> <?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label ?> <?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea ?> <?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.BorderPane ?> <?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.FlowPane ?> <?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.HBox ?> <?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox ?> <?import javafx.scene.layout.VBox?>
<?import org.kordamp.ikonli.javafx.FontIcon?>
<!-- <?import com.example.javafx.control.UserBox?> --> <!-- <?import com.example.javafx.control.UserBox?> -->
<!-- fx:controller="com.example.javafx.controller.SimpleUiController" --> <!-- fx:controller="com.example.javafx.controller.SimpleUiController" -->
<BorderPane minHeight="533.0" minWidth="800.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="wow.doge.chatto.controller.ChatController"> <BorderPane fx:id="chatMainPane" minWidth="800.0" prefHeight="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="wow.doge.chatto.controller.ChatController">
<left> <left>
<VBox fx:id="usersVBox" alignment="TOP_CENTER" prefHeight="200.0" prefWidth="175.0" BorderPane.alignment="CENTER"> <VBox fx:id="usersVBox" alignment="CENTER" prefHeight="200.0" prefWidth="175.0" BorderPane.alignment="CENTER">
<children> <children>
<JFXListView fx:id="usersListView" prefHeight="554.0" prefWidth="175.0" styleClass="my-list-view" /> <JFXListView fx:id="usersListView" prefHeight="561.0" prefWidth="175.0" styleClass="my-list-view" VBox.vgrow="ALWAYS" />
</children> </children>
</VBox> </VBox>
</left> </left>
<center> <center>
<VBox prefHeight="200.0" prefWidth="100.0" spacing="5.0" BorderPane.alignment="CENTER"> <VBox alignment="CENTER" prefHeight="200.0" prefWidth="100.0" spacing="5.0" BorderPane.alignment="CENTER">
<children> <children>
<BorderPane prefHeight="41.0" prefWidth="620.0"> <BorderPane prefHeight="41.0" prefWidth="620.0">
<center> <center>
<HBox alignment="CENTER" spacing="5.0"> <HBox fx:id="selectedUserBox" alignment="CENTER" spacing="5.0" styleClass="chat-background">
<children> <children>
<Label id="currentUser" fx:id="curUsr" text="User1" /> <Label id="currentUser" fx:id="curUsr" styleClass="text-white" text="User1" />
<Label id="lastActive" fx:id="dataContent" text="User2" /> <Label id="lastActive" fx:id="lastActiveLabel" styleClass="text-white" text="User2" />
<Label id="online" text="User2" /> <Label id="online" fx:id="isOnlineLabel" styleClass="text-white" text="User2" />
</children> </children>
</HBox> </HBox>
</center> </center>
</BorderPane> </BorderPane>
<JFXListView fx:id="chatListView" prefHeight="463.0" prefWidth="610.0" /> <JFXListView fx:id="chatListView" minWidth="100.0" prefHeight="477.0" prefWidth="608.0" styleClass="my-list-view" VBox.vgrow="ALWAYS" />
<HBox prefHeight="50.0" prefWidth="790.0" spacing="2.0"> <HBox prefHeight="50.0" prefWidth="790.0" spacing="2.0" styleClass="chat-background">
<children> <children>
<TextArea fx:id="chatInput" prefHeight="15.0" prefWidth="250.0" HBox.hgrow="ALWAYS" /> <TextArea fx:id="chatInput" prefHeight="15.0" prefWidth="250.0" HBox.hgrow="ALWAYS" />
<FlowPane alignment="CENTER" hgap="2.0" prefHeight="47.0" prefWidth="221.0"> <FlowPane alignment="CENTER" hgap="2.0" prefHeight="50.0" prefWidth="181.0">
<children> <children>
<Button fx:id="logoutButton" styleClass="btn, btn-primary" text="Logout" onAction="#actionLogout" /> <Button fx:id="logoutButton" onAction="#actionLogout" styleClass="btn, btn-primary" text="Logout" />
<Button fx:id="submitButton" styleClass="btn, btn-primary" text="Submit" /> <Button fx:id="submitButton" style="-fx-background-color: transparent;">
<graphic>
<FontIcon accessibleText="Submit" fill="#2f91c9" iconLiteral="fa-chevron-circle-right" iconSize="40" />
</graphic>
</Button>
</children> </children>
</FlowPane> </FlowPane>
@ -55,8 +60,8 @@
</BorderPane.margin> </BorderPane.margin>
</VBox> </VBox>
</center> </center>
<stylesheets> <!-- <stylesheets>
<!-- <URL value="@../styles/ui.css" /> <URL value="@../styles/chat.css" />
<URL value="@../styles/bootstrapfx.css" /> --> <URL value="@../styles/bootstrapfx.css" />
</stylesheets> </stylesheets> -->
</BorderPane> </BorderPane>

View File

@ -15,8 +15,7 @@
<!-- minHeight="533.0" minWidth="800" maxHeight="533.0" maxWidth="800" --> <!-- minHeight="533.0" minWidth="800" maxHeight="533.0" maxWidth="800" -->
<!-- fx:controller="com.example.javafx.controller.LoginController" --> <!-- fx:controller="com.example.javafx.controller.LoginController" -->
<GridPane id="rootPane" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="wow.doge.chatto.controller.LoginController">
<GridPane prefHeight="533.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="wow.doge.chatto.controller.LoginController">
<columnConstraints> <columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" maxWidth="257.0" minWidth="10.0" prefWidth="122.0" /> <ColumnConstraints hgrow="SOMETIMES" maxWidth="257.0" minWidth="10.0" prefWidth="122.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="667.0" /> <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="667.0" />
@ -43,14 +42,14 @@
<Font size="14.0" /> <Font size="14.0" />
</font> </font>
</Label> </Label>
<JFXTextField fx:id="usernameTextField" focusColor="#d30699" labelFloat="true" minWidth="196.0" prefHeight="31.0" prefWidth="215.0" id="username" promptText="Username" /> <JFXTextField id="username" fx:id="usernameTextField" focusColor="#d30699" labelFloat="true" minWidth="196.0" prefHeight="31.0" prefWidth="215.0" promptText="Username" />
<JFXPasswordField fx:id="passwordTextField" focusColor="#fb06d2" labelFloat="true" minWidth="196.0" prefHeight="31.0" prefWidth="215.0" id="password" promptText="Password" /> <JFXPasswordField id="password" fx:id="passwordTextField" focusColor="#fb06d2" labelFloat="true" minWidth="196.0" prefHeight="31.0" prefWidth="215.0" promptText="Password" />
<!-- <JFXButton fx:id="submitButton" buttonType="RAISED" prefHeight="37.0" prefWidth="110.0" ripplerFill="WHITE" style="-fx-background-color: #fb06d2; -fx-background-radius: 50px;" text="Get started" textFill="WHITE" /> --> <!-- <JFXButton fx:id="submitButton" buttonType="RAISED" prefHeight="37.0" prefWidth="110.0" ripplerFill="WHITE" style="-fx-background-color: #fb06d2; -fx-background-radius: 50px;" text="Get started" textFill="WHITE" /> -->
<JFXButton fx:id="submitButton" styleClass="btn, btn-primary" text="Submit" onAction="#actionLogin" /> <JFXButton fx:id="submitButton" onAction="#actionLogin" styleClass="btn, btn-primary" text="Submit" />
<!-- style="-fx-background-radius: 50px;-fx-background-color: #fb06d2" --> <!-- style="-fx-background-radius: 50px;-fx-background-color: #fb06d2" -->
<Label fx:id="errorLabel" alignment="CENTER" prefHeight="37.0" prefWidth="324.0" text="" textAlignment="CENTER" textFill="#727070" wrapText="true"> <Label fx:id="errorLabel" alignment="CENTER" prefHeight="37.0" prefWidth="324.0" style="-fx-text-fill: RED;" textAlignment="CENTER" wrapText="true">
<font> <font>
<Font size="14.0" /> <Font size="14.0" />
</font> </font>
@ -70,7 +69,7 @@
</VBox> </VBox>
</children> </children>
<stylesheets> <stylesheets>
<!-- <URL value="@../styles/style2.css" /> --> <URL value="@../styles/login.css" />
<URL value="@../styles/bootstrapfx.css" /> <URL value="@../styles/bootstrapfx.css" />
</stylesheets> </stylesheets>
</GridPane> </GridPane>

View File

@ -4,8 +4,27 @@
<?import javafx.scene.layout.* ?> <?import javafx.scene.layout.* ?>
<?import javafx.scene.control.* ?> <?import javafx.scene.control.* ?>
<AnchorPane id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="400" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="wow.doge.chatto.controller.MainViewController"> <BorderPane id="rootPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="400" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="wow.doge.chatto.controller.MainViewController">
<children> <!-- <children>
<BorderPane prefHeight="600.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<top>
<AnchorPane fx:id="navigationPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
prefHeight="40.0" styleClass="navigation"/>
</top>
<center>
<AnchorPane fx:id="workspacePane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
prefHeight="200.0"/>
</center>
<bottom>
<AnchorPane fx:id="statusPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
prefHeight="30.0" styleClass="status"/>
</bottom>
</BorderPane>
<AnchorPane fx:id="mainPane"></AnchorPane>
<AnchorPane fx:id="chatPane"></AnchorPane>
</children> -->
<top>
<MenuBar VBox.vgrow="NEVER" fx:id="menuBar"> <MenuBar VBox.vgrow="NEVER" fx:id="menuBar">
<menus> <menus>
<Menu mnemonicParsing="false" text="File"> <Menu mnemonicParsing="false" text="File">
@ -45,28 +64,13 @@
</Menu> </Menu>
</menus> </menus>
</MenuBar> </MenuBar>
<!-- <BorderPane prefHeight="600.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<top>
<AnchorPane fx:id="navigationPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
prefHeight="40.0" styleClass="navigation"/>
</top> </top>
<center> <center>
<AnchorPane fx:id="workspacePane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" <HBox fx:id="mainPane"></HBox>
prefHeight="200.0"/>
</center> </center>
<bottom>
<AnchorPane fx:id="statusPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
prefHeight="30.0" styleClass="status"/>
</bottom>
</BorderPane> -->
<AnchorPane fx:id="mainPane"></AnchorPane>
<!-- <AnchorPane fx:id="chatPane"></AnchorPane> -->
</children>
<stylesheets> <stylesheets>
<!-- <URL value="@default.css" /> <URL value="@../styles/default.css" />
<URL value="@../styles/ui.css" /> <URL value="@../styles/bootstrapfx.css" />
<URL value="@../styles/style2.css" /> --> <URL value="@../styles/chat.css" />
</stylesheets> </stylesheets>
</AnchorPane> </BorderPane>

View File

@ -1,29 +0,0 @@
.navigation {
-fx-background-color: derive(cadetblue, 60%);
-fx-font-size: 14px;
}
.status {
-fx-background-color: derive(lightgray, 30%);
-fx-font-size: 12px;
}
.workspace2 {
-fx-background-color: azure;
-fx-font-size: 16px;
}
.workspace {
-fx-background-color: beige;
-fx-font-size: 13px;
}
.personPane {
-fx-font-size: 11px;
}

View File

@ -0,0 +1,173 @@
/* .ikonli-font-icon {
-fx-icon-size: 100px;
-fx-icon-color: blue;
} */
.ikonli-font-icon:hover {
-fx-icon-color: #1976a8;
}
#chatMainPane {
-fx-padding: 5px;
}
.my-list-view .scroll-bar:horizontal .track,
.my-list-view .scroll-bar:vertical .track {
-fx-background-color: transparent;
-fx-border-color: transparent;
-fx-background-radius: 0em;
-fx-border-radius: 2em;
}
.my-list-view .scroll-bar:horizontal .increment-button,
.my-list-view .scroll-bar:horizontal .decrement-button {
-fx-background-color: transparent;
-fx-background-radius: 0em;
-fx-padding: 0 0 10 0;
}
.my-list-view .scroll-bar:vertical .increment-button,
.my-list-view .scroll-bar:vertical .decrement-button {
-fx-background-color: transparent;
-fx-background-radius: 0em;
-fx-padding: 0 10 0 0;
}
.my-list-view .scroll-bar .increment-arrow,
.my-list-view .scroll-bar .decrement-arrow {
-fx-shape: " ";
-fx-padding: 0;
}
.my-list-view .scroll-bar:horizontal .thumb,
.my-list-view .scroll-bar:vertical .thumb {
-fx-background-color: derive(black, 90%);
-fx-background-insets: 2, 0, 0;
-fx-background-radius: 2em;
}
.scroll-pane .scroll-bar:horizontal .track,
.scroll-pane .scroll-bar:vertical .track {
-fx-background-color: transparent;
-fx-border-color: transparent;
-fx-background-radius: 0em;
-fx-border-radius: 2em;
}
.scroll-pane .scroll-bar:horizontal .increment-button,
.scroll-pane .scroll-bar:horizontal .decrement-button {
-fx-background-color: transparent;
-fx-background-radius: 0em;
-fx-padding: 0 0 10 0;
}
.scroll-pane .scroll-bar:vertical .increment-button,
.scroll-pane .scroll-bar:vertical .decrement-button {
-fx-background-color: transparent;
-fx-background-radius: 0em;
-fx-padding: 0 10 0 0;
}
.scroll-pane .scroll-bar .increment-arrow,
.scroll-pane .scroll-bar .decrement-arrow {
-fx-shape: " ";
-fx-padding: 0;
}
.scroll-pane .scroll-bar:horizontal .thumb,
.scroll-pane .scroll-bar:vertical .thumb {
-fx-background-color: derive(black, 90%);
-fx-background-insets: 2, 0, 0;
-fx-background-radius: 2em;
}
.scroll-pane {
-fx-background-color: transparent;
}
.scroll-pane > .viewport {
-fx-background-color: transparent;
}
.chat-message-box {
-fx-text-fill: white;
/* -fx-background-color: LIGHTGREEN; */
-fx-background-color: #82ccdd;
-fx-background-radius: 30px;
-fx-padding: 20px;
}
.chat-background {
-fx-background-color: rgba(0, 0, 0, 0.4);
/* -fx-selection-bar: rgba(0, 0, 0, 0.5); */
-fx-text-fill: white;
-fx-background-radius: 20px;
-fx-padding: 5px 10px;
}
.my-list-view {
-fx-background-color: rgba(0, 0, 0, 0.4);
/* -fx-selection-bar: rgba(0, 0, 0, 0.5); */
-fx-text-fill: white;
-fx-background-radius: 20px;
-fx-padding: 5px 10px;
}
.list-cell {
-fx-background-color: transparent;
-fx-text-fill: white;
}
.list-cell:selected {
-fx-background-color: rgba(0, 0, 0, 0.2);
-fx-text-fill: white;
-fx-background-radius: 20px;
}
.list-cell:hover {
-fx-background-color: rgba(0, 0, 0, 0.1);
-fx-text-fill: white;
-fx-background-radius: 20px;
}
.list-cell:selected:hover {
-fx-background-color: rgba(0, 0, 0, 0.3);
-fx-text-fill: white;
-fx-background-radius: 20px;
}
.list-view:focused .list-cell:selected {
-fx-background-color: rgba(0, 0, 0, 0.3);
-fx-text-fill: white;
-fx-background-radius: 20px;
}
.text-area {
-fx-text-fill: white;
-fx-border-radius: 20px;
}
.text-area .content {
-fx-background-color: rgb(116, 116, 116);
-fx-background-radius: 20px;
}
.text-area {
-fx-background-color: rgba(53, 89, 119, 0.4);
}
.text-area .scroll-pane {
-fx-background-color: transparent;
}
.text-area .scroll-pane .viewport {
-fx-background-color: transparent;
}
.text-area .scroll-pane .content {
-fx-background-color: transparent;
}
#chatInput {
-fx-text-fill: white;
-fx-background-radius: 20px;
-fx-padding: 5px 10px;
}

View File

@ -0,0 +1,85 @@
.navigation {
-fx-background-color: derive(cadetblue, 60%);
-fx-font-size: 14px;
}
.status {
-fx-background-color: derive(lightgray, 30%);
-fx-font-size: 12px;
}
.workspace2 {
-fx-background-color: azure;
-fx-font-size: 16px;
}
.workspace {
-fx-background-color: beige;
-fx-font-size: 13px;
}
.personPane {
-fx-font-size: 11px;
}
.root {
-fx-padding: 5 5 5 5;
}
.scroll-bar:horizontal .track,
.scroll-bar:vertical .track {
-fx-background-color: transparent;
-fx-border-color: transparent;
-fx-background-radius: 0em;
-fx-border-radius: 2em;
}
.scroll-bar:horizontal .increment-button,
.scroll-bar:horizontal .decrement-button {
-fx-background-color: transparent;
-fx-background-radius: 0em;
-fx-padding: 0 0 10 0;
}
.scroll-bar:vertical .increment-button,
.scroll-bar:vertical .decrement-button {
-fx-background-color: transparent;
-fx-background-radius: 0em;
-fx-padding: 0 10 0 0;
}
.scroll-bar .increment-arrow,
.scroll-bar .decrement-arrow {
-fx-shape: " ";
-fx-padding: 0.15em 0;
}
.scroll-bar:vertical .increment-arrow,
.scroll-bar:vertical .decrement-arrow {
-fx-shape: " ";
-fx-padding: 0 0.15em;
}
.scroll-bar:horizontal .thumb,
.scroll-bar:vertical .thumb {
-fx-background-color: derive(black, 90%);
-fx-background-insets: 2, 0, 0;
-fx-background-radius: 2em;
}
.scroll-bar:horizontal .thumb:hover,
.scroll-bar:vertical .thumb:hover {
-fx-background-color: derive(#4d4c4f, 10%);
-fx-background-insets: 2, 0, 0;
-fx-background-radius: 2em;
}
.root {
-fx-background-color: linear-gradient(to right, #91eae4, #86a8e7, #7f7fd5);
}
/* linear-gradient(to right, #91EAE4, #86A8E7, #7F7FD5); */
/* linear-gradient(from 25% 25% to 100% 100%, #dc143c, #661a33)"); */
.text-white {
-fx-text-fill: white;
}

View File

@ -0,0 +1,5 @@
#rootPane {
-fx-background-image: url("../images/backgroung.jpg");
-fx-background-size: 1920 1080;
-fx-background-position: center center;
}

View File

@ -38,19 +38,20 @@ class ApplicationController extends DefaultWindowController {
// override def width: Int = 400 // override def width: Int = 400
@Inject // @Inject
private var appDataHandler: AppDataHandler = _ // private var appDataHandler: AppDataHandler = _
def applicationDidLaunch() = { def applicationDidLaunch() = {
logger.info("start " + this) logger.info("start " + this)
applicationEnvironment.loadResourceBundle("bundles/application") applicationEnvironment.loadResourceBundle("bundles/application")
replaceSceneContent(mainViewController) replaceSceneContent(mainViewController.loginController)
} }
@Produces @Produces
def applicationName: ApplicationName = { def applicationName: ApplicationName = {
ApplicationName(configStringValue("application.name")) ApplicationName(configStringValue("application.name"))
} }
@Produces @Produces
def httpBackend = backend def httpBackend = backend
@ -65,15 +66,15 @@ class ApplicationController extends DefaultWindowController {
replaceSceneContent(newMainViewController) replaceSceneContent(newMainViewController)
} }
def testListener(@Observes event: SceneControllerWillChangeEvent) = { // def testListener(@Observes event: SceneControllerWillChangeEvent) = {
logger.info("test success 1") // logger.info("test success 1")
// logger.info(s"${event.newController}") // // logger.info(s"${event.newController}")
} // }
def testListener2(@Observes event: SceneControllerDidChangeEvent) = { // def testListener2(@Observes event: SceneControllerDidChangeEvent) = {
logger.info("test success 2") // logger.info("test success 2")
// logger.info(s"${event.newController}") // // logger.info(s"${event.newController}")
} // }
override def applicationWillStop(): Unit = async { override def applicationWillStop(): Unit = async {
super.applicationWillStop() super.applicationWillStop()
@ -84,42 +85,17 @@ class ApplicationController extends DefaultWindowController {
} }
def showLoginPane() = onFX { def showLoginPane() = onFX {
offFX { appDataHandler.clearCredentials() } // offFX { appDataHandler.clearCredentials() }
// replaceSceneContent(mainViewController.loginController)
// mainViewController.mainManager.updatePaneContent(
// mainViewController.loginController
// )
replaceSceneContent(mainViewController.loginController) replaceSceneContent(mainViewController.loginController)
} }
def logout() = { def logout() = onFX {
val newMainViewController = getController[MainViewController]() val newMainViewController = getController[MainViewController]()
replaceSceneContent(newMainViewController) replaceSceneContent(mainViewController.loginController)
} }
def showChatPane(): Unit = onFX { def showChatPane(): Unit = onFX {
// import org.scalafx.extras._ replaceSceneContent(mainViewController, true)
replaceSceneContent(mainViewController.chatController, true)
// mainViewController.mainManager.updatePaneContent(
// mainViewController.chatController
// )
// httpBackend.send(basicRequest.get(uri""))
// val willBeResponse = basicRequest
// .get(uri"https://httpbin.org/get")
// .response(asJson[HttpBinResponse])
// .send()
// async {
// val r = await { willBeResponse }
// r.body.map(println)
// }
// willBeResponse onComplete {
// case Success(x) => { x.body }
// case Failure(x) => {}
// }
// val body = for {
// r <- willBeResponse
// } yield (r.body)
} }
} }
@ -142,7 +118,6 @@ class AppDataHandler {
def appData = _appData def appData = _appData
def updateCredentials(credentials: UserCredentials): Unit = offFX { def updateCredentials(credentials: UserCredentials): Unit = offFX {
println(credentials)
appData = appData.copy(credentials = credentials) appData = appData.copy(credentials = credentials)
} }

View File

@ -0,0 +1,114 @@
package wow.doge.chatto.control;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.DefaultProperty;
import javafx.beans.property.DoubleProperty;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.ListView;
import javafx.geometry.Orientation;
import javafx.scene.control.ScrollBar;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Transform;
import javafx.util.Duration;
import java.util.function.Function;
public class JFXSmoothScroll {
private static ScrollBar getScrollbarComponent(ListView<?> control, Orientation orientation) {
Node n = control.lookup(".scroll-bar");
if (n instanceof ScrollBar) {
final ScrollBar bar = (ScrollBar) n;
if (bar.getOrientation().equals(orientation)) {
return bar;
}
}
return null;
}
public static void smoothScrollingListView(ListView<?> listView, double speed) {
smoothScrollingListView(listView, speed, Orientation.VERTICAL, bounds -> bounds.getHeight());
}
public static void smoothHScrollingListView(ListView<?> listView, double speed) {
smoothScrollingListView(listView, speed, Orientation.HORIZONTAL, bounds -> bounds.getHeight());
}
private static void smoothScrollingListView(ListView<?> listView, double speed, Orientation orientation,
Function<Bounds, Double> sizeFunc) {
ScrollBar scrollBar = getScrollbarComponent(listView, orientation);
if (scrollBar == null) {
return;
}
scrollBar.setUnitIncrement(5);
final double[] frictions = { 0.99, 0.1, 0.05, 0.04, 0.03, 0.02, 0.01, 0.04, 0.01, 0.008, 0.008, 0.008, 0.008,
0.0006, 0.0005, 0.00003, 0.00001 };
final double[] pushes = { speed };
final double[] derivatives = new double[frictions.length];
final double[] lastVPos = { 0 };
Timeline timeline = new Timeline();
final EventHandler<MouseEvent> dragHandler = event -> timeline.stop();
final EventHandler<ScrollEvent> scrollHandler = event -> {
scrollBar.valueProperty().set(lastVPos[0]);
if (event.getEventType() == ScrollEvent.SCROLL) {
double direction = event.getDeltaY() > 0 ? -1 : 1;
for (int i = 0; i < pushes.length; i++) {
derivatives[i] += direction * pushes[i];
}
if (timeline.getStatus() == Animation.Status.STOPPED) {
timeline.play();
}
}
event.consume();
};
if (scrollBar.getParent() != null) {
scrollBar.getParent().addEventHandler(MouseEvent.DRAG_DETECTED, dragHandler);
scrollBar.getParent().addEventHandler(ScrollEvent.ANY, scrollHandler);
}
scrollBar.parentProperty().addListener((o, oldVal, newVal) -> {
if (oldVal != null) {
oldVal.removeEventHandler(MouseEvent.DRAG_DETECTED, dragHandler);
oldVal.removeEventHandler(ScrollEvent.ANY, scrollHandler);
}
if (newVal != null) {
newVal.addEventHandler(MouseEvent.DRAG_DETECTED, dragHandler);
newVal.addEventHandler(ScrollEvent.ANY, scrollHandler);
}
});
timeline.getKeyFrames().add(new KeyFrame(Duration.millis(3), (event) -> {
for (int i = 0; i < derivatives.length; i++) {
derivatives[i] *= frictions[i];
}
for (int i = 1; i < derivatives.length; i++) {
derivatives[i] += derivatives[i - 1];
}
double dy = derivatives[derivatives.length - 1];
double size = sizeFunc.apply(scrollBar.getLayoutBounds());
scrollBar.valueProperty().set(Math.min(Math.max(scrollBar.getValue() + dy / size, 0), 1));
lastVPos[0] = scrollBar.getValue();
if (Math.abs(dy) < 1) {
if (Math.abs(dy) < 0.001) {
timeline.stop();
}
}
}));
timeline.setCycleCount(Animation.INDEFINITE);
}
}

View File

@ -0,0 +1,10 @@
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 MessageBox(val sender: String, val receiver: String, val message: String)
extends HBox() {}

View File

@ -7,7 +7,10 @@ import wow.doge.chatto.controller.ChatData
import com.sfxcode.sapphire.core.value.FXBean import com.sfxcode.sapphire.core.value.FXBean
class UserBox2(val username: String, val chatData: ChatData) extends HBox() { class UserBox2(val username: String, val chatData: ChatData) extends HBox() {
val usernameLabel = new Label(username) val usernameLabel = new Label(username) {
// this.style = "-fx-text-fill: white"
this.styleClass ++= Seq("text-white")
}
// lazy val chatDataBean = FXBean[ChatData](chatData) // lazy val chatDataBean = FXBean[ChatData](chatData)
this.children ++= Seq { this.children ++= Seq {
usernameLabel usernameLabel

View File

@ -18,7 +18,6 @@ import wow.doge.chatto.service.UserService
import scala.concurrent.ExecutionContext import scala.concurrent.ExecutionContext
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
import com.typesafe.scalalogging.LazyLogging import com.typesafe.scalalogging.LazyLogging
// import wow.doge.chatto.controller.LoginController.Person
import com.sfxcode.sapphire.core.value.FXBean import com.sfxcode.sapphire.core.value.FXBean
import wow.doge.chatto.AppDataHandler import wow.doge.chatto.AppDataHandler
import com.jfoenix.controls.JFXListView import com.jfoenix.controls.JFXListView
@ -41,6 +40,27 @@ import wow.doge.chatto.messagebuble.BubbleSpec
import javafx.scene.layout.Background import javafx.scene.layout.Background
import javafx.scene.layout.BackgroundFill import javafx.scene.layout.BackgroundFill
import javafx.geometry.Pos import javafx.geometry.Pos
import scalafx.beans.property.ReadOnlyBufferProperty
import scalafx.beans.property.ReadOnlyBufferWrapper
import javafx.beans.property.ReadOnlyListProperty
import scalafx.beans.property.BufferProperty
import javafx.collections.FXCollections
import com.sandec.mdfx.MDFXNode
import javafx.scene.layout.BorderPane
import javafx.scene.layout.Priority
import net.synedra.validatorfx.Validator
import wow.doge.chatto.control.JFXSmoothScroll
import javafx.scene.control.ContextMenu
import javafx.scene.control.MenuItem
import javafx.scene.input.Clipboard
import javafx.scene.input.ClipboardContent
import scalafx.scene.input.KeyCodeCombination
import scalafx.scene.input.KeyCode
import scalafx.scene.input.KeyCombination
import javafx.scene.input.DataFormat
import wow.doge.chatto.control.MessageBox
import javafx.scene.control.SelectionMode
import scalafx.beans.property.BooleanProperty
class ChatController @Inject() ( class ChatController @Inject() (
userService: UserService, userService: UserService,
@ -49,71 +69,54 @@ class ChatController @Inject() (
with LazyLogging { with LazyLogging {
// @FXML private var label: Label = _ // @FXML private var label: Label = _
@FXML private var flowPane: FlowPane = _ @FXML var chatMainPane: BorderPane = _
// @FXML private var flowPane: FlowPane = _
@FXML private var submitButton: Button = _ @FXML private var submitButton: Button = _
@FXML private var logoutButton: Button = _ @FXML private var logoutButton: Button = _
// @FXML private var chatTextArea: TextArea = _ // @FXML private var chatTextArea: TextArea = _
@FXML private var chatInput: TextArea = _ @FXML private var chatInput: TextArea = _
@FXML private var usersVBox: VBox = _ @FXML private var usersVBox: VBox = _
@FXML var usersListView: JFXListView[UserBox2] = _ @FXML var usersListView: JFXListView[UserBox2] = _
@FXML var chatListView: JFXListView[HBox] = _ @FXML var chatListView: JFXListView[MessageBox] = _
@FXML private var curUsr: Label = _ @FXML private var curUsr: Label = _
@FXML private var dataContent: Label = _ @FXML private var lastActiveLabel: Label = _
// applicationController.show @FXML private var isOnlineLabel: Label = _
private val usersListProperty = new SimpleListProperty( @FXML private var selectedUserBox: HBox = _
ObservableBuffer[UserBox2]()
) private val usersBuffer = ObservableBuffer.empty[UserBox2]
private val chatDataBuffer = ObservableBuffer[UserBox2]() private val usersListProperty = BufferProperty(usersBuffer)
private val chatDataStore: mutable.Map[String, ChatDataProperty] =
TrieMap() /**
* Readonly property wrapping an unmodifiable list.
* Synchronized with the internal users list property.
* Attemping to modify the internal list will throw an exception
*/
val usersListROProp: ReadOnlyListProperty[UserBox2] = BufferProperty(
FXCollections.unmodifiableObservableList(usersListProperty())
)
private val chatDataStore = TrieMap.empty[String, ChatDataProperty]
// 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) private lazy val chatDataAdapter = FXBeanAdapter[ChatData](this)
override def didGainVisibilityFirstTime(): Unit = { override def didGainVisibilityFirstTime(): Unit = {
super.didGainVisibilityFirstTime() super.didGainVisibilityFirstTime()
// val ub = new UserBox()
this.stage.resizable = true this.stage.resizable = true
// ub.messageLabel.text = "Hi there" chatMainPane.hgrow = Priority.ALWAYS
// ub.messageLabel.id = chatListView.selectionModel().selectionMode = SelectionMode.MULTIPLE
// 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}")) chatDataAdapter.set(FXBean(ChatData.empty))
// val person = Person(0, 10, "Billy") Array(submitButton, chatInput).foreach(n => {
// val bean = FXBean[Person](person) n.disableProperty() <== usersListView
// ub.messageLabel.text <== bean.getStringProperty("name") .selectionModel()
// bean.getStringProperty("name") <== chatInput.text .selectedItemProperty()
.isNull()
})
// 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()}") // curUserKeys.add("content", "${_self.data().content()}")
val chatDataAdapterKeys = KeyBindings() val chatDataAdapterKeys = KeyBindings()
// chatDataAdapterKeys.add("currentUser", "${_self.userName()}") chatDataAdapterKeys.add("currentUser", "${_self.userName()}")
// chatDataAdapterKeys.add( // chatDataAdapterKeys.add(
// "lastActive", // "lastActive",
// "${_self.lastActiveString()}" // "${_self.lastActiveString()}"
@ -125,39 +128,97 @@ class ChatController @Inject() (
// curUserAdapter.addDateConverter() // curUserAdapter.addDateConverter()
// curUserAdapter.addBindings(curUserKeys) // curUserAdapter.addBindings(curUserKeys)
chatDataAdapter.addBindings(chatDataAdapterKeys) chatDataAdapter.addBindings(chatDataAdapterKeys)
// curUsr.text <== chatDataAdapter.beanProperty
// .getOrElse(FXBean(ChatData.empty))
// .getStringProperty("lastActiveString")
usersListView usersListView
.getSelectionModel() .selectionModel()
.selectedItemProperty() .selectedItemProperty()
.addListener((_, _, newValue) => { .addListener((_, _, newValue) => {
if (newValue != null) { Option(newValue).foreach(nv => {
// val dataBean = val maybeCDP = chatDataStore
// FXBean(User(newValue.usernameLabel.text(), Data("test data"))) .get(nv.username)
// curUserAdapter val chatDataBean = maybeCDP
// .set(dataBean)
// chatDataAdapter.set(newValue.chatDataBean)
val y = chatDataStore
.get(newValue.username)
val x = y
.map(_.bean) .map(_.bean)
.getOrElse { .getOrElse {
logger.error("Error null") logger.error("Error null")
FXBean(ChatData.empty) FXBean(ChatData.empty)
} }
chatDataAdapter.set(x) chatDataAdapter.set(chatDataBean)
y.map(z => chatListView.items <== z.prop) maybeCDP.foreach(cdp => {
} // lastActiveLabel.text <== cdp.lastActive
isOnlineLabel.text <== cdp.isActive.asString()
chatListView.items <== cdp.messageBubbles
})
})
}) })
// curUsr.text <== usersListView val copyMessageMenuItem = new MenuItem("Copy Message")
// .getSelectionModel() copyMessageMenuItem.accelerator =
// .getSelectedItem() new KeyCodeCombination(KeyCode.C, KeyCombination.ControlDown)
// .usernameLabel copyMessageMenuItem.onAction = _ => {
// .text 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 chatListMenu = new ContextMenu()
chatListMenu.items += copyMessageMenuItem
chatListView.contextMenu = chatListMenu
usersListView.items <== usersListProperty usersListView.items <== usersListProperty
val validator = new Validator()
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()
)
})
}
}
validator
.createCheck()
.withMethod(c => {
val userName = chatInput.text()
if (!userName.toLowerCase().equals(userName)) {
c.error("Please use only lowercase letters.")
}
})
.dependsOn("chatInput", chatInput.text)
.decorates(chatInput)
.immediate()
} }
override def didGainVisibility(): Unit = { override def didGainVisibility(): Unit = {
@ -165,70 +226,60 @@ class ChatController @Inject() (
chatInput.requestFocus() chatInput.requestFocus()
async { async {
val willBeUsers = userService
.getUsers(appDataHandler.appData.credentials)
.map(_.body)
val willBeActiveUsers = userService val willBeActiveUsers = userService
.getActiveUsers(appDataHandler.appData.credentials) .getActiveUsers(appDataHandler.appData.credentials)
.map(_.body) .map(_.body)
val maybeUsers = await(willBeUsers)
val maybeActiveUsers = await(willBeActiveUsers) val maybeActiveUsers = await(willBeActiveUsers)
// maybeActiveUsers.foreach(println) logger.debug(s"Received Users: $maybeActiveUsers")
logger.debug(s"$maybeActiveUsers")
val maybeUserBoxes = maybeActiveUsers.map(users => { val maybeUserBoxes = maybeActiveUsers.map(users => {
// usersBuffer ++= users
users.map(user => { 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 = val chatData =
ChatData(user.userName, user, ObservableBuffer.empty[String]) 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.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) { new UserBox2(user.userName, chatData) {
// this.children += new Label { this.styleClass ++= Seq("text-white")
// 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 => { val messageBox = ChatDataProperty.createMdMessageBox2(
// // chatDataBuffer ++= userBoxes """**Hello world qefwew yeeehay bwergqwevqcqe**
// usersListProperty ++= userBoxes |**Hello world qefwew yeeehay bwergqwevqcqe**
// }) |
val messageBox = ChatDataProperty.createMdMessageBox("*hello!*") | Hello World
""".stripMargin
)
onFX { onFX {
// maybeUserBoxes.map(userBoxes => { maybeUserBoxes.foreach(userBoxes => {
// chatDataBuffer ++= userBoxes usersBuffer ++= userBoxes
// // usersListView.items() ++= userBoxes
// // val x = new SimpleListProperty(ObservableBuffer(userBoxes))
// // usersListView.items <== x
// })
maybeUserBoxes.map(userBoxes => {
usersListProperty ++= userBoxes
}) })
chatListView.items() += messageBox 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
)
)
// .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")
)
// .map(ChatDataProperty.createMdMessageBox)
})
} }
} }
def func() = { def func() = {
@ -241,40 +292,29 @@ class ChatController @Inject() (
def actionLogout = onFX { def actionLogout = onFX {
offFXAndWait { offFXAndWait {
appDataHandler.clearCredentials() appDataHandler.clearCredentials()
println(appDataHandler.appData)
} }
// curUserAdapter.set(User.empty) // curUserAdapter.set(User.empty)
logger.debug(s"Logout - clearing credentials - ${appDataHandler.appData}")
chatDataAdapter.set(FXBean(ChatData.empty)) chatDataAdapter.set(FXBean(ChatData.empty))
usersListView.items().clear() usersListView.items().clear()
chatListView.items().clear() chatListView.items().clear()
chatDataBuffer.clear()
chatDataStore.clear() chatDataStore.clear()
usersListProperty.clear() usersBuffer.clear()
chatInput.clear()
this.stage.maximized = false
applicationController.logout() applicationController.logout()
println(appDataHandler.appData)
} }
} implicit class MyClipboardExtension(clipboard: Clipboard) {
object ChatController { def putString(string: String) = {
lazy val markdownStyleSheet = // val content = Option(clipboard.getContent(DataFormat.PLAIN_TEXT))
getClass().getResource("/styles/markdown.css").toExternalForm() // .getOrElse(new ClipboardContent())
// content.putString(string)
// clipboard.setContent(content)
}
}
} }
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( final case class ChatData(
userName: String, userName: String,
activeUser: ActiveUser, activeUser: ActiveUser,
@ -294,21 +334,26 @@ object ChatData {
class ChatDataProperty(chatData: ChatData) { class ChatDataProperty(chatData: ChatData) {
import ChatDataProperty._ import ChatDataProperty._
val bean = FXBean(chatData) val bean = FXBean(chatData)
val usernameProperty = bean.getStringProperty("userName") val username = bean.getStringProperty("userName")
val isActiveProperty = bean.getBooleanProperty("activeUser.online") val isActive = bean.getBooleanProperty("activeUser.online")
val lastActiveProperty = bean.getStringProperty("lastActiveString") val lastActive = bean.getStringProperty("lastActiveString")
val messagesStringProperty = new SimpleListProperty(chatData.messages) lazy val messageBubbles = BufferProperty(
val prop = new SimpleListProperty(ObservableBuffer.empty[HBox]) chatData.messages.map(ChatDataProperty.createMdMessageBox2)
// val x = messagesStringProperty.map(message => createMdMessageBox(message)) )
// prop <== messagesStringProperty.map(message => createMdMessageBox(message)) def messageList = messageBubbles().map(_.message)
// prop <== new SimpleListProperty(x) // lazy val messages = messagesBubbleProperty
// .get()
// .map(_.messageText)
} }
object ChatDataProperty { object ChatDataProperty {
lazy val markdownStyleSheet =
getClass().getResource("/styles/markdown.css").toExternalForm()
def createMdMessageBox(mdfxText: String) = { def createMdMessageBox(mdfxText: String) = {
val mdfxNode = new BubbledMDFXNode(mdfxText); val mdfxNode = new BubbledMDFXNode(mdfxText);
mdfxNode mdfxNode
.getStylesheets() .getStylesheets()
.add(ChatController.markdownStyleSheet); .add(markdownStyleSheet);
mdfxNode.setBubbleSpec(BubbleSpec.FACE_RIGHT_CENTER); mdfxNode.setBubbleSpec(BubbleSpec.FACE_RIGHT_CENTER);
mdfxNode.setBackground( mdfxNode.setBackground(
new Background(new BackgroundFill(Color.LIGHTSTEELBLUE, null, null)) new Background(new BackgroundFill(Color.LIGHTSTEELBLUE, null, null))
@ -319,4 +364,49 @@ object ChatDataProperty {
box.children += mdfxNode; box.children += mdfxNode;
box box
} }
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
) = {
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(sender, receiver, 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
}
} }

View File

@ -31,6 +31,8 @@ import wow.doge.chatto.types.AppTypes
import org.scalafx.extras._ import org.scalafx.extras._
import wow.doge.chatto.AppDataHandler import wow.doge.chatto.AppDataHandler
import com.sfxcode.sapphire.core.value.BeanConversions import com.sfxcode.sapphire.core.value.BeanConversions
import javafx.scene.layout.StackPane
import com.jfoenix.controls.JFXSpinner
class LoginController @Inject() ( class LoginController @Inject() (
userService: UserService, userService: UserService,
@ -87,33 +89,31 @@ class LoginController @Inject() (
val inputUserName = usernameTextField.text() val inputUserName = usernameTextField.text()
val inputPassword = passwordTextField.text() val inputPassword = passwordTextField.text()
submitButton.disable = true
login(inputUserName, inputPassword) onComplete { login(inputUserName, inputPassword) onComplete {
case Success(maybeToken) => { case Success(maybeToken) => {
maybeToken.foreach(println)
maybeToken match { maybeToken match {
case Some(token) => case Some(token) =>
async { async {
val credentials = val credentials =
UserCredentials(inputUserName, inputPassword, token) UserCredentials(inputUserName, inputPassword, token)
appDataHandler.updateCredentials(credentials) appDataHandler.updateCredentials(credentials)
// await { updateErrorLabel("")
// userService.getUsers(credentials).map(_.body.foreach(println))
// }
applicationController.showChatPane() applicationController.showChatPane()
onFX { submitButton.disable = false }
} }
case None => { case None => {
updateErrorLabel("Error logging in - please check your password") updateErrorLabel("Error logging in - please check your password")
logger.warn("Login unsuccessful wrong password") logger.warn("Login unsuccessful wrong password")
onFX { submitButton.disable = false }
} }
} }
// applicationController.showChatPane()
} }
case Failure(exception) => { case Failure(exception) => {
logger.error(s"${exception.getMessage()}") logger.error(s"${exception.getMessage()}")
logger.warn("Login unsuccessful network problem") logger.warn("Login unsuccessful network problem")
updateErrorLabel("Error logging in - Please check your network") updateErrorLabel("Error logging in - Please check your network")
// applicationController.showChatPane() onFX { submitButton.disable = false }
} }
} }
} }
@ -141,5 +141,4 @@ class LoginController @Inject() (
username: String, username: String,
password: String password: String
) )
} }

View File

@ -11,11 +11,13 @@ import com.typesafe.scalalogging.LazyLogging
import wow.doge.chatto.messagebuble.BubbledMDFXNode import wow.doge.chatto.messagebuble.BubbledMDFXNode
import scalafx.scene.layout.GridPane import scalafx.scene.layout.GridPane
import scalafx.Includes._ import scalafx.Includes._
// import wow.doge.chatto. import javafx.scene.layout.HBox
import javafx.scene.layout.Priority
import wow.doge.chatto.control.UserBox
class MainViewController extends ViewController with LazyLogging { class MainViewController extends ViewController with LazyLogging {
@FXML var menuBar: MenuBar = _ @FXML private var menuBar: MenuBar = _
// @FXML // @FXML
// var workspacePane: Pane = _ // var workspacePane: Pane = _
// @FXML // @FXML
@ -23,9 +25,7 @@ class MainViewController extends ViewController with LazyLogging {
// @FXML // @FXML
// var navigationPane: Pane = _ // var navigationPane: Pane = _
@FXML var mainPane: Pane = _ @FXML private var mainPane: HBox = _
// @FXML var chatPane: Pane = _
lazy val workspaceController = getController[WorkspaceController]() lazy val workspaceController = getController[WorkspaceController]()
lazy val navigationController = getController[NavigationController]() lazy val navigationController = getController[NavigationController]()
@ -33,22 +33,21 @@ class MainViewController extends ViewController with LazyLogging {
lazy val loginController = getController[LoginController]() lazy val loginController = getController[LoginController]()
lazy val chatController = getController[ChatController]() lazy val chatController = getController[ChatController]()
// val bubbleNode = new BubbledMDFXNode("Wow")
var workspaceManager: ContentManager = _ var workspaceManager: ContentManager = _
var navigationManager: ContentManager = _ var navigationManager: ContentManager = _
var statusBarManager: ContentManager = _ var statusBarManager: ContentManager = _
var mainManager: ContentManager = _ var mainManager: ContentManager = _
override def didGainVisibilityFirstTime() { override def didGainVisibilityFirstTime() = {
// menuBar.setUseSystemMenuBar(true) menuBar.setUseSystemMenuBar(true)
// menuBar.setVisible(false) // menuBar.setVisible(false)
// navigationManager = // navigationManager =
// ContentManager(navigationPane, this, navigationController) // ContentManager(navigationPane, this, navigationController)
// statusBarManager = ContentManager(statusPane, this, statusBarController) // statusBarManager = ContentManager(statusPane, this, statusBarController)
// workspaceManager = ContentManager(workspacePane, this, workspaceController) // workspaceManager = ContentManager(workspacePane, this, workspaceController)
mainManager = ContentManager(mainPane, this, loginController) mainManager = ContentManager(mainPane, this, chatController)
chatController.chatMainPane.hgrow = Priority.ALWAYS
} }
} }

View File

@ -5,12 +5,12 @@ import javafx.scene.control.Button
class NavigationController extends AbstractViewController { class NavigationController extends AbstractViewController {
def actionClickButton(event: ActionEvent) { def actionClickButton(event: ActionEvent) = {
logger.debug(event.toString) logger.debug(event.toString)
statusBarController.updateLabel(event.getSource.asInstanceOf[Button]) statusBarController.updateLabel(event.getSource.asInstanceOf[Button])
} }
def actionHotReload(event: ActionEvent) { def actionHotReload(event: ActionEvent) = {
applicationController.replacePrimarySceneContent() applicationController.replacePrimarySceneContent()
logger.debug("Hot Reload Succeeded") logger.debug("Hot Reload Succeeded")
statusBarController.updateLabel(event.getSource.asInstanceOf[Button]) statusBarController.updateLabel(event.getSource.asInstanceOf[Button])

View File

@ -15,7 +15,7 @@ class WorkspaceController @Inject() (applicationName: ApplicationName)
@FXML @FXML
var infoLabel: Label = _ var infoLabel: Label = _
override def didGainVisibilityFirstTime() { override def didGainVisibilityFirstTime() = {
infoLabel.setText(applicationName.name) infoLabel.setText(applicationName.name)
} }
} }

View File

@ -1,69 +0,0 @@
package wow.doge.chatto.service
import org.json4s.CustomSerializer
import org.json4s._
import java.time.Instant
// import org.json4s.JsonAST._
import org.json4s.JsonDSL._
// class ParentSerializer extends Serializer[Parent] {
// private val ParentClass = classOf[Parent]
// implicit val formats = DefaultFormats
// def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), Parent] = {
// case (TypeInfo(ParentClass, _), json) => json match {
// case JObject(JField("kind", JString(kind)) :: _) => kind match {
// case "first_type" => json.extract[ChildClassOne]
// case "second_type" => json.extract[ChildClassTwo]
// }
// case _ => throw new MappingException("Invalid kind")
// }
// }
// def serialize(implicit format: Formats): PartialFunction[Any, JValue] = Map()
// }
// class MyJInstantSerializer extends Serializer[Instant] {
// implicit val formats = DefaultFormats
// def deserialize(
// implicit format: Formats
// ): PartialFunction[(TypeInfo, JValue), Instant] = {
// case (_, JString(d)) => Instant.parse(d)
// case (_, JNull) => null
// }
// def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
// case d: Instant => JString(d.toString())
// }
// }
// class MyJInstantSerializer
// extends CustomSerializer[Instant](implicit format =>
// (
// {
// // case JInt(d) => Instant.ofEpochMilli(d.toLong)
// case JString(d) => Instant.parse(d)
// case JNull => null
// }, {
// // case d: Instant => JInt(d.toEpochMilli)
// case d: Instant => JString(d.toString())
// }
// )
// )
// import java.time.ZonedDateTime
// import java.time.format.DateTimeFormatter
// a custom serializer has two partial functions, one
// for serializing and one for deserializing
// case object ZDTSerializer
// extends CustomSerializer[ZonedDateTime](format =>
// ({
// case JString(s) => ZonedDateTime.parse(s)
// }, {
// case zdt: ZonedDateTime =>
// JString(
// zdt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX"))
// )
// })
// )

View File

@ -52,12 +52,12 @@ class UserService @Inject() (appDataHandler: AppDataHandler)(
private def endpoint(uri: String) = uri"$baseUrl/$uri" private def endpoint(uri: String) = uri"$baseUrl/$uri"
def getUsers(credentials: UserCredentials) = async { def getUsers(credentials: UserCredentials) = async {
logger.debug(s"${appDataHandler.appData}") // logger.debug(s"${appDataHandler.appData}")
println( // println(
write[ActiveUser]( // write[ActiveUser](
ActiveUser("hmm what is it", true, Some(ZonedDateTime.now())) // ActiveUser("hmm what is it", true, Some(ZonedDateTime.now()))
) // )
) // )
await { await {
authBasicRequest(credentials) authBasicRequest(credentials)
.get(uri"http://localhost:8080/api/chat/get/users") .get(uri"http://localhost:8080/api/chat/get/users")
@ -67,7 +67,7 @@ class UserService @Inject() (appDataHandler: AppDataHandler)(
} }
def getMessages(credentials: UserCredentials) = async { def getMessages(credentials: UserCredentials) = async {
logger.debug(s"${appDataHandler.appData}") // logger.debug(s"${appDataHandler.appData}")
await { await {
authBasicRequest(credentials) authBasicRequest(credentials)
.get(uri"http://localhost:8080/api/chat/get/users") .get(uri"http://localhost:8080/api/chat/get/users")