updated UI
This commit is contained in:
parent
8402c2f59e
commit
640b2507eb
12
build.sbt
12
build.sbt
@ -45,13 +45,14 @@ libraryDependencies ++= Seq(
|
||||
"org.json4s" %% "json4s-jackson" % "3.6.8",
|
||||
"org.scala-lang.modules" %% "scala-async" % "0.10.0",
|
||||
"org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided,
|
||||
// "org.kordamp.ikonli" %% "ikonli-javafx" % "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-javafx" % "11.4.0",
|
||||
"org.kordamp.ikonli" % "ikonli-fontawesome-pack" % "11.4.0",
|
||||
"org.kordamp.ikonli" % "ikonli-fontawesome5-pack" % "11.4.0",
|
||||
"org.jsoup" % "jsoup" % "1.13.1",
|
||||
"com.sandec" % "mdfx" % "0.1.6",
|
||||
"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 += "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
|
||||
libraryDependencies += "org.json4s" %% "json4s-ext" % "3.6.8"
|
||||
|
||||
// https://mvnrepository.com/artifact/org.jsoup/jsoup
|
||||
libraryDependencies += "org.jsoup" % "jsoup" % "1.13.1"
|
||||
|
||||
enablePlugins(BuildInfoPlugin)
|
||||
|
||||
buildInfoPackage := "wow.doge.chatto"
|
||||
|
@ -1,49 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import com.jfoenix.controls.JFXListView ?>
|
||||
<?import javafx.geometry.Insets ?>
|
||||
<?import javafx.scene.control.Button ?>
|
||||
<?import javafx.scene.control.Label ?>
|
||||
<?import javafx.scene.control.TextArea ?>
|
||||
<?import javafx.scene.layout.BorderPane ?>
|
||||
<?import javafx.scene.layout.FlowPane ?>
|
||||
<?import javafx.scene.layout.HBox ?>
|
||||
<?import javafx.scene.layout.VBox ?>
|
||||
<?import com.jfoenix.controls.JFXListView?>
|
||||
<?import javafx.geometry.Insets?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.control.TextArea?>
|
||||
<?import javafx.scene.layout.BorderPane?>
|
||||
<?import javafx.scene.layout.FlowPane?>
|
||||
<?import javafx.scene.layout.HBox?>
|
||||
<?import javafx.scene.layout.VBox?>
|
||||
<?import org.kordamp.ikonli.javafx.FontIcon?>
|
||||
|
||||
<!-- <?import com.example.javafx.control.UserBox?> -->
|
||||
<!-- 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>
|
||||
<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>
|
||||
<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>
|
||||
</VBox>
|
||||
</left>
|
||||
<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>
|
||||
<BorderPane prefHeight="41.0" prefWidth="620.0">
|
||||
<center>
|
||||
<HBox alignment="CENTER" spacing="5.0">
|
||||
<HBox fx:id="selectedUserBox" alignment="CENTER" spacing="5.0" styleClass="chat-background">
|
||||
<children>
|
||||
<Label id="currentUser" fx:id="curUsr" text="User1" />
|
||||
<Label id="lastActive" fx:id="dataContent" text="User2" />
|
||||
<Label id="online" text="User2" />
|
||||
<Label id="currentUser" fx:id="curUsr" styleClass="text-white" text="User1" />
|
||||
<Label id="lastActive" fx:id="lastActiveLabel" styleClass="text-white" text="User2" />
|
||||
<Label id="online" fx:id="isOnlineLabel" styleClass="text-white" text="User2" />
|
||||
</children>
|
||||
</HBox>
|
||||
</center>
|
||||
</BorderPane>
|
||||
<JFXListView fx:id="chatListView" prefHeight="463.0" prefWidth="610.0" />
|
||||
<HBox prefHeight="50.0" prefWidth="790.0" spacing="2.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" styleClass="chat-background">
|
||||
<children>
|
||||
<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>
|
||||
|
||||
<Button fx:id="logoutButton" styleClass="btn, btn-primary" text="Logout" onAction="#actionLogout" />
|
||||
<Button fx:id="submitButton" styleClass="btn, btn-primary" text="Submit" />
|
||||
<Button fx:id="logoutButton" onAction="#actionLogout" styleClass="btn, btn-primary" text="Logout" />
|
||||
<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>
|
||||
</FlowPane>
|
||||
@ -55,8 +60,8 @@
|
||||
</BorderPane.margin>
|
||||
</VBox>
|
||||
</center>
|
||||
<stylesheets>
|
||||
<!-- <URL value="@../styles/ui.css" />
|
||||
<URL value="@../styles/bootstrapfx.css" /> -->
|
||||
</stylesheets>
|
||||
<!-- <stylesheets>
|
||||
<URL value="@../styles/chat.css" />
|
||||
<URL value="@../styles/bootstrapfx.css" />
|
||||
</stylesheets> -->
|
||||
</BorderPane>
|
@ -15,8 +15,7 @@
|
||||
<!-- minHeight="533.0" minWidth="800" maxHeight="533.0" maxWidth="800" -->
|
||||
<!-- fx:controller="com.example.javafx.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">
|
||||
<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">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="257.0" minWidth="10.0" prefWidth="122.0" />
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="667.0" />
|
||||
@ -43,14 +42,14 @@
|
||||
<Font size="14.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<JFXTextField fx:id="usernameTextField" focusColor="#d30699" labelFloat="true" minWidth="196.0" prefHeight="31.0" prefWidth="215.0" id="username" promptText="Username" />
|
||||
<JFXPasswordField fx:id="passwordTextField" focusColor="#fb06d2" labelFloat="true" minWidth="196.0" prefHeight="31.0" prefWidth="215.0" id="password" promptText="Password" />
|
||||
<JFXTextField id="username" fx:id="usernameTextField" focusColor="#d30699" labelFloat="true" minWidth="196.0" prefHeight="31.0" prefWidth="215.0" promptText="Username" />
|
||||
<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" 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" -->
|
||||
|
||||
<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 size="14.0" />
|
||||
</font>
|
||||
@ -70,7 +69,7 @@
|
||||
</VBox>
|
||||
</children>
|
||||
<stylesheets>
|
||||
<!-- <URL value="@../styles/style2.css" /> -->
|
||||
<URL value="@../styles/login.css" />
|
||||
<URL value="@../styles/bootstrapfx.css" />
|
||||
</stylesheets>
|
||||
</GridPane>
|
@ -4,8 +4,27 @@
|
||||
<?import javafx.scene.layout.* ?>
|
||||
<?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">
|
||||
<children>
|
||||
<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>
|
||||
<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">
|
||||
<menus>
|
||||
<Menu mnemonicParsing="false" text="File">
|
||||
@ -45,28 +64,13 @@
|
||||
</Menu>
|
||||
</menus>
|
||||
</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>
|
||||
<center>
|
||||
<AnchorPane fx:id="workspacePane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308"
|
||||
prefHeight="200.0"/>
|
||||
<HBox fx:id="mainPane"></HBox>
|
||||
</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>
|
||||
<!-- <URL value="@default.css" />
|
||||
<URL value="@../styles/ui.css" />
|
||||
<URL value="@../styles/style2.css" /> -->
|
||||
<URL value="@../styles/default.css" />
|
||||
<URL value="@../styles/bootstrapfx.css" />
|
||||
<URL value="@../styles/chat.css" />
|
||||
</stylesheets>
|
||||
</AnchorPane>
|
||||
</BorderPane>
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
173
src/main/resources/styles/chat.css
Normal file
173
src/main/resources/styles/chat.css
Normal 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;
|
||||
}
|
85
src/main/resources/styles/default.css
Normal file
85
src/main/resources/styles/default.css
Normal 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;
|
||||
}
|
5
src/main/resources/styles/login.css
Normal file
5
src/main/resources/styles/login.css
Normal file
@ -0,0 +1,5 @@
|
||||
#rootPane {
|
||||
-fx-background-image: url("../images/backgroung.jpg");
|
||||
-fx-background-size: 1920 1080;
|
||||
-fx-background-position: center center;
|
||||
}
|
@ -38,19 +38,20 @@ class ApplicationController extends DefaultWindowController {
|
||||
|
||||
// override def width: Int = 400
|
||||
|
||||
@Inject
|
||||
private var appDataHandler: AppDataHandler = _
|
||||
// @Inject
|
||||
// private var appDataHandler: AppDataHandler = _
|
||||
|
||||
def applicationDidLaunch() = {
|
||||
logger.info("start " + this)
|
||||
applicationEnvironment.loadResourceBundle("bundles/application")
|
||||
replaceSceneContent(mainViewController)
|
||||
replaceSceneContent(mainViewController.loginController)
|
||||
}
|
||||
|
||||
@Produces
|
||||
def applicationName: ApplicationName = {
|
||||
ApplicationName(configStringValue("application.name"))
|
||||
}
|
||||
|
||||
@Produces
|
||||
def httpBackend = backend
|
||||
|
||||
@ -65,15 +66,15 @@ class ApplicationController extends DefaultWindowController {
|
||||
replaceSceneContent(newMainViewController)
|
||||
}
|
||||
|
||||
def testListener(@Observes event: SceneControllerWillChangeEvent) = {
|
||||
logger.info("test success 1")
|
||||
// logger.info(s"${event.newController}")
|
||||
}
|
||||
// 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}")
|
||||
}
|
||||
// def testListener2(@Observes event: SceneControllerDidChangeEvent) = {
|
||||
// logger.info("test success 2")
|
||||
// // logger.info(s"${event.newController}")
|
||||
// }
|
||||
|
||||
override def applicationWillStop(): Unit = async {
|
||||
super.applicationWillStop()
|
||||
@ -84,42 +85,17 @@ class ApplicationController extends DefaultWindowController {
|
||||
}
|
||||
|
||||
def showLoginPane() = onFX {
|
||||
offFX { appDataHandler.clearCredentials() }
|
||||
// replaceSceneContent(mainViewController.loginController)
|
||||
// mainViewController.mainManager.updatePaneContent(
|
||||
// mainViewController.loginController
|
||||
// )
|
||||
// offFX { appDataHandler.clearCredentials() }
|
||||
replaceSceneContent(mainViewController.loginController)
|
||||
}
|
||||
|
||||
def logout() = {
|
||||
def logout() = onFX {
|
||||
val newMainViewController = getController[MainViewController]()
|
||||
replaceSceneContent(newMainViewController)
|
||||
replaceSceneContent(mainViewController.loginController)
|
||||
}
|
||||
|
||||
def showChatPane(): Unit = onFX {
|
||||
// import org.scalafx.extras._
|
||||
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)
|
||||
replaceSceneContent(mainViewController, true)
|
||||
}
|
||||
}
|
||||
|
||||
@ -142,7 +118,6 @@ class AppDataHandler {
|
||||
def appData = _appData
|
||||
|
||||
def updateCredentials(credentials: UserCredentials): Unit = offFX {
|
||||
println(credentials)
|
||||
appData = appData.copy(credentials = credentials)
|
||||
}
|
||||
|
||||
|
114
src/main/scala/wow/doge/chatto/control/JFXSmoothScroll.java
Normal file
114
src/main/scala/wow/doge/chatto/control/JFXSmoothScroll.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
10
src/main/scala/wow/doge/chatto/control/MessageBox.scala
Normal file
10
src/main/scala/wow/doge/chatto/control/MessageBox.scala
Normal 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() {}
|
@ -7,7 +7,10 @@ import wow.doge.chatto.controller.ChatData
|
||||
import com.sfxcode.sapphire.core.value.FXBean
|
||||
|
||||
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)
|
||||
this.children ++= Seq {
|
||||
usernameLabel
|
||||
|
@ -18,7 +18,6 @@ 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
|
||||
@ -41,6 +40,27 @@ import wow.doge.chatto.messagebuble.BubbleSpec
|
||||
import javafx.scene.layout.Background
|
||||
import javafx.scene.layout.BackgroundFill
|
||||
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() (
|
||||
userService: UserService,
|
||||
@ -49,71 +69,54 @@ class ChatController @Inject() (
|
||||
with LazyLogging {
|
||||
|
||||
// @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 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 var chatListView: JFXListView[MessageBox] = _
|
||||
@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()
|
||||
@FXML private var lastActiveLabel: Label = _
|
||||
@FXML private var isOnlineLabel: Label = _
|
||||
@FXML private var selectedUserBox: HBox = _
|
||||
|
||||
private val usersBuffer = ObservableBuffer.empty[UserBox2]
|
||||
private val usersListProperty = BufferProperty(usersBuffer)
|
||||
|
||||
/**
|
||||
* 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)
|
||||
|
||||
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
|
||||
chatMainPane.hgrow = Priority.ALWAYS
|
||||
chatListView.selectionModel().selectionMode = SelectionMode.MULTIPLE
|
||||
|
||||
// for (r <- userService.func2()) yield (logger.info(s"${r.body}"))
|
||||
chatDataAdapter.set(FXBean(ChatData.empty))
|
||||
|
||||
// val person = Person(0, 10, "Billy")
|
||||
// val bean = FXBean[Person](person)
|
||||
// ub.messageLabel.text <== bean.getStringProperty("name")
|
||||
// bean.getStringProperty("name") <== chatInput.text
|
||||
Array(submitButton, chatInput).foreach(n => {
|
||||
n.disableProperty() <== usersListView
|
||||
.selectionModel()
|
||||
.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()}")
|
||||
val chatDataAdapterKeys = KeyBindings()
|
||||
// chatDataAdapterKeys.add("currentUser", "${_self.userName()}")
|
||||
chatDataAdapterKeys.add("currentUser", "${_self.userName()}")
|
||||
// chatDataAdapterKeys.add(
|
||||
// "lastActive",
|
||||
// "${_self.lastActiveString()}"
|
||||
@ -125,39 +128,97 @@ class ChatController @Inject() (
|
||||
// curUserAdapter.addDateConverter()
|
||||
// curUserAdapter.addBindings(curUserKeys)
|
||||
chatDataAdapter.addBindings(chatDataAdapterKeys)
|
||||
// curUsr.text <== chatDataAdapter.beanProperty
|
||||
// .getOrElse(FXBean(ChatData.empty))
|
||||
// .getStringProperty("lastActiveString")
|
||||
usersListView
|
||||
.getSelectionModel()
|
||||
.selectionModel()
|
||||
.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
|
||||
Option(newValue).foreach(nv => {
|
||||
val maybeCDP = chatDataStore
|
||||
.get(nv.username)
|
||||
val chatDataBean = maybeCDP
|
||||
.map(_.bean)
|
||||
.getOrElse {
|
||||
logger.error("Error null")
|
||||
FXBean(ChatData.empty)
|
||||
}
|
||||
chatDataAdapter.set(x)
|
||||
y.map(z => chatListView.items <== z.prop)
|
||||
}
|
||||
chatDataAdapter.set(chatDataBean)
|
||||
maybeCDP.foreach(cdp => {
|
||||
// lastActiveLabel.text <== cdp.lastActive
|
||||
isOnlineLabel.text <== cdp.isActive.asString()
|
||||
chatListView.items <== cdp.messageBubbles
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// curUsr.text <== usersListView
|
||||
// .getSelectionModel()
|
||||
// .getSelectedItem()
|
||||
// .usernameLabel
|
||||
// .text
|
||||
val copyMessageMenuItem = new MenuItem("Copy Message")
|
||||
copyMessageMenuItem.accelerator =
|
||||
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 chatListMenu = new ContextMenu()
|
||||
|
||||
chatListMenu.items += copyMessageMenuItem
|
||||
chatListView.contextMenu = chatListMenu
|
||||
|
||||
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 = {
|
||||
@ -165,70 +226,60 @@ class ChatController @Inject() (
|
||||
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")
|
||||
logger.debug(s"Received Users: $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)
|
||||
this.styleClass ++= Seq("text-white")
|
||||
}
|
||||
})
|
||||
})
|
||||
// maybeUserBoxes.map(userBoxes => {
|
||||
// // chatDataBuffer ++= userBoxes
|
||||
// usersListProperty ++= userBoxes
|
||||
// })
|
||||
val messageBox = ChatDataProperty.createMdMessageBox("*hello!*")
|
||||
val messageBox = ChatDataProperty.createMdMessageBox2(
|
||||
"""**Hello world qefwew yeeehay bwergqwevqcqe**
|
||||
|**Hello world qefwew yeeehay bwergqwevqcqe**
|
||||
|
|
||||
| Hello World
|
||||
""".stripMargin
|
||||
)
|
||||
onFX {
|
||||
// maybeUserBoxes.map(userBoxes => {
|
||||
// chatDataBuffer ++= userBoxes
|
||||
// // usersListView.items() ++= userBoxes
|
||||
// // val x = new SimpleListProperty(ObservableBuffer(userBoxes))
|
||||
// // usersListView.items <== x
|
||||
// })
|
||||
maybeUserBoxes.map(userBoxes => {
|
||||
usersListProperty ++= userBoxes
|
||||
maybeUserBoxes.foreach(userBoxes => {
|
||||
usersBuffer ++= 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() = {
|
||||
@ -241,40 +292,29 @@ class ChatController @Inject() (
|
||||
def actionLogout = onFX {
|
||||
offFXAndWait {
|
||||
appDataHandler.clearCredentials()
|
||||
println(appDataHandler.appData)
|
||||
}
|
||||
// curUserAdapter.set(User.empty)
|
||||
logger.debug(s"Logout - clearing credentials - ${appDataHandler.appData}")
|
||||
chatDataAdapter.set(FXBean(ChatData.empty))
|
||||
usersListView.items().clear()
|
||||
chatListView.items().clear()
|
||||
chatDataBuffer.clear()
|
||||
chatDataStore.clear()
|
||||
usersListProperty.clear()
|
||||
usersBuffer.clear()
|
||||
chatInput.clear()
|
||||
this.stage.maximized = false
|
||||
applicationController.logout()
|
||||
println(appDataHandler.appData)
|
||||
}
|
||||
|
||||
}
|
||||
object ChatController {
|
||||
lazy val markdownStyleSheet =
|
||||
getClass().getResource("/styles/markdown.css").toExternalForm()
|
||||
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 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,
|
||||
@ -294,21 +334,26 @@ object ChatData {
|
||||
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)
|
||||
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)
|
||||
}
|
||||
object ChatDataProperty {
|
||||
lazy val markdownStyleSheet =
|
||||
getClass().getResource("/styles/markdown.css").toExternalForm()
|
||||
|
||||
def createMdMessageBox(mdfxText: String) = {
|
||||
val mdfxNode = new BubbledMDFXNode(mdfxText);
|
||||
mdfxNode
|
||||
.getStylesheets()
|
||||
.add(ChatController.markdownStyleSheet);
|
||||
.add(markdownStyleSheet);
|
||||
mdfxNode.setBubbleSpec(BubbleSpec.FACE_RIGHT_CENTER);
|
||||
mdfxNode.setBackground(
|
||||
new Background(new BackgroundFill(Color.LIGHTSTEELBLUE, null, null))
|
||||
@ -319,4 +364,49 @@ object ChatDataProperty {
|
||||
box.children += mdfxNode;
|
||||
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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ import wow.doge.chatto.types.AppTypes
|
||||
import org.scalafx.extras._
|
||||
import wow.doge.chatto.AppDataHandler
|
||||
import com.sfxcode.sapphire.core.value.BeanConversions
|
||||
import javafx.scene.layout.StackPane
|
||||
import com.jfoenix.controls.JFXSpinner
|
||||
|
||||
class LoginController @Inject() (
|
||||
userService: UserService,
|
||||
@ -87,33 +89,31 @@ class LoginController @Inject() (
|
||||
val inputUserName = usernameTextField.text()
|
||||
val inputPassword = passwordTextField.text()
|
||||
|
||||
submitButton.disable = true
|
||||
login(inputUserName, inputPassword) onComplete {
|
||||
case Success(maybeToken) => {
|
||||
maybeToken.foreach(println)
|
||||
maybeToken match {
|
||||
case Some(token) =>
|
||||
async {
|
||||
val credentials =
|
||||
UserCredentials(inputUserName, inputPassword, token)
|
||||
appDataHandler.updateCredentials(credentials)
|
||||
// await {
|
||||
// userService.getUsers(credentials).map(_.body.foreach(println))
|
||||
// }
|
||||
updateErrorLabel("")
|
||||
applicationController.showChatPane()
|
||||
onFX { submitButton.disable = false }
|
||||
}
|
||||
case None => {
|
||||
updateErrorLabel("Error logging in - please check your password")
|
||||
logger.warn("Login unsuccessful wrong password")
|
||||
onFX { submitButton.disable = false }
|
||||
}
|
||||
}
|
||||
// applicationController.showChatPane()
|
||||
|
||||
}
|
||||
case Failure(exception) => {
|
||||
logger.error(s"${exception.getMessage()}")
|
||||
logger.warn("Login unsuccessful network problem")
|
||||
updateErrorLabel("Error logging in - Please check your network")
|
||||
// applicationController.showChatPane()
|
||||
onFX { submitButton.disable = false }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -141,5 +141,4 @@ class LoginController @Inject() (
|
||||
username: String,
|
||||
password: String
|
||||
)
|
||||
|
||||
}
|
||||
|
@ -11,11 +11,13 @@ import com.typesafe.scalalogging.LazyLogging
|
||||
import wow.doge.chatto.messagebuble.BubbledMDFXNode
|
||||
import scalafx.scene.layout.GridPane
|
||||
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 {
|
||||
|
||||
@FXML var menuBar: MenuBar = _
|
||||
@FXML private var menuBar: MenuBar = _
|
||||
// @FXML
|
||||
// var workspacePane: Pane = _
|
||||
// @FXML
|
||||
@ -23,9 +25,7 @@ class MainViewController extends ViewController with LazyLogging {
|
||||
// @FXML
|
||||
// var navigationPane: Pane = _
|
||||
|
||||
@FXML var mainPane: Pane = _
|
||||
|
||||
// @FXML var chatPane: Pane = _
|
||||
@FXML private var mainPane: HBox = _
|
||||
|
||||
lazy val workspaceController = getController[WorkspaceController]()
|
||||
lazy val navigationController = getController[NavigationController]()
|
||||
@ -33,22 +33,21 @@ class MainViewController extends ViewController with LazyLogging {
|
||||
lazy val loginController = getController[LoginController]()
|
||||
lazy val chatController = getController[ChatController]()
|
||||
|
||||
// val bubbleNode = new BubbledMDFXNode("Wow")
|
||||
|
||||
var workspaceManager: ContentManager = _
|
||||
var navigationManager: ContentManager = _
|
||||
var statusBarManager: ContentManager = _
|
||||
var mainManager: ContentManager = _
|
||||
|
||||
override def didGainVisibilityFirstTime() {
|
||||
// menuBar.setUseSystemMenuBar(true)
|
||||
override def didGainVisibilityFirstTime() = {
|
||||
menuBar.setUseSystemMenuBar(true)
|
||||
// menuBar.setVisible(false)
|
||||
|
||||
// navigationManager =
|
||||
// ContentManager(navigationPane, this, navigationController)
|
||||
// statusBarManager = ContentManager(statusPane, this, statusBarController)
|
||||
// workspaceManager = ContentManager(workspacePane, this, workspaceController)
|
||||
mainManager = ContentManager(mainPane, this, loginController)
|
||||
mainManager = ContentManager(mainPane, this, chatController)
|
||||
chatController.chatMainPane.hgrow = Priority.ALWAYS
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,12 +5,12 @@ import javafx.scene.control.Button
|
||||
|
||||
class NavigationController extends AbstractViewController {
|
||||
|
||||
def actionClickButton(event: ActionEvent) {
|
||||
def actionClickButton(event: ActionEvent) = {
|
||||
logger.debug(event.toString)
|
||||
statusBarController.updateLabel(event.getSource.asInstanceOf[Button])
|
||||
}
|
||||
|
||||
def actionHotReload(event: ActionEvent) {
|
||||
def actionHotReload(event: ActionEvent) = {
|
||||
applicationController.replacePrimarySceneContent()
|
||||
logger.debug("Hot Reload Succeeded")
|
||||
statusBarController.updateLabel(event.getSource.asInstanceOf[Button])
|
||||
|
@ -15,7 +15,7 @@ class WorkspaceController @Inject() (applicationName: ApplicationName)
|
||||
@FXML
|
||||
var infoLabel: Label = _
|
||||
|
||||
override def didGainVisibilityFirstTime() {
|
||||
override def didGainVisibilityFirstTime() = {
|
||||
infoLabel.setText(applicationName.name)
|
||||
}
|
||||
}
|
||||
|
@ -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"))
|
||||
// )
|
||||
// })
|
||||
// )
|
@ -52,12 +52,12 @@ class UserService @Inject() (appDataHandler: AppDataHandler)(
|
||||
private def endpoint(uri: String) = uri"$baseUrl/$uri"
|
||||
|
||||
def getUsers(credentials: UserCredentials) = async {
|
||||
logger.debug(s"${appDataHandler.appData}")
|
||||
println(
|
||||
write[ActiveUser](
|
||||
ActiveUser("hmm what is it", true, Some(ZonedDateTime.now()))
|
||||
)
|
||||
)
|
||||
// logger.debug(s"${appDataHandler.appData}")
|
||||
// println(
|
||||
// write[ActiveUser](
|
||||
// ActiveUser("hmm what is it", true, Some(ZonedDateTime.now()))
|
||||
// )
|
||||
// )
|
||||
await {
|
||||
authBasicRequest(credentials)
|
||||
.get(uri"http://localhost:8080/api/chat/get/users")
|
||||
@ -67,7 +67,7 @@ class UserService @Inject() (appDataHandler: AppDataHandler)(
|
||||
}
|
||||
|
||||
def getMessages(credentials: UserCredentials) = async {
|
||||
logger.debug(s"${appDataHandler.appData}")
|
||||
// logger.debug(s"${appDataHandler.appData}")
|
||||
await {
|
||||
authBasicRequest(credentials)
|
||||
.get(uri"http://localhost:8080/api/chat/get/users")
|
||||
|
Loading…
Reference in New Issue
Block a user