Rohan Sircar
4 years ago
45 changed files with 3155 additions and 1 deletions
-
11.gitignore
-
1.scalafmt.conf
-
7CHANGES.md
-
4README.md
-
84build.sbt
-
1project/build.properties
-
4project/metals.sbt
-
6project/plugin.sbt
-
0src/main/resources/META-INF/beans.xml
-
8src/main/resources/application.conf
-
1src/main/resources/bundles/application.properties
-
1src/main/resources/bundles/application_de.properties
-
67src/main/resources/fxml/Chat.fxml
-
76src/main/resources/fxml/Login.fxml
-
71src/main/resources/fxml/MainView.fxml
-
20src/main/resources/fxml/Navigation.fxml
-
20src/main/resources/fxml/UserBox.fxml
-
17src/main/resources/fxml/Workspace.fxml
-
29src/main/resources/fxml/default.css
-
BINsrc/main/resources/images/backgroung.jpg
-
14src/main/resources/logback.xml
-
1513src/main/resources/styles/bootstrapfx.css
-
18src/main/resources/styles/markdown.css
-
16src/main/resources/styles/style2.css
-
57src/main/resources/styles/ui.css
-
30src/main/resources/styles/userbox.css
-
9src/main/scala/wow/doge/chatto/Application.scala
-
102src/main/scala/wow/doge/chatto/ApplicationController.scala
-
10src/main/scala/wow/doge/chatto/config/Beans.scala
-
52src/main/scala/wow/doge/chatto/control/UserBox.scala
-
37src/main/scala/wow/doge/chatto/controller/AbstractViewController.scala
-
80src/main/scala/wow/doge/chatto/controller/ChatController.scala
-
160src/main/scala/wow/doge/chatto/controller/LoginController.scala
-
54src/main/scala/wow/doge/chatto/controller/MainViewController.scala
-
18src/main/scala/wow/doge/chatto/controller/NavigationController.scala
-
46src/main/scala/wow/doge/chatto/controller/StatusBarController.scala
-
21src/main/scala/wow/doge/chatto/controller/WorkspaceController.scala
-
81src/main/scala/wow/doge/chatto/messagebubble/Bubble.java
-
23src/main/scala/wow/doge/chatto/messagebubble/BubbleSpec.java
-
178src/main/scala/wow/doge/chatto/messagebubble/BubbledLabel.java
-
135src/main/scala/wow/doge/chatto/messagebubble/BubbledMDFXNode.java
-
10src/main/scala/wow/doge/chatto/model/ChatUser.scala
-
46src/main/scala/wow/doge/chatto/service/UserService.scala
-
14src/main/scala/wow/doge/chatto/types/Types.scala
-
2version.sbt
@ -0,0 +1,11 @@ |
|||
.idea* |
|||
*.iml |
|||
project/target |
|||
target |
|||
lib |
|||
out |
|||
.DS_Store |
|||
.gitconfig |
|||
.vscode |
|||
.bloop |
|||
.metals |
@ -0,0 +1 @@ |
|||
version = "2.4.2" |
@ -0,0 +1,7 @@ |
|||
# Changes # |
|||
|
|||
## Versions |
|||
|
|||
### 0.1.0-SNAPSHOT |
|||
|
|||
* initial Version |
@ -1,3 +1,7 @@ |
|||
# Chatto-Desktop-ScalaFX |
|||
|
|||
WIP desktop client for Chatto reimplemented in ScalaFX and Sapphire Framework |
|||
|
|||
## Based on Sapphire |
|||
|
|||
A JavaFX Application Framework for Scala User. [https://sfxcode.github.io/sapphire-core](https://sfxcode.github.io/sapphire-core) |
@ -0,0 +1,84 @@ |
|||
name := "chatto-sapphire" |
|||
|
|||
organization := "wow.doge" |
|||
|
|||
scalaVersion := "2.13.1" |
|||
|
|||
mainClass := Some("wow.doge.chatto.Application") |
|||
|
|||
resolvers += "sfxcode-maven" at "https://bintray.com/sfxcode/maven/" |
|||
resolvers += "javafx-markdown-renderer" at "https://sandec.bintray.com/repo" |
|||
|
|||
libraryDependencies += "org.specs2" %% "specs2-core" % "4.7.1" % Test |
|||
|
|||
val JavaFXVersion = "11.0.2" |
|||
|
|||
val osName = System.getProperty("os.name") match { |
|||
case n if n.startsWith("Linux") => "linux" |
|||
case n if n.startsWith("Mac") => "mac" |
|||
case n if n.startsWith("Windows") => "win" |
|||
case _ => throw new Exception("Unknown platform!") |
|||
} |
|||
|
|||
fork := true |
|||
|
|||
libraryDependencies ++= Seq( |
|||
"base", |
|||
"controls", |
|||
"fxml", |
|||
"graphics", |
|||
"media", |
|||
"swing", |
|||
"web" |
|||
).map(m => "org.openjfx" % s"javafx-$m" % JavaFXVersion classifier osName) |
|||
|
|||
libraryDependencies += "com.sfxcode.sapphire" %% "sapphire-core" % "1.7.3" |
|||
|
|||
libraryDependencies += "com.sfxcode.sapphire" %% "sapphire-extension" % "1.0.6" |
|||
|
|||
libraryDependencies += "ch.qos.logback" % "logback-classic" % "1.2.3" |
|||
|
|||
libraryDependencies ++= Seq( |
|||
"org.scalafx" %% "scalafx" % "12.0.2-R18", |
|||
"org.scalafx" %% "scalafx-extras" % "0.3.4", |
|||
"com.softwaremill.sttp.client" %% "json4s" % "2.1.1", |
|||
"org.json4s" %% "json4s-native" % "3.6.7", |
|||
"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.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" |
|||
) |
|||
libraryDependencies += "org.asynchttpclient" % "async-http-client" % "2.12.1" |
|||
libraryDependencies += "com.softwaremill.macwire" %% "macros" % "2.3.3" |
|||
scalacOptions ++= Seq("-Ymacro-annotations", "-deprecation") |
|||
|
|||
libraryDependencies += "org.scalafx" %% "scalafxml-core-sfx8" % "0.5" |
|||
// https://mvnrepository.com/artifact/com.jfoenix/jfoenix |
|||
libraryDependencies += "com.jfoenix" % "jfoenix" % "9.0.9" |
|||
// https://mvnrepository.com/artifact/org.kordamp.bootstrapfx/bootstrapfx-core |
|||
libraryDependencies += "org.kordamp.bootstrapfx" % "bootstrapfx-core" % "0.2.4" |
|||
|
|||
enablePlugins(BuildInfoPlugin) |
|||
|
|||
buildInfoPackage := "wow.doge.chatto" |
|||
|
|||
buildInfoOptions += BuildInfoOption.BuildTime |
|||
|
|||
enablePlugins(JavaFxPlugin) |
|||
|
|||
javaFxMainClass := "wow.doge.chatto.Application" |
|||
|
|||
javaFxJvmargs := Seq("-Xms512m", "-Xmx1024m", "-XX:ReservedCodeCacheSize=128m") |
|||
|
|||
javaFxTitle := "chatto-sapphire" |
|||
|
|||
javaFxCategory := "Aplication" |
|||
|
|||
javaFxNativeBundles := "image" |
|||
|
|||
javaFxVerbose := true |
@ -0,0 +1 @@ |
|||
sbt.version=1.3.8 |
@ -0,0 +1,4 @@ |
|||
// DO NOT EDIT! This file is auto-generated. |
|||
// This file enables sbt-bloop to create bloop config files. |
|||
|
|||
addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.4.0-RC1-229-b7c15aa9") |
@ -0,0 +1,6 @@ |
|||
addSbtPlugin("com.timushev.sbt" % "sbt-updates" % "0.5.0") |
|||
|
|||
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.9.0") |
|||
|
|||
addSbtPlugin("com.quadstingray" % "sbt-javafx" % "1.5.2") |
|||
|
@ -0,0 +1,8 @@ |
|||
sapphire.core.fxml.basePath="/fxml/" |
|||
application.name = "Application" |
|||
project.name = "chatto-sapphire" |
|||
project.version = "0.1.0-SNAPSHOT" |
|||
stage.default { |
|||
height = 600 |
|||
width = 800 |
|||
} |
@ -0,0 +1 @@ |
|||
navigation.toggle=Toggle Workspace |
@ -0,0 +1 @@ |
|||
navigation.toggle=Bereich wechseln |
@ -0,0 +1,67 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
|
|||
<?import java.net.URL ?> |
|||
<?import javafx.geometry.Insets ?> |
|||
<?import javafx.scene.control.Button ?> |
|||
<?import javafx.scene.control.Label ?> |
|||
<?import javafx.scene.control.ListView ?> |
|||
<?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.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"> |
|||
<left> |
|||
<VBox fx:id="usersVBox" alignment="TOP_CENTER" prefHeight="200.0" prefWidth="175.0" BorderPane.alignment="CENTER"> |
|||
<children> |
|||
<Button mnemonicParsing="false" styleClass="userButton" text="User1" VBox.vgrow="ALWAYS"> |
|||
<VBox.margin> |
|||
<Insets /> |
|||
</VBox.margin> |
|||
</Button> |
|||
<Button mnemonicParsing="false" styleClass="userButton" text="User2"> |
|||
<VBox.margin> |
|||
<Insets /> |
|||
</VBox.margin> |
|||
</Button> |
|||
</children> |
|||
</VBox> |
|||
</left> |
|||
<center> |
|||
<VBox prefHeight="200.0" prefWidth="100.0" spacing="5.0" BorderPane.alignment="CENTER"> |
|||
<children> |
|||
<ListView fx:id="chatListView" prefHeight="792.0" prefWidth="610.0" /> |
|||
<TextArea id="chatTextArea" fx:id="chatTextArea" editable="false" prefHeight="474.0" prefWidth="690.0" styleClass="lead" visible="false" VBox.vgrow="ALWAYS"> |
|||
<VBox.margin> |
|||
<Insets /> |
|||
</VBox.margin> |
|||
</TextArea> |
|||
<HBox prefHeight="50.0" prefWidth="790.0" spacing="2.0"> |
|||
<children> |
|||
<Label fx:id="label" contentDisplay="CENTER" maxWidth="100.0" prefHeight="30.0" prefWidth="52.0" text="Label" /> |
|||
<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"> |
|||
<children> |
|||
|
|||
<Button fx:id="logoutButton" styleClass="btn, btn-primary" text="Logout" /> |
|||
<Button fx:id="submitButton" styleClass="btn, btn-primary" text="Submit" /> |
|||
|
|||
</children> |
|||
</FlowPane> |
|||
</children> |
|||
</HBox> |
|||
</children> |
|||
<BorderPane.margin> |
|||
<Insets left="5.0" /> |
|||
</BorderPane.margin> |
|||
</VBox> |
|||
</center> |
|||
<stylesheets> |
|||
<URL value="@../styles/ui.css" /> |
|||
<URL value="@../styles/bootstrapfx.css" /> |
|||
</stylesheets> |
|||
</BorderPane> |
@ -0,0 +1,76 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
|
|||
<?import com.jfoenix.controls.JFXButton ?> |
|||
<?import com.jfoenix.controls.JFXPasswordField ?> |
|||
<?import com.jfoenix.controls.JFXTextField ?> |
|||
<?import java.net.URL ?> |
|||
<?import javafx.scene.control.Label ?> |
|||
<?import javafx.scene.effect.DropShadow ?> |
|||
<?import javafx.scene.layout.ColumnConstraints ?> |
|||
<?import javafx.scene.layout.GridPane ?> |
|||
<?import javafx.scene.layout.RowConstraints ?> |
|||
<?import javafx.scene.layout.VBox ?> |
|||
<?import javafx.scene.text.Font ?> |
|||
|
|||
<!-- 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"> |
|||
<columnConstraints> |
|||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="257.0" minWidth="10.0" prefWidth="122.0" /> |
|||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="667.0" /> |
|||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="121.0" minWidth="10.0" prefWidth="119.0" /> |
|||
</columnConstraints> |
|||
<rowConstraints> |
|||
<RowConstraints maxHeight="170.0" minHeight="0.0" prefHeight="54.0" vgrow="SOMETIMES" /> |
|||
<RowConstraints minHeight="10.0" prefHeight="429.0" vgrow="SOMETIMES" /> |
|||
<RowConstraints maxHeight="63.0" minHeight="0.0" prefHeight="48.0" vgrow="SOMETIMES" /> |
|||
</rowConstraints> |
|||
<children> |
|||
<VBox alignment="CENTER" fillWidth="false" prefHeight="431.0" prefWidth="283.0" spacing="20.0" style="-fx-background-color: #fff; -fx-background-radius: 40px;" GridPane.columnIndex="1" GridPane.rowIndex="1"> |
|||
<effect> |
|||
<DropShadow color="#9e9e9e" /> |
|||
</effect> |
|||
<children> |
|||
<Label lineSpacing="10.0" text="Sign In" textFill="#004ecd"> |
|||
<font> |
|||
<Font name="Microsoft JhengHei UI Light" size="28.0" /> |
|||
</font> |
|||
</Label> |
|||
<Label alignment="CENTER" prefHeight="37.0" prefWidth="324.0" text="Hi, please login to view your messages" textAlignment="CENTER" textFill="#727070" wrapText="true"> |
|||
<font> |
|||
<Font size="14.0" /> |
|||
</font> |
|||
</Label> |
|||
<JFXTextField 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" 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" /> |
|||
|
|||
<!-- 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"> |
|||
<font> |
|||
<Font size="14.0" /> |
|||
</font> |
|||
</Label> |
|||
|
|||
<Label alignment="CENTER" prefHeight="31.0" prefWidth="263.0" text="Forgot password" textAlignment="CENTER" textFill="#727070" wrapText="true"> |
|||
<font> |
|||
<Font size="14.0" /> |
|||
</font> |
|||
</Label> |
|||
<Label alignment="CENTER" prefHeight="31.0" prefWidth="221.0" text="Create a new account " textAlignment="CENTER" textFill="#727070" wrapText="true"> |
|||
<font> |
|||
<Font size="14.0" /> |
|||
</font> |
|||
</Label> |
|||
</children> |
|||
</VBox> |
|||
</children> |
|||
<stylesheets> |
|||
<URL value="@../styles/style2.css" /> |
|||
<URL value="@../styles/bootstrapfx.css" /> |
|||
</stylesheets> |
|||
</GridPane> |
@ -0,0 +1,71 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
|
|||
<?import java.net.* ?> |
|||
<?import javafx.scene.layout.* ?> |
|||
<?import javafx.scene.control.* ?> |
|||
|
|||
<AnchorPane 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> |
|||
<MenuBar VBox.vgrow="NEVER" fx:id="menuBar"> |
|||
<menus> |
|||
<Menu mnemonicParsing="false" text="File"> |
|||
<items> |
|||
<MenuItem mnemonicParsing="false" text="New" /> |
|||
<MenuItem mnemonicParsing="false" text="Open…" /> |
|||
<Menu mnemonicParsing="false" text="Open Recent" /> |
|||
<SeparatorMenuItem mnemonicParsing="false" /> |
|||
<MenuItem mnemonicParsing="false" text="Close" /> |
|||
<MenuItem mnemonicParsing="false" text="Save" /> |
|||
<MenuItem mnemonicParsing="false" text="Save As…" /> |
|||
<MenuItem mnemonicParsing="false" text="Revert" /> |
|||
<SeparatorMenuItem mnemonicParsing="false" /> |
|||
<MenuItem mnemonicParsing="false" text="Preferences…" /> |
|||
<SeparatorMenuItem mnemonicParsing="false" /> |
|||
<MenuItem mnemonicParsing="false" text="Quit" /> |
|||
</items> |
|||
</Menu> |
|||
<Menu mnemonicParsing="false" text="Edit"> |
|||
<items> |
|||
<MenuItem mnemonicParsing="false" text="Undo" /> |
|||
<MenuItem mnemonicParsing="false" text="Redo" /> |
|||
<SeparatorMenuItem mnemonicParsing="false" /> |
|||
<MenuItem mnemonicParsing="false" text="Cut" /> |
|||
<MenuItem mnemonicParsing="false" text="Copy" /> |
|||
<MenuItem mnemonicParsing="false" text="Paste" /> |
|||
<MenuItem mnemonicParsing="false" text="Delete" /> |
|||
<SeparatorMenuItem mnemonicParsing="false" /> |
|||
<MenuItem mnemonicParsing="false" text="Select All" /> |
|||
<MenuItem mnemonicParsing="false" text="Unselect All" /> |
|||
</items> |
|||
</Menu> |
|||
<Menu mnemonicParsing="false" text="Help"> |
|||
<items> |
|||
<MenuItem mnemonicParsing="false" text="About MyHelloApp" /> |
|||
</items> |
|||
</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"/> |
|||
</center> |
|||
<bottom> |
|||
<AnchorPane fx:id="statusPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" |
|||
prefHeight="30.0" styleClass="status"/> |
|||
</bottom> |
|||
</BorderPane> --> |
|||
<AnchorPane fx:id="loginPane"></AnchorPane> |
|||
<AnchorPane fx:id="chatPane"></AnchorPane> |
|||
</children> |
|||
<stylesheets> |
|||
<URL value="@default.css" /> |
|||
<URL value="@../styles/ui.css" /> |
|||
</stylesheets> |
|||
</AnchorPane> |
@ -0,0 +1,20 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
|
|||
<?import javafx.geometry.Insets?> |
|||
<?import javafx.scene.control.Button?> |
|||
<?import javafx.scene.layout.AnchorPane?> |
|||
<?import javafx.scene.layout.HBox?> |
|||
|
|||
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="40.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="wow.doge.chatto.controller.NavigationController"> |
|||
<children> |
|||
<HBox layoutY="-10.0" prefHeight="40.0" prefWidth="600.0" spacing="10.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"> |
|||
<children> |
|||
<Button mnemonicParsing="false" onAction="#actionClickButton" text="Navigation Button" /> |
|||
<Button mnemonicParsing="false" onAction="#actionHotReload" text="Hot Reload FXML" textFill="RED" /> |
|||
</children> |
|||
<padding> |
|||
<Insets left="10.0" top="5.0" /> |
|||
</padding> |
|||
</HBox> |
|||
</children> |
|||
</AnchorPane> |
@ -0,0 +1,20 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
|
|||
<?import java.net.URL ?> |
|||
<?import javafx.scene.control.Label ?> |
|||
<?import javafx.scene.control.RadioButton ?> |
|||
<?import javafx.scene.layout.VBox ?> |
|||
|
|||
<!-- fx:controller="com.example.javafx.control.UserBox" --> |
|||
|
|||
<fx:root prefHeight="65.0" styleClass="btn, btn-primary, user-box" type="VBox" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1"> |
|||
<children> |
|||
<!-- <Label fx:id="nameLabel" id="nameLabel" text="John Doe" /> --> |
|||
<RadioButton fx:id="_userRadioButton" mnemonicParsing="false" styleClass="h1, user-radio, lead" text="John Doe Radio" /> |
|||
<Label fx:id="_messageLabel" styleClass="messageLabel, lbl" text="Hey there, how are you?" /> |
|||
</children> |
|||
<stylesheets> |
|||
<URL value="@../styles/userbox.css" /> |
|||
<URL value="@../styles/bootstrapfx.css" /> |
|||
</stylesheets> |
|||
</fx:root> |
@ -0,0 +1,17 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
|
|||
<?import javafx.scene.control.Label?> |
|||
<?import javafx.scene.layout.*?> |
|||
<?import java.net.URL?> |
|||
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" |
|||
styleClass="workspace" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" |
|||
AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" xmlns="http://javafx.com/javafx/null" |
|||
xmlns:fx="http://javafx.com/fxml/1" |
|||
fx:controller="wow.doge.chatto.controller.WorkspaceController"> |
|||
<children> |
|||
<Label fx:id="infoLabel" layoutX="79.0" layoutY="126.0" text="Workspace"/> |
|||
</children> |
|||
<stylesheets> |
|||
<URL value="@default.css"/> |
|||
</stylesheets> |
|||
</AnchorPane> |
@ -0,0 +1,29 @@ |
|||
.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; |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
After Width: 800 | Height: 533 | Size: 50 KiB |
@ -0,0 +1,14 @@ |
|||
<configuration> |
|||
|
|||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> |
|||
<!-- encoders are assigned the type |
|||
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default --> |
|||
<encoder> |
|||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> |
|||
</encoder> |
|||
</appender> |
|||
|
|||
<root level="info"> |
|||
<appender-ref ref="STDOUT" /> |
|||
</root> |
|||
</configuration> |
1513
src/main/resources/styles/bootstrapfx.css
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,18 @@ |
|||
* { |
|||
-mdfx-font-color: white; |
|||
-mdfx-border-color-1: #888; |
|||
|
|||
-mdfx-bg-color-1: #ccc; |
|||
-mdfx-bg-color-2: #ddd; |
|||
-mdfx-bg-color-3: #eee; |
|||
} |
|||
|
|||
.markdown-text { |
|||
-fx-font-family: ARIAL; |
|||
} |
|||
.markdown-italic { |
|||
-fx-font-style: italic; |
|||
} |
|||
.markdown-bold { |
|||
-fx-font-weight: bold; |
|||
} |
@ -0,0 +1,16 @@ |
|||
#rootPane{ |
|||
-fx-background-image: url("../images/backgroung.jpg"); |
|||
-fx-background-size: 1920.0 1080.0; |
|||
-fx-background-position: center center; |
|||
} |
|||
|
|||
.ikonli-font-icon{ |
|||
-fx-icon-size: 100px; |
|||
-fx-icon-color: blue; |
|||
} |
|||
|
|||
.user-radio .radio { |
|||
visibility: hidden; |
|||
-fx-pref-width: 0px; |
|||
-fx-max-width: 0px; |
|||
} |
@ -0,0 +1,57 @@ |
|||
/* .button { |
|||
-fx-background-color: #009688; |
|||
-fx-background-radius: 0.0; |
|||
-fx-text-fill: #FFFFFF; |
|||
-fx-margin: 0.0; |
|||
-fx-background-radius: 21.0px; |
|||
} */ |
|||
|
|||
/* .userButton{ |
|||
-fx-background-color: #ff9688; |
|||
-fx-background-radius: 0.0px; |
|||
-fx-pref-width: 100px; |
|||
-fx-pref-height: 40px; |
|||
-fx-background-insets: 5px; |
|||
} */ |
|||
.root{ |
|||
-fx-padding: 5.0 5.0 5.0 5.0; |
|||
-fx-background-image: url("../images/backgroung.jpg"); |
|||
-fx-background-size: 1920.0 1080.0; |
|||
-fx-background-position: center center; |
|||
} |
|||
|
|||
|
|||
#flowPane { |
|||
-fx-hgap: 5.0px; |
|||
-fx-vgap: 5.0px; |
|||
} |
|||
|
|||
.userVbox { |
|||
-fx-padding: 5.0 5.0 5.0 5.0; |
|||
-fx-background-insets: 5px; |
|||
-fx-background-size: 1920.0 1080.0; |
|||
-fx-background-position: center center; |
|||
-fx-background-color: #ff0055; |
|||
-fx-background-radius: 10px; |
|||
|
|||
} |
|||
|
|||
#chatTextArea{ |
|||
-fx-font-size: 1.4em; |
|||
} |
|||
|
|||
.my-list-cell { |
|||
-fx-background-color: null; |
|||
} |
|||
|
|||
.my-list-view { |
|||
-fx-background-color: null; |
|||
} |
|||
|
|||
.my-list-view > .list-cell { |
|||
-fx-background-color: null; |
|||
} |
|||
|
|||
/*.myButton { |
|||
-fx-background-radius: 21.0px; |
|||
}*/ |
@ -0,0 +1,30 @@ |
|||
.user-box { |
|||
-fx-padding: 0.0 2.5 0.0 0.0; |
|||
-fx-background-radius: 0px; |
|||
-fx-border-color: #337ab7; |
|||
} |
|||
.user-box:selected { |
|||
-fx-background-color: red; |
|||
} |
|||
.user-radio .radio { |
|||
visibility: hidden; |
|||
-fx-pref-width: 0.0px; |
|||
-fx-max-width: 0.0px; |
|||
-fx-padding: 0.0 0.0 0.0 0.0; |
|||
} |
|||
|
|||
|
|||
.user-radio { |
|||
-fx-font-size: 20px ; |
|||
} |
|||
#nameLabel { |
|||
-fx-text-fill: #fff; |
|||
} |
|||
.user-radio { |
|||
-fx-text-fill: #fff; |
|||
} |
|||
.messageLabel { |
|||
-fx-padding: 0.0 0.0 0.0 5.0; |
|||
-fx-text-fill: #fff; |
|||
-fx-font-size: 15px ; |
|||
} |
@ -0,0 +1,9 @@ |
|||
package wow.doge.chatto |
|||
|
|||
import com.sfxcode.sapphire.core.ConfigValues |
|||
import com.sfxcode.sapphire.core.application.FXApp |
|||
|
|||
object Application extends FXApp with ConfigValues { |
|||
|
|||
override def title: String = configStringValue("project.name") |
|||
} |
@ -0,0 +1,102 @@ |
|||
package wow.doge.chatto |
|||
|
|||
import javax.enterprise.context.ApplicationScoped |
|||
import javax.enterprise.inject.Produces |
|||
import javax.inject.Named |
|||
import com.typesafe.config.ConfigFactory |
|||
import com.sfxcode.sapphire.core.controller.DefaultWindowController |
|||
// import org.asynchttpclient.Dsl._ |
|||
import wow.doge.chatto.controller.MainViewController |
|||
import sttp.client.asynchttpclient.future.AsyncHttpClientFutureBackend |
|||
import sttp.client._ |
|||
import scala.concurrent.ExecutionContext.Implicits.global |
|||
import scala.async.Async.{async, await} |
|||
import sttp.client.json4s._ |
|||
import org.json4s._ |
|||
import org.json4s.native.JsonMethods._ |
|||
import org.json4s.JsonDSL._ |
|||
import scala.util.Success |
|||
import scala.util.Failure |
|||
import com.softwaremill.quicklens._ |
|||
@Named |
|||
@ApplicationScoped |
|||
class ApplicationController extends DefaultWindowController { |
|||
// import ApplicationController._ |
|||
|
|||
lazy val mainViewController = getController[MainViewController]() |
|||
private implicit lazy val serialization = org.json4s.native.Serialization |
|||
private implicit lazy val backend = AsyncHttpClientFutureBackend() |
|||
|
|||
// override def width: Int = 400 |
|||
|
|||
def applicationDidLaunch() = { |
|||
logger.info("start " + this) |
|||
applicationEnvironment.loadResourceBundle("bundles/application") |
|||
replaceSceneContent(mainViewController) |
|||
} |
|||
|
|||
@Produces |
|||
def applicationName: ApplicationName = { |
|||
ApplicationName(configStringValue("application.name")) |
|||
} |
|||
|
|||
@Produces var appData: AppData = synchronized { |
|||
AppData(User.empty, "") |
|||
} |
|||
|
|||
@Produces |
|||
def httpBackend = backend |
|||
|
|||
def replacePrimarySceneContent(): Unit = { |
|||
// Styling |
|||
reloadStyles() |
|||
// Resources |
|||
applicationEnvironment.clearResourceBundleCache() |
|||
applicationEnvironment.loadResourceBundle("bundles/application") |
|||
// FXML |
|||
val newMainViewController = getController[MainViewController]() |
|||
replaceSceneContent(newMainViewController) |
|||
} |
|||
|
|||
override def applicationWillStop(): Unit = async { |
|||
super.applicationWillStop() |
|||
println("stopping") |
|||
await(httpBackend.close()) |
|||
System.exit(0) |
|||
} |
|||
|
|||
def showLoginPane() = { |
|||
appData = appData.copy(user = User.empty) |
|||
appData = appData.modify(_.user).using(_ => User.empty) |
|||
appData = appData.modify(_.user.username).using(_ => "") |
|||
replaceSceneContent(mainViewController.loginController) |
|||
} |
|||
|
|||
def showChatPane(): Unit = { |
|||
// import org.scalafx.extras._ |
|||
replaceSceneContent(mainViewController.chatController, true) |
|||
// 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) |
|||
} |
|||
} |
|||
final case class ApplicationName(name: String) |
|||
final case class User(username: String, password: String, token: String) |
|||
object User { |
|||
def empty = User("", "", "") |
|||
} |
|||
final case class AppData(user: User, sumth: String) |
@ -0,0 +1,10 @@ |
|||
package wow.doge.chatto.config |
|||
|
|||
import javax.enterprise.context.ApplicationScoped |
|||
import javax.enterprise.inject.Produces |
|||
|
|||
@ApplicationScoped |
|||
class AppBeans { |
|||
@Produces |
|||
def something: String = "Hello" |
|||
} |
@ -0,0 +1,52 @@ |
|||
package wow.doge.chatto.control |
|||
|
|||
import javafx.scene.layout.VBox |
|||
import javafx.fxml.FXML |
|||
import javafx.scene.control.RadioButton |
|||
import javafx.scene.control.Label |
|||
import javafx.fxml.FXMLLoader |
|||
import scalafx.Includes._ |
|||
|
|||
class UserBox() extends VBox() { |
|||
@FXML private var _userRadioButton: RadioButton = _ |
|||
@FXML private var _messageLabel: Label = _ |
|||
|
|||
def userRadioButton = this._userRadioButton |
|||
def messageLabel = this._messageLabel |
|||
|
|||
init() |
|||
|
|||
def init() = { |
|||
val fxmlLoader = new FXMLLoader( |
|||
getClass().getResource("/fxml/UserBox.fxml") |
|||
) |
|||
fxmlLoader.setRoot(this); |
|||
fxmlLoader.setController(this); |
|||
|
|||
fxmlLoader.load(); |
|||
|
|||
// userRadioButton |
|||
// .selectedProperty() |
|||
// .addListener(changeListener => { |
|||
// if (userRadioButton.isSelected()) { |
|||
// getStyleClass().clear(); |
|||
// getStyleClass().addAll("btn", "btn-primary", "user-box"); |
|||
// } else { |
|||
// getStyleClass().clear(); |
|||
// getStyleClass().addAll("btn", "btn-primary", "user-box"); |
|||
// } |
|||
// }); |
|||
|
|||
userRadioButton.selected.onChange { (_, _, _) => |
|||
{ |
|||
getStyleClass().clear(); |
|||
getStyleClass().addAll("btn", "btn-primary", "user-box"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
|
|||
object UserBox { |
|||
// val ub = new UserBox() |
|||
} |
@ -0,0 +1,37 @@ |
|||
package wow.doge.chatto.controller |
|||
|
|||
import com.sfxcode.sapphire.core.controller.ViewController |
|||
import com.typesafe.scalalogging.LazyLogging |
|||
import wow.doge.chatto.ApplicationController |
|||
|
|||
abstract class AbstractViewController extends ViewController with LazyLogging { |
|||
|
|||
override def didGainVisibility(): Unit = { |
|||
statusBarController.statusLabel.setText( |
|||
"%s loaded".format(getClass.getSimpleName) |
|||
) |
|||
} |
|||
|
|||
def applicationController: ApplicationController = { |
|||
getBean[ApplicationController]() |
|||
|
|||
} |
|||
|
|||
def mainViewController: MainViewController = |
|||
applicationController.mainViewController |
|||
|
|||
/** |
|||
* |
|||
* @return |
|||
*/ |
|||
def statusBarController = getBean[StatusBarController]() |
|||
|
|||
/** |
|||
* |
|||
* @return workspace manager resolved by parent |
|||
*/ |
|||
def workspaceManager = mainViewController.workspaceManager |
|||
|
|||
// def loginManager = mainViewController.loginManager |
|||
|
|||
} |
@ -0,0 +1,80 @@ |
|||
package wow.doge.chatto.controller |
|||
|
|||
import javafx.fxml.FXML |
|||
import javafx.scene.control.Label |
|||
import javafx.scene.control.Button |
|||
import javafx.scene.layout.FlowPane |
|||
import javafx.scene.control.TextArea |
|||
import javafx.scene.control.ListView |
|||
import javafx.scene.layout.HBox |
|||
import javafx.scene.layout.VBox |
|||
import scalafx.Includes._ |
|||
import wow.doge.chatto.control.UserBox |
|||
import javafx.application.Platform |
|||
import javax.inject.Inject |
|||
import org.scalafx.extras._ |
|||
import wow.doge.chatto.messagebuble.BubbledMDFXNode |
|||
import wow.doge.chatto.service.UserService |
|||
import scala.concurrent.ExecutionContext |
|||
import scala.concurrent.ExecutionContext.Implicits.global |
|||
import com.typesafe.scalalogging.LazyLogging |
|||
// import wow.doge.chatto.controller.LoginController.Person |
|||
import com.sfxcode.sapphire.core.value.FXBean |
|||
|
|||
class ChatController @Inject() (userService: UserService) |
|||
extends AbstractViewController |
|||
with LazyLogging { |
|||
|
|||
@FXML private var label: Label = _ |
|||
@FXML private var flowPane: FlowPane = _ |
|||
@FXML private var submitButton: Button = _ |
|||
@FXML private var loginButton: Button = _ |
|||
@FXML private var chatTextArea: TextArea = _ |
|||
@FXML private var chatInput: TextArea = _ |
|||
@FXML private var usersVBox: VBox = _ |
|||
@FXML private var chatListView: ListView[HBox] = _ |
|||
// applicationController.show |
|||
|
|||
override def didGainVisibilityFirstTime(): Unit = { |
|||
super.didGainVisibilityFirstTime() |
|||
val ub = new UserBox() |
|||
this.stage.resizable = true |
|||
ub.messageLabel.text = "Hi there" |
|||
// ub.messageLabel.id = |
|||
ub.userRadioButton.text = "User 1" |
|||
usersVBox.children.clear() |
|||
usersVBox.children += ub |
|||
println("test") |
|||
println(s"Result = ${func()}") |
|||
offFX(println("hello from new thread")) |
|||
chatTextArea.visible <== !chatInput.text.isEmpty |
|||
chatTextArea.text <== chatInput.text |
|||
|
|||
for (r <- userService.func2()) yield (logger.info(s"${r.body}")) |
|||
|
|||
val person = Person(0, 10, "Billy") |
|||
val bean = FXBean[Person](person) |
|||
ub.messageLabel.text <== bean.getStringProperty("name") |
|||
// bean.getStringProperty("name") <== chatInput.text |
|||
|
|||
// bean.getStringProperty("name")() = "Lester" |
|||
println(bean.getValue("name")) |
|||
println(bean.getStringProperty("name")()) |
|||
// bean. |
|||
bean.updateValue("name", "Lester") |
|||
println(bean.bean) |
|||
|
|||
} |
|||
|
|||
override def didGainVisibility(): Unit = { |
|||
super.didGainVisibility() |
|||
} |
|||
def func() = { |
|||
val x = offFXAndWait { |
|||
2 + 3 |
|||
} |
|||
x |
|||
} |
|||
} |
|||
|
|||
final case class Person(id: Int, age: Int, name: String) |
@ -0,0 +1,160 @@ |
|||
package wow.doge.chatto.controller |
|||
|
|||
import com.typesafe.scalalogging.LazyLogging |
|||
import com.sfxcode.sapphire.core.controller.ViewController |
|||
import javafx.fxml.FXML |
|||
import com.jfoenix.controls.JFXButton |
|||
import com.jfoenix.controls.JFXTextField |
|||
import com.jfoenix.controls.JFXPasswordField |
|||
import scalafx.Includes._ |
|||
// import scalafx.application.Platform |
|||
import scalafx.event.ActionEvent |
|||
import com.sfxcode.sapphire.core.value.KeyBindings |
|||
import scalafx.scene.layout.VBox |
|||
import com.sfxcode.sapphire.core.value.FXBean |
|||
import javax.inject.Inject |
|||
import com.sfxcode.sapphire.core.value.FXBeanAdapter |
|||
import wow.doge.chatto.service.UserService |
|||
import scala.concurrent.ExecutionContext.Implicits.global |
|||
import scala.util.Success |
|||
import scala.util.Failure |
|||
import javafx.scene.control.Label |
|||
import javafx.scene.input.KeyCode |
|||
import scala.async.Async.{async, await} |
|||
import wow.doge.chatto.AppData |
|||
import wow.doge.chatto.User |
|||
import sttp.client._ |
|||
import scala.concurrent.Future |
|||
import sttp.client.asynchttpclient.WebSocketHandler |
|||
import wow.doge.chatto.types.AppTypes.HttpBackend |
|||
import wow.doge.chatto.types.AppTypes |
|||
|
|||
class LoginController @Inject() (userService: UserService, var appData: AppData)( |
|||
implicit backend: HttpBackend |
|||
) extends AbstractViewController |
|||
with LazyLogging |
|||
with AppTypes { |
|||
@FXML private var submitButton: JFXButton = _ |
|||
|
|||
@FXML private var usernameTextField: JFXTextField = _ |
|||
|
|||
@FXML private var passwordTextField: JFXPasswordField = _ |
|||
|
|||
@FXML private var errorLabel: Label = _ |
|||
|
|||
override def didGainVisibilityFirstTime(): Unit = { |
|||
super.didGainVisibilityFirstTime() |
|||
this.stage.resizable = false |
|||
usernameTextField.requestFocus() |
|||
submitButton.setOnAction(actionLogin) |
|||
|
|||
// println(something) |
|||
|
|||
val bindings = KeyBindings("usernameTextField", "passwordTextField") |
|||
// Expression Binding Example |
|||
// bindings.add( |
|||
// "usernameTextField", |
|||
// "${sf:i18n('personText', _self.usernameTextField(), _self.passwordTextField())})" |
|||
// ) |
|||
|
|||
val box = new VBox() |
|||
val adapter = FXBeanAdapter[Person](this) |
|||
// adapter. |
|||
val bean = FXBean[Person](Person("twar", "username", "password")) |
|||
// bean. |
|||
// bean.get |
|||
adapter.addBindings(bindings) |
|||
adapter.set(bean) |
|||
// adapter.addIntConverter("age") |
|||
// adapter.hasBeanProperty |
|||
// adapter.revert() |
|||
|
|||
// usernameTextField.onKeyPressed = (keyEvent) => { |
|||
// if (keyEvent.getCode() == KeyCode.ENTER) submitButton.fire() |
|||
// } |
|||
// submitButton.onKeyPressed = (keyEvent) => { |
|||
// if (keyEvent.getCode() == KeyCode.ENTER) submitButton.fire() |
|||
// } |
|||
// passwordTextField.onKeyPressed = (keyEvent) => { |
|||
// if (keyEvent.getCode() == KeyCode.ENTER) submitButton.fire() |
|||
// } |
|||
|
|||
Array(usernameTextField, passwordTextField, submitButton) |
|||
.foreach(_.onKeyPressed = (keyEvent) => { |
|||
if (keyEvent.getCode() == KeyCode.ENTER) submitButton.fire() |
|||
}) |
|||
|
|||
} |
|||
|
|||
override def didGainVisibility(): Unit = { |
|||
usernameTextField.requestFocus() |
|||
} |
|||
|
|||
def actionLogin(e: ActionEvent) = { |
|||
import org.scalafx.extras._ |
|||
val inputUserName = usernameTextField.text() |
|||
val inputPassword = passwordTextField.text() |
|||
|
|||
// val authenticated = |
|||
// inputPassword.equals("password") && inputUserName.equals("hmm") |
|||
login(inputUserName, inputPassword) onComplete { |
|||
case Success(value) => { |
|||
value.foreach(println) |
|||
value match { |
|||
case Some(token) => { |
|||
appData = |
|||
appData.copy(user = User(inputUserName, inputPassword, token)) |
|||
} |
|||
case None => { |
|||
onFX(errorLabel.text = |
|||
"Error logging in - please check your password" |
|||
) |
|||
logger.warn("Login unsuccessful wrong password") |
|||
} |
|||
} |
|||
// Platform.runLater(() => applicationController.showChatPane()) |
|||
onFX(applicationController.showChatPane()) |
|||
} |
|||
case Failure(exception) => { |
|||
logger.error(s"${exception.getMessage()}") |
|||
logger.warn("Login unsuccessful network problem") |
|||
onFX { |
|||
errorLabel.text = "Error logging in - Please check your network" |
|||
applicationController.showChatPane() |
|||
} |
|||
// onFX(applicationController.showChatPane()) |
|||
} |
|||
} |
|||
// if (authenticated) { |
|||
// passwordTextField.clear() |
|||
// val res = Result(username = inputUserName, password = inputPassword) |
|||
// println(res) |
|||
// // loginManager. |
|||
|
|||
// applicationController.showChatPane() |
|||
// } else { |
|||
// logger.error("Login Error") |
|||
// } |
|||
} |
|||
|
|||
def login(username: String, password: String) = async { |
|||
val resp = await(initLogin(username, password)) |
|||
resp.header("X-AUTH-TOKEN") |
|||
} |
|||
|
|||
def initLogin(username: String, password: String) = { |
|||
basicRequest.auth |
|||
.basic(username, password) |
|||
.get(uri"http://localhost:8080/api/chat/get/token") |
|||
.send() |
|||
} |
|||
|
|||
final case class Result(username: String, password: String) |
|||
|
|||
final case class Person( |
|||
id: String, |
|||
usernameTextField: String, |
|||
passwordTextField: String |
|||
) |
|||
|
|||
} |
@ -0,0 +1,54 @@ |
|||
package wow.doge.chatto.controller |
|||
|
|||
import javafx.fxml.FXML |
|||
import javafx.scene.control.MenuBar |
|||
import javafx.scene.layout.Pane |
|||
import javax.enterprise.event.Observes |
|||
|
|||
import com.sfxcode.sapphire.core.controller.ViewController |
|||
import com.sfxcode.sapphire.core.scene.{ContentDidChangeEvent, ContentManager} |
|||
import com.typesafe.scalalogging.LazyLogging |
|||
import wow.doge.chatto.messagebuble.BubbledMDFXNode |
|||
import scalafx.scene.layout.GridPane |
|||
import scalafx.Includes._ |
|||
// import wow.doge.chatto. |
|||
|
|||
class MainViewController extends ViewController with LazyLogging { |
|||
|
|||
@FXML var menuBar: MenuBar = _ |
|||
// @FXML |
|||
// var workspacePane: Pane = _ |
|||
// @FXML |
|||
// var statusPane: Pane = _ |
|||
// @FXML |
|||
// var navigationPane: Pane = _ |
|||
|
|||
@FXML var loginPane: Pane = _ |
|||
|
|||
@FXML var chatPane: Pane = _ |
|||
|
|||
lazy val workspaceController = getController[WorkspaceController]() |
|||
lazy val navigationController = getController[NavigationController]() |
|||
lazy val statusBarController = getBean[StatusBarController]() |
|||
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) |
|||
menuBar.setVisible(false) |
|||
|
|||
// navigationManager = |
|||
// ContentManager(navigationPane, this, navigationController) |
|||
// statusBarManager = ContentManager(statusPane, this, statusBarController) |
|||
// workspaceManager = ContentManager(workspacePane, this, workspaceController) |
|||
mainManager = ContentManager(loginPane, this, loginController) |
|||
} |
|||
|
|||
} |
@ -0,0 +1,18 @@ |
|||
package wow.doge.chatto.controller |
|||
|
|||
import javafx.event.ActionEvent |
|||
import javafx.scene.control.Button |
|||
|
|||
class NavigationController extends AbstractViewController { |
|||
|
|||
def actionClickButton(event: ActionEvent) { |
|||
logger.debug(event.toString) |
|||
statusBarController.updateLabel(event.getSource.asInstanceOf[Button]) |
|||
} |
|||
|
|||
def actionHotReload(event: ActionEvent) { |
|||
applicationController.replacePrimarySceneContent() |
|||
logger.debug("Hot Reload Succeeded") |
|||
statusBarController.updateLabel(event.getSource.asInstanceOf[Button]) |
|||
} |
|||
} |
@ -0,0 +1,46 @@ |
|||
package wow.doge.chatto.controller |
|||
|
|||
import com.typesafe.scalalogging.LazyLogging |
|||
import javafx.geometry.Insets |
|||
import javafx.scene.control.{Button, Label} |
|||
import javafx.scene.layout.HBox |
|||
import javax.enterprise.context.ApplicationScoped |
|||
import javax.inject.Named |
|||
|
|||
@Named |
|||
@ApplicationScoped |
|||
class StatusBarController extends AbstractViewController with LazyLogging { |
|||
|
|||
rootPane = new HBox() |
|||
|
|||
val actionLabel: Label = new Label("Status Bar Action Label ...") |
|||
actionLabel.setPadding(new Insets(5)) |
|||
|
|||
val statusLabel: Label = new Label("Status Bar Status Label ...") |
|||
statusLabel.setPadding(new Insets(5)) |
|||
|
|||
val statusButton = new Button("Status Button 1") |
|||
statusButton.setOnAction(_ => { |
|||
logger.debug("%s".format(statusButton.getText)) |
|||
updateLabel(statusButton) |
|||
}) |
|||
|
|||
val statusButton2 = new Button("Status Button 2") |
|||
statusButton2.setOnAction(_ => { |
|||
logger.debug("%s".format(statusButton2.getText)) |
|||
updateLabel(statusButton2) |
|||
}) |
|||
|
|||
val box = new HBox() |
|||
box.setId("statusBar") |
|||
box.setPadding(new Insets(10)) |
|||
box.setSpacing(10.0) |
|||
|
|||
box.getChildren.addAll(statusButton, statusButton2, statusLabel, actionLabel) |
|||
|
|||
rootPane = box |
|||
|
|||
def updateLabel(button: Button): Unit = { |
|||
actionLabel.setText("%s clicked".format(button.getText)) |
|||
} |
|||
} |
@ -0,0 +1,21 @@ |
|||
package wow.doge.chatto.controller |
|||
|
|||
import javafx.fxml.FXML |
|||
import javafx.scene.control.Label |
|||
import javax.inject.Inject |
|||
|
|||
import wow.doge.chatto.ApplicationName |
|||
|
|||
class WorkspaceController @Inject() (applicationName: ApplicationName) |
|||
extends AbstractViewController { |
|||
|
|||
// @Inject |
|||
// var applicationName: ApplicationName = _ |
|||
|
|||
@FXML |
|||
var infoLabel: Label = _ |
|||
|
|||
override def didGainVisibilityFirstTime() { |
|||
infoLabel.setText(applicationName.name) |
|||
} |
|||
} |
@ -0,0 +1,81 @@ |
|||
package wow.doge.chatto.messagebuble; |
|||
|
|||
import javafx.scene.shape.HLineTo; |
|||
import javafx.scene.shape.LineTo; |
|||
import javafx.scene.shape.MoveTo; |
|||
import javafx.scene.shape.Path; |
|||
import javafx.scene.shape.VLineTo; |
|||
|
|||
public class Bubble extends Path { |
|||
|
|||
/* |
|||
* Copyright {2015} {Terah Laweh} |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not |
|||
* use this file except in compliance with the License. You may obtain a copy of |
|||
* the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0 |
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
|||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
|||
* License for the specific language governing permissions and limitations under |
|||
* the License. |
|||
*/ |
|||
|
|||
public Bubble(BubbleSpec bubbleSpec) { |
|||
super(); |
|||
switch (bubbleSpec) { |
|||
case FACE_BOTTOM: |
|||
break; |
|||
case FACE_LEFT_BOTTOM: |
|||
drawRectBubbleLeftBaselineIndicator(); |
|||
break; |
|||
case FACE_LEFT_CENTER: |
|||
drawRectBubbleLeftCenterIndicator(); |
|||
break; |
|||
case FACE_RIGHT_BOTTOM: |
|||
drawRectBubbleRightBaselineIndicator(); |
|||
break; |
|||
case FACE_RIGHT_CENTER: |
|||
drawRectBubbleRightCenterIndicator(); |
|||
break; |
|||
case FACE_TOP: |
|||
drawRectBubbleToplineIndicator(); |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
|
|||
} |
|||
|
|||
private void drawRectBubbleToplineIndicator() { |
|||
getElements().addAll(new MoveTo(1.0f, 1.2f), new HLineTo(2.5f), new LineTo(2.7f, 1.0f), new LineTo(2.9f, 1.2f), |
|||
new HLineTo(4.4f), new VLineTo(4f), new HLineTo(1.0f), new VLineTo(1.2f)); |
|||
} |
|||
|
|||
private void drawRectBubbleRightBaselineIndicator() { |
|||
getElements().addAll(new MoveTo(3.0f, 1.0f), new HLineTo(0f), new VLineTo(4f), new HLineTo(3.0f), |
|||
new LineTo(2.8f, 3.8f), new VLineTo(1f)); |
|||
} |
|||
|
|||
private void drawRectBubbleLeftBaselineIndicator() { |
|||
getElements().addAll(new MoveTo(1.2f, 1.0f), new HLineTo(3f), new VLineTo(4f), new HLineTo(1.0f), |
|||
new LineTo(1.2f, 3.8f), new VLineTo(1f)); |
|||
} |
|||
|
|||
private void drawRectBubbleRightCenterIndicator() { |
|||
getElements().addAll(new MoveTo(3.0f, 2.5f), new LineTo(2.8f, 2.4f), new VLineTo(1f), new HLineTo(0f), |
|||
new VLineTo(4f), new HLineTo(2.8f), new VLineTo(2.7f), new LineTo(3.0f, 2.5f)); |
|||
} |
|||
|
|||
protected double drawRectBubbleIndicatorRule = 0.2; |
|||
|
|||
private void drawRectBubbleLeftCenterIndicator() { |
|||
getElements().addAll(new MoveTo(1.0f, 2.5f), new LineTo(1.2f, 2.4f), new VLineTo(1f), new HLineTo(2.9f), |
|||
new VLineTo(4f), new HLineTo(1.2f), new VLineTo(2.7f), new LineTo(1.0f, 2.5f)); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,23 @@ |
|||
package wow.doge.chatto.messagebuble; |
|||
|
|||
public enum BubbleSpec { |
|||
|
|||
/* |
|||
* Copyright {2015} {Terah Laweh} |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not |
|||
* use this file except in compliance with the License. You may obtain a copy of |
|||
* the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0 |
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
|||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
|||
* License for the specific language governing permissions and limitations under |
|||
* the License. |
|||
*/ |
|||
|
|||
FACE_TOP, FACE_BOTTOM, FACE_LEFT_BOTTOM, FACE_LEFT_CENTER, FACE_RIGHT_BOTTOM, FACE_RIGHT_CENTER; |
|||
|
|||
} |
@ -0,0 +1,178 @@ |
|||
package wow.doge.chatto.messagebuble; |
|||
|
|||
import javafx.beans.InvalidationListener; |
|||
import javafx.beans.Observable; |
|||
import javafx.beans.value.ChangeListener; |
|||
import javafx.beans.value.ObservableValue; |
|||
import javafx.geometry.Insets; |
|||
import javafx.scene.Node; |
|||
import javafx.scene.control.Label; |
|||
import javafx.scene.effect.DropShadow; |
|||
import javafx.scene.paint.Color; |
|||
import javafx.scene.shape.Shape; |
|||
|
|||
public class BubbledLabel extends Label { |
|||
|
|||
/* |
|||
* Copyright {2015} {Terah Laweh} |
|||
* |
|||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not |
|||
* use this file except in compliance with the License. You may obtain a copy of |
|||
* the License at |
|||
* |
|||
* http://www.apache.org/licenses/LICENSE-2.0 |
|||
* |
|||
* Unless required by applicable law or agreed to in writing, software |
|||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
|||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
|||
* License for the specific language governing permissions and limitations under |
|||
* the License. |
|||
*/ |
|||
|
|||
private BubbleSpec bs = BubbleSpec.FACE_LEFT_CENTER; |
|||
private double pading = 5.0; |
|||
private boolean systemCall = false; |
|||
|
|||
public BubbledLabel() { |
|||
super(); |
|||
init(); |
|||
} |
|||
|
|||
public BubbledLabel(String arg0, Node arg1) { |
|||
super(arg0, arg1); |
|||
init(); |
|||
} |
|||
|
|||
public BubbledLabel(String arg0) { |
|||
super(arg0); |
|||
init(); |
|||
} |
|||
|
|||
public BubbledLabel(BubbleSpec bubbleSpec) { |
|||
super(); |
|||
this.bs = bubbleSpec; |
|||
init(); |
|||
} |
|||
|
|||
public BubbledLabel(String arg0, Node arg1, BubbleSpec bubbleSpec) { |
|||
super(arg0, arg1); |
|||
this.bs = bubbleSpec; |
|||
init(); |
|||
} |
|||
|
|||
public BubbledLabel(String arg0, BubbleSpec bubbleSpec) { |
|||
super(arg0); |
|||
this.bs = bubbleSpec; |
|||
init(); |
|||
} |
|||
|
|||
private void init() { |
|||
DropShadow ds = new DropShadow(); |
|||
ds.setOffsetX(1.3); |
|||
ds.setOffsetY(1.3); |
|||
ds.setColor(Color.DARKGRAY); |
|||
setPrefSize(Label.USE_COMPUTED_SIZE, Label.USE_COMPUTED_SIZE); |
|||
shapeProperty().addListener(new ChangeListener<Shape>() { |
|||
@Override |
|||
public void changed(ObservableValue<? extends Shape> arg0, Shape arg1, Shape arg2) { |
|||
if (systemCall) { |
|||
systemCall = false; |
|||
} else { |
|||
shapeIt(); |
|||
} |
|||
/* |
|||
* if(arg2.getClass().isAssignableFrom(Bubble.class)){ // i do no need to check |
|||
* for this actuall is waste of time systemCall = false; return; }else{ // not |
|||
* the required shape systemCall = true; setShape(new Bubble(bs)); System.gc(); |
|||
* } |
|||
*/ |
|||
|
|||
} |
|||
}); |
|||
|
|||
heightProperty().addListener(new InvalidationListener() { |
|||
|
|||
@Override |
|||
public void invalidated(Observable arg0) { |
|||
if (!systemCall) |
|||
setPrefHeight(Label.USE_COMPUTED_SIZE); |
|||
} |
|||
}); |
|||
|
|||
widthProperty().addListener(new InvalidationListener() { |
|||
|
|||
@Override |
|||
public void invalidated(Observable observable) { |
|||
if (!systemCall) |
|||
setPrefHeight(Label.USE_COMPUTED_SIZE); |
|||
} |
|||
}); |
|||
|
|||
shapeIt(); |
|||
} |
|||
|
|||
@Override |
|||
protected void updateBounds() { |
|||
super.updateBounds(); |
|||
// top right bottom left |
|||
switch (bs) { |
|||
case FACE_LEFT_BOTTOM: |
|||
setPadding(new Insets(pading, pading, |
|||
(this.getBoundsInLocal().getWidth() * ((Bubble) getShape()).drawRectBubbleIndicatorRule) / 2 |
|||
+ pading, |
|||
pading)); |
|||
break; |
|||
case FACE_LEFT_CENTER: |
|||
setPadding(new Insets(pading, pading, pading, |
|||
(this.getBoundsInLocal().getWidth() * ((Bubble) getShape()).drawRectBubbleIndicatorRule) / 2 |
|||
+ pading)); |
|||
break; |
|||
case FACE_RIGHT_BOTTOM: |
|||
setPadding(new Insets(pading, |
|||
(this.getBoundsInLocal().getWidth() * ((Bubble) getShape()).drawRectBubbleIndicatorRule) / 2 |
|||
+ pading, |
|||
pading, pading)); |
|||
break; |
|||
case FACE_RIGHT_CENTER: |
|||
setPadding(new Insets(pading, |
|||
(this.getBoundsInLocal().getWidth() * ((Bubble) getShape()).drawRectBubbleIndicatorRule) / 2 |
|||
+ pading, |
|||
pading, pading)); |
|||
break; |
|||
case FACE_TOP: |
|||
setPadding(new Insets( |
|||
(this.getBoundsInLocal().getWidth() * ((Bubble) getShape()).drawRectBubbleIndicatorRule) / 2 |
|||
+ pading, |
|||
pading, pading, pading)); |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
public final double getPading() { |
|||
return pading; |
|||
} |
|||
|
|||
public void setPading(double pading) { |
|||
if (pading > 25.0) |
|||
return; |
|||
this.pading = pading; |
|||
} |
|||
|
|||
public BubbleSpec getBubbleSpec() { |
|||
return bs; |
|||
} |
|||
|
|||
public void setBubbleSpec(BubbleSpec bubbleSpec) { |
|||
this.bs = bubbleSpec; |
|||
shapeIt(); |
|||
} |
|||
|
|||
private final void shapeIt() { |
|||
systemCall = true; |
|||
setShape(new Bubble(bs)); |
|||
System.gc(); |
|||
} |
|||
} |
@ -0,0 +1,135 @@ |
|||
package wow.doge.chatto.messagebuble; |
|||
|
|||
import com.sandec.mdfx.MDFXNode; |
|||
|
|||
import javafx.beans.InvalidationListener; |
|||
import javafx.beans.Observable; |
|||
import javafx.beans.value.ChangeListener; |
|||
import javafx.beans.value.ObservableValue; |
|||
import javafx.geometry.Insets; |
|||
import javafx.scene.Node; |
|||
import javafx.scene.control.Label; |
|||
import javafx.scene.effect.DropShadow; |
|||
import javafx.scene.paint.Color; |
|||
import javafx.scene.shape.Shape; |
|||
|
|||
public class BubbledMDFXNode extends MDFXNode { |
|||
public BubbledMDFXNode(String s) { |
|||
super(s); |
|||
init(); |
|||
} |
|||
|
|||
private BubbleSpec bs = BubbleSpec.FACE_LEFT_CENTER; |
|||
private double pading = 5.0; |
|||
private boolean systemCall = false; |
|||
|
|||
private void init() { |
|||
DropShadow ds = new DropShadow(); |
|||
ds.setOffsetX(1.3); |
|||
ds.setOffsetY(1.3); |
|||
ds.setColor(Color.DARKGRAY); |
|||
setPrefSize(Label.USE_COMPUTED_SIZE, Label.USE_COMPUTED_SIZE); |
|||
shapeProperty().addListener(new ChangeListener<Shape>() { |
|||
@Override |
|||
public void changed(ObservableValue<? extends Shape> arg0, Shape arg1, Shape arg2) { |
|||
if (systemCall) { |
|||
systemCall = false; |
|||
} else { |
|||
shapeIt(); |
|||
} |
|||
/* |
|||
* if(arg2.getClass().isAssignableFrom(Bubble.class)){ // i do no need to check |
|||
* for this actuall is waste of time systemCall = false; return; }else{ // not |
|||
* the required shape systemCall = true; setShape(new Bubble(bs)); System.gc(); |
|||
* } |
|||
*/ |
|||
|
|||
} |
|||
}); |
|||
|
|||
heightProperty().addListener(new InvalidationListener() { |
|||
|
|||
@Override |
|||
public void invalidated(Observable arg0) { |
|||
if (!systemCall) |
|||
setPrefHeight(Label.USE_COMPUTED_SIZE); |
|||
} |
|||
}); |
|||
|
|||
widthProperty().addListener(new InvalidationListener() { |
|||
|
|||
@Override |
|||
public void invalidated(Observable observable) { |
|||
if (!systemCall) |
|||
setPrefHeight(Label.USE_COMPUTED_SIZE); |
|||
} |
|||
}); |
|||
|
|||
shapeIt(); |
|||
} |
|||
|
|||
@Override |
|||
protected void updateBounds() { |
|||
super.updateBounds(); |
|||
// top right bottom left |
|||
switch (bs) { |
|||
case FACE_LEFT_BOTTOM: |
|||
setPadding(new Insets(pading, pading, |
|||
(this.getBoundsInLocal().getWidth() * ((Bubble) getShape()).drawRectBubbleIndicatorRule) / 2 |
|||
+ pading, |
|||
pading)); |
|||
break; |
|||
case FACE_LEFT_CENTER: |
|||
setPadding(new Insets(pading, pading, pading, |
|||
(this.getBoundsInLocal().getWidth() * ((Bubble) getShape()).drawRectBubbleIndicatorRule) / 2 |
|||
+ pading)); |
|||
break; |
|||
case FACE_RIGHT_BOTTOM: |
|||
setPadding(new Insets(pading, |
|||
(this.getBoundsInLocal().getWidth() * ((Bubble) getShape()).drawRectBubbleIndicatorRule) / 2 |
|||
+ pading, |
|||
pading, pading)); |
|||
break; |
|||
case FACE_RIGHT_CENTER: |
|||
setPadding(new Insets(pading, |
|||
(this.getBoundsInLocal().getWidth() * ((Bubble) getShape()).drawRectBubbleIndicatorRule) / 2 |
|||
+ pading, |
|||
pading, pading)); |
|||
break; |
|||
case FACE_TOP: |
|||
setPadding(new Insets( |
|||
(this.getBoundsInLocal().getWidth() * ((Bubble) getShape()).drawRectBubbleIndicatorRule) / 2 |
|||
+ pading, |
|||
pading, pading, pading)); |
|||
break; |
|||
|
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
|
|||
public final double getPading() { |
|||
return pading; |
|||
} |
|||
|
|||
public void setPading(double pading) { |
|||
if (pading > 25.0) |
|||
return; |
|||
this.pading = pading; |
|||
} |
|||
|
|||
public BubbleSpec getBubbleSpec() { |
|||
return bs; |
|||
} |
|||
|
|||
public void setBubbleSpec(BubbleSpec bubbleSpec) { |
|||
this.bs = bubbleSpec; |
|||
shapeIt(); |
|||
} |
|||
|
|||
private final void shapeIt() { |
|||
systemCall = true; |
|||
setShape(new Bubble(bs)); |
|||
System.gc(); |
|||
} |
|||
} |
@ -0,0 +1,10 @@ |
|||
package wow.doge.chatto.model |
|||
|
|||
import java.time.Instant |
|||
|
|||
case class ChatUser( |
|||
userId: Long, |
|||
userName: String, |
|||
password: String, |
|||
joinDate: Instant |
|||
) |
@ -0,0 +1,46 @@ |
|||
package wow.doge.chatto.service |
|||
|
|||
import scala.concurrent.ExecutionContext |
|||
import scala.concurrent.ExecutionContext.Implicits.global |
|||
import scala.async.Async.{async, await} |
|||
import sttp.client.json4s._ |
|||
import org.json4s._ |
|||
import sttp.client._ |
|||
import scala.concurrent.Future |
|||
import sttp.client.asynchttpclient.WebSocketHandler |
|||
import javax.inject.Inject |
|||
import scala.async.Async.{async, await} |
|||
import scala.util.Success |
|||
import scala.util.Failure |
|||
import wow.doge.chatto.AppData |
|||
import wow.doge.chatto.types.AppTypes.HttpBackend |
|||
|
|||
class UserService @Inject() (appData: AppData)( |
|||
implicit backend: HttpBackend |
|||
) { |
|||
private implicit lazy val serialization = org.json4s.native.Serialization |
|||
|
|||
def func1() = { |
|||
val willBeResponse = basicRequest |
|||
.get(uri"https://httpbin.org/get") |
|||
.response(asJson[HttpBinResponse]) |
|||
.send() |
|||
async { |
|||
val r = await { willBeResponse } |
|||
r.body.map(println) |
|||
} |
|||
} |
|||
|
|||
def func2() = |
|||
basicRequest |
|||
.get(uri"https://httpbin.org/get") |
|||
.response(asJson[HttpBinResponse]) |
|||
.send() |
|||
|
|||
} |
|||
|
|||
case class HttpBinResponse( |
|||
url: String, |
|||
origin: String, |
|||
headers: Map[String, String] |
|||
) |
@ -0,0 +1,14 @@ |
|||
package wow.doge.chatto.types |
|||
|
|||
import sttp.client.SttpBackend |
|||
import scala.concurrent.Future |
|||
import sttp.client.asynchttpclient.WebSocketHandler |
|||
|
|||
trait AppTypes { |
|||
// import AppTypes._ |
|||
type HttpBackend = SttpBackend[Future, Nothing, WebSocketHandler] |
|||
} |
|||
|
|||
object AppTypes extends AppTypes { |
|||
// type HttpBackend = SttpBackend[Future, Nothing, WebSocketHandler] |
|||
} |
@ -0,0 +1,2 @@ |
|||
version in ThisBuild := "0.1.0-SNAPSHOT" |
|||
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue