Rohan Sircar
4 years ago
19 changed files with 748 additions and 381 deletions
-
12build.sbt
-
61src/main/resources/fxml/Chat.fxml
-
13src/main/resources/fxml/Login.fxml
-
54src/main/resources/fxml/MainView.fxml
-
29src/main/resources/fxml/default.css
-
173src/main/resources/styles/chat.css
-
85src/main/resources/styles/default.css
-
5src/main/resources/styles/login.css
-
57src/main/scala/wow/doge/chatto/ApplicationController.scala
-
114src/main/scala/wow/doge/chatto/control/JFXSmoothScroll.java
-
10src/main/scala/wow/doge/chatto/control/MessageBox.scala
-
5src/main/scala/wow/doge/chatto/control/UserBox2.scala
-
388src/main/scala/wow/doge/chatto/controller/ChatController.scala
-
15src/main/scala/wow/doge/chatto/controller/LoginController.scala
-
19src/main/scala/wow/doge/chatto/controller/MainViewController.scala
-
4src/main/scala/wow/doge/chatto/controller/NavigationController.scala
-
2src/main/scala/wow/doge/chatto/controller/WorkspaceController.scala
-
69src/main/scala/wow/doge/chatto/service/CustomSerializer.scala
-
14src/main/scala/wow/doge/chatto/service/UserService.scala
@ -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; |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
||||
|
|
@ -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; |
||||
|
} |
@ -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; |
||||
|
} |
@ -0,0 +1,5 @@ |
|||||
|
#rootPane { |
||||
|
-fx-background-image: url("../images/backgroung.jpg"); |
||||
|
-fx-background-size: 1920 1080; |
||||
|
-fx-background-position: center center; |
||||
|
} |
@ -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); |
||||
|
} |
||||
|
|
||||
|
} |
@ -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() {} |
@ -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")) |
|
||||
// ) |
|
||||
// }) |
|
||||
// ) |
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue