package nova.monadic_sfx import java.util.concurrent.TimeUnit import scala.util.Random import com.softwaremill.macwire._ import io.odin.Logger import monix.bio.IO import monix.bio.Task import monix.eval.Coeval import monix.{eval => me} import nova.monadic_sfx.executors.Schedulers import nova.monadic_sfx.implicits.JFXButton import nova.monadic_sfx.implicits._ import nova.monadic_sfx.ui.MyFxApp import nova.monadic_sfx.ui.components.router.FXRouter import nova.monadic_sfx.ui.components.router.Page import nova.monadic_sfx.ui.components.todo.TodoListStore import nova.monadic_sfx.ui.components.todo.TodoListView import org.gerweck.scalafx.util._ import scalafx.Includes._ import scalafx.application.JFXApp.PrimaryStage import scalafx.beans.property.ObjectProperty import scalafx.beans.property.StringProperty import scalafx.collections.ObservableBuffer import scalafx.geometry.Insets import scalafx.geometry.Pos import scalafx.scene.Parent import scalafx.scene.Scene import scalafx.scene.control.Label import scalafx.scene.control.TableColumn import scalafx.scene.control.TableView import scalafx.scene.layout.BorderPane import scalafx.scene.layout.FlowPane import scalafx.scene.layout.HBox import scalafx.scene.layout.Priority class MainApp( // spawnProtocol: ActorSystem[SpawnProtocol.Command], schedulers: Schedulers, startTime: Long )(implicit logger: Logger[Task]) { lazy val _scene = new Scene { root = new HBox { padding = Insets(20) } } private lazy val stage = new PrimaryStage { title = "Simple ScalaFX App" scene = _scene width = 640 height = 480 } val program = for { (fxApp, fxAppFib) <- wire[MyFxApp].init(stage) _ <- wire[MainAppDelegate].init .flatMap(mainSceneNode => Task(_scene.getChildren += mainSceneNode)) .executeOn(schedulers.fx) currentTime <- IO.clock.realTime(TimeUnit.MILLISECONDS) _ <- logger.info( s"Application started in ${(currentTime - startTime) / 1000f} seconds" ) _ <- fxAppFib.join } yield () } class MainAppDelegate(schedulers: Schedulers)(implicit logger: Logger[Task]) { val buttonStyle = """| -fx-padding: 0.7em 0.57em; | -fx-font-size: 14px; | -jfx-button-type: RAISED; | -fx-background-color: rgb(77,102,204); | -fx-pref-width: 200; | -fx-text-fill: WHITE; """.stripMargin def init = for { router <- Task.pure(new FXRouter[Page]) routerStore <- router.store(Page.Home, logger) todoStore <- TodoListStore(logger) todoComponent <- TodoListView(todoStore) resolver: PartialFunction[Page, Task[Parent]] = { case Page.Home => Task(new Label { text = "HomePage" }) case Page.UserHome(id0) => Task(new Label { text = s"User Home, Id = $id0" }) case Page.Todo => Task(todoComponent) } routerNode <- Task .deferAction(implicit s => Task(new HBox { //TODO find a better way to do this var oldValue: Option[Parent] = None children <-- router .render(resolver)(routerStore) // call cancel on the old component to cancel all subscriptions .doOnNextF(newValue => Coeval { oldValue.foreach(_ => ()) } >> Coeval { oldValue = Some(newValue) } ) .map(_.delegate) }) ) mainSceneNode <- Task.deferAction(implicit s => Task(new BorderPane { hgrow = Priority.Always vgrow = Priority.Always center = routerNode bottom = new FlowPane { alignment = Pos.Center hgap = 20 children = Seq( new JFXButton { text = "Todo" style = buttonStyle obsAction .useLazyEval( me.Task.pure(FXRouter.Replace(Page.Todo)) ) --> routerStore }, new JFXButton { text = "UserHome" style = buttonStyle obsAction .useLazyEval( me.Task(FXRouter.Replace(Page.UserHome(Random.nextInt(20)))) ) --> routerStore } ) } }) ) } yield mainSceneNode } class TestModel(_name: String, _age: Int) { val name = StringProperty(_name).readOnly val age = ObjectProperty(_age).readOnly } object Test { val items = ObservableBuffer( new TestModel("hmm", 1), new TestModel("hmm2", 2) ) val ttv = new TableView[TestModel](items) { columns ++= Seq( new TableColumn[TestModel, String] { text = "Name" cellValueFactory = { _.value.name } }, new TableColumn[TestModel, Int] { text = "Age" cellValueFactory = { _.value.age } } ) } }