diff --git a/src/main/resources/fxml/Chat.fxml b/src/main/resources/fxml/Chat.fxml index 7b2beb4..b6f981c 100644 --- a/src/main/resources/fxml/Chat.fxml +++ b/src/main/resources/fxml/Chat.fxml @@ -1,10 +1,10 @@ + - @@ -18,28 +18,14 @@ - - +
- - +
- - + \ No newline at end of file diff --git a/src/main/resources/fxml/Login.fxml b/src/main/resources/fxml/Login.fxml index f0d10d0..63823c6 100644 --- a/src/main/resources/fxml/Login.fxml +++ b/src/main/resources/fxml/Login.fxml @@ -43,10 +43,10 @@ - - + + - + @@ -70,7 +70,7 @@ - + \ No newline at end of file diff --git a/src/main/resources/fxml/MainView.fxml b/src/main/resources/fxml/MainView.fxml index c844e78..115746c 100644 --- a/src/main/resources/fxml/MainView.fxml +++ b/src/main/resources/fxml/MainView.fxml @@ -4,7 +4,7 @@ - + @@ -61,11 +61,12 @@ prefHeight="30.0" styleClass="status"/> --> - - + + - + \ No newline at end of file diff --git a/src/main/resources/styles/style2.css b/src/main/resources/styles/style2.css index e2c230e..81a0677 100644 --- a/src/main/resources/styles/style2.css +++ b/src/main/resources/styles/style2.css @@ -1,16 +1,50 @@ -#rootPane{ - -fx-background-image: url("../images/backgroung.jpg"); - -fx-background-size: 1920.0 1080.0; - -fx-background-position: center center; +#rootPane { + -fx-background-image: url("../images/backgroung.jpg"); + -fx-background-size: 1920 1080; + -fx-background-position: center center; } -.ikonli-font-icon{ - -fx-icon-size: 100px; - -fx-icon-color: blue; +.ikonli-font-icon { + -fx-icon-size: 100px; + -fx-icon-color: blue; } - .user-radio .radio { - visibility: hidden; - -fx-pref-width: 0px; - -fx-max-width: 0px; -} \ No newline at end of file +.user-radio .radio { + visibility: hidden; + -fx-pref-width: 0px; + -fx-max-width: 0px; +} + +.mylistview .scroll-bar:horizontal .track, +.mylistview .scroll-bar:vertical .track { + -fx-background-color: transparent; + -fx-border-color: transparent; + -fx-background-radius: 0em; + -fx-border-radius: 2em; +} + +.mylistview .scroll-bar:horizontal .increment-button, +.mylistview .scroll-bar:horizontal .decrement-button { + -fx-background-color: transparent; + -fx-background-radius: 0em; + -fx-padding: 0 0 10 0; +} + +.mylistview .scroll-bar:vertical .increment-button, +.mylistview .scroll-bar:vertical .decrement-button { + -fx-background-color: transparent; + -fx-background-radius: 0em; + -fx-padding: 0 10 0 0; +} +.mylistview .scroll-bar .increment-arrow, +.mylistview .scroll-bar .decrement-arrow { + -fx-shape: " "; + -fx-padding: 0; +} + +.mylistview .scroll-bar:horizontal .thumb, +.mylistview .scroll-bar:vertical .thumb { + -fx-background-color: derive(black, 90%); + -fx-background-insets: 2, 0, 0; + -fx-background-radius: 2em; +} diff --git a/src/main/resources/styles/ui.css b/src/main/resources/styles/ui.css index 1997cf2..e090a96 100644 --- a/src/main/resources/styles/ui.css +++ b/src/main/resources/styles/ui.css @@ -13,44 +13,42 @@ -fx-pref-height: 40px; -fx-background-insets: 5px; } */ -.root{ - -fx-padding: 5.0 5.0 5.0 5.0; +.root { + -fx-padding: 5 5 5 5; -fx-background-image: url("../images/backgroung.jpg"); - -fx-background-size: 1920.0 1080.0; - -fx-background-position: center center; + -fx-background-size: 1920 1080; + -fx-background-position: center center; } - #flowPane { - -fx-hgap: 5.0px; - -fx-vgap: 5.0px; + -fx-hgap: 5px; + -fx-vgap: 5px; } -.userVbox { - -fx-padding: 5.0 5.0 5.0 5.0; +/* .userVbox { + -fx-padding: 5 5 5 5; -fx-background-insets: 5px; - -fx-background-size: 1920.0 1080.0; - -fx-background-position: center center; - -fx-background-color: #ff0055; - -fx-background-radius: 10px; - + -fx-background-size: 1920 1080; + -fx-background-position: center center; + -fx-background-color: #ff0055; + -fx-background-radius: 10px; +} */ + +#chatTextArea { + -fx-font-size: 1.4em; } -#chatTextArea{ - -fx-font-size: 1.4em; -} - -.my-list-cell { - -fx-background-color: null; +/* .my-list-cell { + -fx-background-color: null; } .my-list-view { - -fx-background-color: null; + -fx-background-color: null; } .my-list-view > .list-cell { - -fx-background-color: null; -} + -fx-background-color: null; +} */ /*.myButton { -fx-background-radius: 21.0px; diff --git a/src/main/scala/wow/doge/chatto/ApplicationController.scala b/src/main/scala/wow/doge/chatto/ApplicationController.scala index 6b4cd4b..a4a74b3 100644 --- a/src/main/scala/wow/doge/chatto/ApplicationController.scala +++ b/src/main/scala/wow/doge/chatto/ApplicationController.scala @@ -18,6 +18,10 @@ import org.json4s.JsonDSL._ import scala.util.Success import scala.util.Failure import com.softwaremill.quicklens._ +import org.scalafx.extras._ +import wow.doge.chatto.service.UserService +import javax.inject._ +import javafx.application.Platform @Named @ApplicationScoped class ApplicationController extends DefaultWindowController { @@ -29,6 +33,9 @@ class ApplicationController extends DefaultWindowController { // override def width: Int = 400 + @Inject + private var appDataHandler: AppDataHandler = _ + def applicationDidLaunch() = { logger.info("start " + this) applicationEnvironment.loadResourceBundle("bundles/application") @@ -39,11 +46,6 @@ class ApplicationController extends DefaultWindowController { def applicationName: ApplicationName = { ApplicationName(configStringValue("application.name")) } - - @Produces var appData: AppData = synchronized { - AppData(User.empty, "") - } - @Produces def httpBackend = backend @@ -62,19 +64,30 @@ class ApplicationController extends DefaultWindowController { super.applicationWillStop() println("stopping") await(httpBackend.close()) + Platform.exit() System.exit(0) } - def showLoginPane() = { - appData = appData.copy(user = User.empty) - appData = appData.modify(_.user).using(_ => User.empty) - appData = appData.modify(_.user.username).using(_ => "") + def showLoginPane() = onFX { + offFX { appDataHandler.clearCredentials() } + // replaceSceneContent(mainViewController.loginController) + // mainViewController.mainManager.updatePaneContent( + // mainViewController.loginController + // ) replaceSceneContent(mainViewController.loginController) } - def showChatPane(): Unit = { + def logout() = { + val newMainViewController = getController[MainViewController]() + replaceSceneContent(newMainViewController) + } + + 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") @@ -94,9 +107,32 @@ class ApplicationController extends DefaultWindowController { // } 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 UserCredentials( + username: String, + password: String, + token: String +) +object UserCredentials { + def empty = UserCredentials("empty", "empty", "empty") } -final case class AppData(user: User, sumth: String) + +@ApplicationScoped +class AppDataHandler { + private var _appData: AppData = AppData(UserCredentials.empty, "empty") + + private def appData_=(appData: AppData) = synchronized { _appData = appData } + + def appData = _appData + + def updateCredentials(credentials: UserCredentials): Unit = offFX { + println(credentials) + appData = appData.copy(credentials = credentials) + } + + def clearCredentials() = { + appData = appData.copy(credentials = UserCredentials.empty) + } +} +final case class AppData(credentials: UserCredentials, sumth: String) diff --git a/src/main/scala/wow/doge/chatto/control/UserBox.scala b/src/main/scala/wow/doge/chatto/control/UserBox.scala index 6ca04fd..bbbb4d4 100644 --- a/src/main/scala/wow/doge/chatto/control/UserBox.scala +++ b/src/main/scala/wow/doge/chatto/control/UserBox.scala @@ -25,6 +25,8 @@ class UserBox() extends VBox() { fxmlLoader.load(); + () + // userRadioButton // .selectedProperty() // .addListener(changeListener => { @@ -37,16 +39,12 @@ class UserBox() extends VBox() { // } // }); - userRadioButton.selected.onChange { (_, _, _) => - { - 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() -} diff --git a/src/main/scala/wow/doge/chatto/controller/ChatController.scala b/src/main/scala/wow/doge/chatto/controller/ChatController.scala index 7466b06..7ae559c 100644 --- a/src/main/scala/wow/doge/chatto/controller/ChatController.scala +++ b/src/main/scala/wow/doge/chatto/controller/ChatController.scala @@ -20,19 +20,26 @@ import scala.concurrent.ExecutionContext.Implicits.global import com.typesafe.scalalogging.LazyLogging // import wow.doge.chatto.controller.LoginController.Person import com.sfxcode.sapphire.core.value.FXBean +import wow.doge.chatto.AppDataHandler +import com.jfoenix.controls.JFXListView +import scala.async.Async.{async, await} +import javafx.scene.paint.Color -class ChatController @Inject() (userService: UserService) - extends AbstractViewController +class ChatController @Inject() ( + userService: UserService, + appDataHandler: AppDataHandler +) extends AbstractViewController with LazyLogging { @FXML private var label: Label = _ @FXML private var flowPane: FlowPane = _ @FXML private var submitButton: Button = _ - @FXML private var loginButton: Button = _ - @FXML private var chatTextArea: TextArea = _ + @FXML private var logoutButton: Button = _ + // @FXML private var chatTextArea: TextArea = _ @FXML private var chatInput: TextArea = _ @FXML private var usersVBox: VBox = _ - @FXML private var chatListView: ListView[HBox] = _ + @FXML var usersListView: JFXListView[Any] = _ + @FXML private var chatListView: JFXListView[HBox] = _ // applicationController.show override def didGainVisibilityFirstTime(): Unit = { @@ -42,13 +49,13 @@ class ChatController @Inject() (userService: UserService) ub.messageLabel.text = "Hi there" // ub.messageLabel.id = ub.userRadioButton.text = "User 1" - usersVBox.children.clear() - usersVBox.children += ub + // 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 + // chatTextArea.visible <== !chatInput.text.isEmpty + // chatTextArea.text <== chatInput.text for (r <- userService.func2()) yield (logger.info(s"${r.body}")) @@ -64,10 +71,47 @@ class ChatController @Inject() (userService: UserService) bean.updateValue("name", "Lester") println(bean.bean) + logoutButton.onAction = (e) => { + applicationController.logout() + println(appDataHandler.appData) + } + } override def didGainVisibility(): Unit = { super.didGainVisibility() + chatInput.requestFocus() + + async { + val willBeUsers = userService + .getUsers(appDataHandler.appData.credentials) + .map(_.body) + val maybeUsers = await(willBeUsers) + val maybeUsersBoxes = maybeUsers.map(users => { + users.map(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 + new HBox { + 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) + } + }) + }) + onFX { + maybeUsersBoxes.map(userBoxes => { + usersListView.items() ++= userBoxes + }) + } + } } def func() = { val x = offFXAndWait { diff --git a/src/main/scala/wow/doge/chatto/controller/LoginController.scala b/src/main/scala/wow/doge/chatto/controller/LoginController.scala index 1d20ea7..7a0ef69 100644 --- a/src/main/scala/wow/doge/chatto/controller/LoginController.scala +++ b/src/main/scala/wow/doge/chatto/controller/LoginController.scala @@ -22,19 +22,26 @@ 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 wow.doge.chatto.UserCredentials 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 +import org.scalafx.extras._ +import wow.doge.chatto.AppDataHandler +import com.sfxcode.sapphire.core.value.BeanConversions -class LoginController @Inject() (userService: UserService, var appData: AppData)( +class LoginController @Inject() ( + userService: UserService, + appDataHandler: AppDataHandler +)( implicit backend: HttpBackend ) extends AbstractViewController with LazyLogging - with AppTypes { - @FXML private var submitButton: JFXButton = _ + with AppTypes + with BeanConversions { + @FXML var submitButton: JFXButton = _ @FXML private var usernameTextField: JFXTextField = _ @@ -45,12 +52,11 @@ class LoginController @Inject() (userService: UserService, var appData: AppData) override def didGainVisibilityFirstTime(): Unit = { super.didGainVisibilityFirstTime() this.stage.resizable = false - usernameTextField.requestFocus() - submitButton.setOnAction(actionLogin) + // usernameTextField.requestFocus() - // println(something) + // submitButton.setOnAction(actionLogin) - val bindings = KeyBindings("usernameTextField", "passwordTextField") + val bindings = KeyBindings("username", "password") // Expression Binding Example // bindings.add( // "usernameTextField", @@ -59,26 +65,13 @@ class LoginController @Inject() (userService: UserService, var appData: AppData) 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() @@ -90,51 +83,43 @@ class LoginController @Inject() (userService: UserService, var appData: AppData) usernameTextField.requestFocus() } - def actionLogin(e: ActionEvent) = { - import org.scalafx.extras._ + def actionLogin() = { 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 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)) + } + applicationController.showChatPane() + } case None => { - onFX(errorLabel.text = - "Error logging in - please check your password" - ) + updateErrorLabel("Error logging in - please check your password") logger.warn("Login unsuccessful wrong password") } } - // Platform.runLater(() => applicationController.showChatPane()) - onFX(applicationController.showChatPane()) + // 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()) + updateErrorLabel("Error logging in - Please check your network") + // applicationController.showChatPane() } } - // if (authenticated) { - // passwordTextField.clear() - // val res = Result(username = inputUserName, password = inputPassword) - // println(res) - // // loginManager. + } - // applicationController.showChatPane() - // } else { - // logger.error("Login Error") - // } + def updateErrorLabel(message: String) = onFX { + errorLabel.text = message } def login(username: String, password: String) = async { @@ -153,8 +138,8 @@ class LoginController @Inject() (userService: UserService, var appData: AppData) final case class Person( id: String, - usernameTextField: String, - passwordTextField: String + username: String, + password: String ) } diff --git a/src/main/scala/wow/doge/chatto/controller/MainViewController.scala b/src/main/scala/wow/doge/chatto/controller/MainViewController.scala index 47671c3..e2efc82 100644 --- a/src/main/scala/wow/doge/chatto/controller/MainViewController.scala +++ b/src/main/scala/wow/doge/chatto/controller/MainViewController.scala @@ -23,9 +23,9 @@ class MainViewController extends ViewController with LazyLogging { // @FXML // var navigationPane: Pane = _ - @FXML var loginPane: Pane = _ + @FXML var mainPane: Pane = _ - @FXML var chatPane: Pane = _ + // @FXML var chatPane: Pane = _ lazy val workspaceController = getController[WorkspaceController]() lazy val navigationController = getController[NavigationController]() @@ -42,13 +42,13 @@ class MainViewController extends ViewController with LazyLogging { override def didGainVisibilityFirstTime() { // menuBar.setUseSystemMenuBar(true) - menuBar.setVisible(false) + // menuBar.setVisible(false) // navigationManager = // ContentManager(navigationPane, this, navigationController) // statusBarManager = ContentManager(statusPane, this, statusBarController) // workspaceManager = ContentManager(workspacePane, this, workspaceController) - mainManager = ContentManager(loginPane, this, loginController) + mainManager = ContentManager(mainPane, this, loginController) } } diff --git a/src/main/scala/wow/doge/chatto/model/ChatUser.scala b/src/main/scala/wow/doge/chatto/model/ChatUser.scala deleted file mode 100644 index 15b3448..0000000 --- a/src/main/scala/wow/doge/chatto/model/ChatUser.scala +++ /dev/null @@ -1,10 +0,0 @@ -package wow.doge.chatto.model - -import java.time.Instant - -case class ChatUser( - userId: Long, - userName: String, - password: String, - joinDate: Instant -) diff --git a/src/main/scala/wow/doge/chatto/service/UserService.scala b/src/main/scala/wow/doge/chatto/service/UserService.scala index 15562db..d506be4 100644 --- a/src/main/scala/wow/doge/chatto/service/UserService.scala +++ b/src/main/scala/wow/doge/chatto/service/UserService.scala @@ -14,21 +14,28 @@ import scala.util.Success import scala.util.Failure import wow.doge.chatto.AppData import wow.doge.chatto.types.AppTypes.HttpBackend +import com.typesafe.scalalogging.LazyLogging +import org.scalafx.extras._ +import wow.doge.chatto.ApplicationController +import wow.doge.chatto.UserCredentials +import javax.inject._ +import wow.doge.chatto.AppDataHandler -class UserService @Inject() (appData: AppData)( +class UserService @Inject() (appDataHandler: AppDataHandler)( implicit backend: HttpBackend -) { +) extends LazyLogging { private implicit lazy val serialization = org.json4s.native.Serialization + private val domain = "http://localhost:8080" + private lazy val baseUrl = uri"$domain/api/chat" + private lazy val authBasicRequest = (credentials: UserCredentials) => + basicRequest.auth + .basic(credentials.username, credentials.password) + // .header("X-AUTH-TOKEN", appData.credentials.token) - 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 func1() = async { + val willBeResponse = func2() + val r = await { willBeResponse } + r.body.map(println) } def func2() = @@ -37,9 +44,21 @@ class UserService @Inject() (appData: AppData)( .response(asJson[HttpBinResponse]) .send() + private def endpoint(uri: String) = uri"$baseUrl/$uri" + + def getUsers(credentials: UserCredentials) = async { + println(appDataHandler.appData) + await { + authBasicRequest(credentials) + .get(uri"http://localhost:8080/api/chat/get/users") + .response(asJson[List[String]]) + .send() + } + } + } -case class HttpBinResponse( +final case class HttpBinResponse( url: String, origin: String, headers: Map[String, String]