package nova.monadic_sfx.ui import scala.concurrent.duration._ import cats.effect.Resource import io.odin.Logger import monix.bio.Task import monix.execution.CancelablePromise import nova.monadic_sfx.concurrent.Schedulers import nova.monadic_sfx.ui.DefaultScene import scalafx.application.JFXApp3 import scalafx.application.JFXApp3.PrimaryStage import monix.bio.UIO import monix.eval.Coeval import scalafx.scene.Scene import scalafx.scene.Parent import scalafx.Includes._ import monix.bio.IO import scalafx.scene.Node final class FX private ( schedulers: Schedulers, delegate: JFXApp3, val await: Task[Unit], val awaitStop: Task[Unit] )(implicit logger: Logger[Task]) { logger.debug("whoopie") def runOnFx[E, A](io: IO[E, A]) = io.executeOn(schedulers.fx.value) def addToScene(node: UIO[Node]) = runOnFx { for { p <- node _ <- UIO(delegate.stage.scene().getChildren += p) } yield () } } object FX { def resource( schedulers: Schedulers, stage: Coeval[PrimaryStage], initialScene: Coeval[Scene] = DefaultScene(), transitionDelay: FiniteDuration = 500.millis )(implicit logger: Logger[Task] ): Resource[Task, FX] = Resource .make(for { _ <- logger.info("Starting FX App") makePromise = UIO(CancelablePromise[Unit]()) startSignal <- makePromise stopSignal <- makePromise delegate <- Task(new JFXApp3 { def start(): Unit = { stage = new PrimaryStage { scene = initialScene.value() } startSignal.success(()) } override def stopApp(): Unit = { stopSignal.success(()) } }) fib <- Task(delegate.main(Array.empty)).start.executeOn(schedulers.io.value) fxApp <- Task( new FX( schedulers, delegate, fib.join, Task.fromCancelablePromise(stopSignal) ) ) _ <- Task.fromCancelablePromise(startSignal) _ <- Task.sleep(transitionDelay) _ <- Task(delegate.stage = stage.value()) .executeOn(schedulers.fx.value) .delayExecution(transitionDelay) } yield fxApp -> fib) { case _ -> fib => fib.cancel } .map { case a -> _ => a } }