You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
5.0 KiB

  1. package nova.monadic_sfx
  2. import java.util.concurrent.TimeUnit
  3. import scala.util.Random
  4. import com.softwaremill.macwire._
  5. import io.odin.Logger
  6. import monix.bio.IO
  7. import monix.bio.Task
  8. import monix.eval.Coeval
  9. import monix.{eval => me}
  10. import nova.monadic_sfx.executors.Schedulers
  11. import nova.monadic_sfx.implicits.JFXButton
  12. import nova.monadic_sfx.implicits._
  13. import nova.monadic_sfx.ui.MyFxApp
  14. import nova.monadic_sfx.ui.components.router.FXRouter
  15. import nova.monadic_sfx.ui.components.router.Page
  16. import nova.monadic_sfx.ui.components.todo.TodoListStore
  17. import nova.monadic_sfx.ui.components.todo.TodoListView
  18. import org.gerweck.scalafx.util._
  19. import scalafx.Includes._
  20. import scalafx.application.JFXApp.PrimaryStage
  21. import scalafx.beans.property.ObjectProperty
  22. import scalafx.beans.property.StringProperty
  23. import scalafx.collections.ObservableBuffer
  24. import scalafx.geometry.Insets
  25. import scalafx.geometry.Pos
  26. import scalafx.scene.Parent
  27. import scalafx.scene.Scene
  28. import scalafx.scene.control.Label
  29. import scalafx.scene.control.TableColumn
  30. import scalafx.scene.control.TableView
  31. import scalafx.scene.layout.BorderPane
  32. import scalafx.scene.layout.FlowPane
  33. import scalafx.scene.layout.HBox
  34. import scalafx.scene.layout.Priority
  35. class MainApp(
  36. // spawnProtocol: ActorSystem[SpawnProtocol.Command],
  37. schedulers: Schedulers,
  38. startTime: Long
  39. )(implicit logger: Logger[Task]) {
  40. lazy val _scene = new Scene {
  41. root = new HBox {
  42. padding = Insets(20)
  43. }
  44. }
  45. private lazy val stage = new PrimaryStage {
  46. title = "Simple ScalaFX App"
  47. scene = _scene
  48. width = 640
  49. height = 480
  50. }
  51. val program = for {
  52. (fxApp, fxAppFib) <- wire[MyFxApp].init(stage)
  53. _ <-
  54. wire[MainAppDelegate].init
  55. .flatMap(mainSceneNode => Task(_scene.getChildren += mainSceneNode))
  56. .executeOn(schedulers.fx)
  57. currentTime <- IO.clock.realTime(TimeUnit.MILLISECONDS)
  58. _ <- logger.info(
  59. s"Application started in ${(currentTime - startTime) / 1000f} seconds"
  60. )
  61. _ <- fxAppFib.join
  62. } yield ()
  63. }
  64. class MainAppDelegate(schedulers: Schedulers)(implicit logger: Logger[Task]) {
  65. val buttonStyle = """| -fx-padding: 0.7em 0.57em;
  66. | -fx-font-size: 14px;
  67. | -jfx-button-type: RAISED;
  68. | -fx-background-color: rgb(77,102,204);
  69. | -fx-pref-width: 200;
  70. | -fx-text-fill: WHITE; """.stripMargin
  71. def init =
  72. for {
  73. router <- Task.pure(new FXRouter[Page])
  74. routerStore <- router.store(Page.Home, logger)
  75. todoStore <- TodoListStore(logger)
  76. todoComponent <- TodoListView(todoStore)
  77. resolver: PartialFunction[Page, Task[Parent]] = {
  78. case Page.Home =>
  79. Task(new Label {
  80. text = "HomePage"
  81. })
  82. case Page.UserHome(id0) =>
  83. Task(new Label {
  84. text = s"User Home, Id = $id0"
  85. })
  86. case Page.Todo =>
  87. Task(todoComponent)
  88. }
  89. routerNode <-
  90. Task
  91. .deferAction(implicit s =>
  92. Task(new HBox {
  93. //TODO find a better way to do this
  94. var oldValue: Option[Parent] = None
  95. children <-- router
  96. .render(resolver)(routerStore)
  97. // call cancel on the old component to cancel all subscriptions
  98. .doOnNextF(newValue =>
  99. Coeval { oldValue.foreach(_ => ()) } >> Coeval {
  100. oldValue = Some(newValue)
  101. }
  102. )
  103. .map(_.delegate)
  104. })
  105. )
  106. mainSceneNode <- Task.deferAction(implicit s =>
  107. Task(new BorderPane {
  108. hgrow = Priority.Always
  109. vgrow = Priority.Always
  110. center = routerNode
  111. bottom = new FlowPane {
  112. alignment = Pos.Center
  113. hgap = 20
  114. children = Seq(
  115. new JFXButton {
  116. text = "Todo"
  117. style = buttonStyle
  118. obsAction
  119. .useLazyEval(
  120. me.Task.pure(FXRouter.Replace(Page.Todo))
  121. ) --> routerStore
  122. },
  123. new JFXButton {
  124. text = "UserHome"
  125. style = buttonStyle
  126. obsAction
  127. .useLazyEval(
  128. me.Task(FXRouter.Replace(Page.UserHome(Random.nextInt(20))))
  129. ) --> routerStore
  130. }
  131. )
  132. }
  133. })
  134. )
  135. } yield mainSceneNode
  136. }
  137. class TestModel(_name: String, _age: Int) {
  138. val name = StringProperty(_name).readOnly
  139. val age = ObjectProperty(_age).readOnly
  140. }
  141. object Test {
  142. val items = ObservableBuffer(
  143. new TestModel("hmm", 1),
  144. new TestModel("hmm2", 2)
  145. )
  146. val ttv = new TableView[TestModel](items) {
  147. columns ++= Seq(
  148. new TableColumn[TestModel, String] {
  149. text = "Name"
  150. cellValueFactory = { _.value.name }
  151. },
  152. new TableColumn[TestModel, Int] {
  153. text = "Age"
  154. cellValueFactory = { _.value.age }
  155. }
  156. )
  157. }
  158. }