Browse Source
Modularized code
Modularized code
Moved all resource creation code to modules (thin cake pattern) Cleanup Added test actor running on fx threadmaster
Rohan Sircar
4 years ago
19 changed files with 467 additions and 375 deletions
-
2src/main/resources/application.conf
-
143src/main/scala/nova/monadic_sfx/Main.scala
-
7src/main/scala/nova/monadic_sfx/MainModule.scala
-
49src/main/scala/nova/monadic_sfx/actors/ActorModule.scala
-
34src/main/scala/nova/monadic_sfx/actors/TestActor.scala
-
5src/main/scala/nova/monadic_sfx/executors/ExecutorsModule.scala
-
2src/main/scala/nova/monadic_sfx/executors/GUIExecutor.scala
-
10src/main/scala/nova/monadic_sfx/http/Backend.scala
-
28src/main/scala/nova/monadic_sfx/http/HttpModule.scala
-
26src/main/scala/nova/monadic_sfx/http/requests/DummyRequest.scala
-
79src/main/scala/nova/monadic_sfx/modules/MainModule.scala
-
39src/main/scala/nova/monadic_sfx/pages/HomePage.scala
-
102src/main/scala/nova/monadic_sfx/pages/LoginPage.scala
-
90src/main/scala/nova/monadic_sfx/ui/MyFxApp.scala
-
37src/main/scala/nova/monadic_sfx/ui/UiModule.scala
-
45src/main/scala/nova/monadic_sfx/ui/screens/HomeScreen.scala
-
108src/main/scala/nova/monadic_sfx/ui/screens/LoginScreen.scala
-
13src/main/scala/nova/monadic_sfx/ui/screens/Screen.scala
-
23src/main/scala/nova/monadic_sfx/util/Action.scala
@ -1,5 +1,5 @@ |
|||
javafx-dispatcher { |
|||
type = "Dispatcher" |
|||
executor = "akka.dispatch.gui.JavaFXEventThreadExecutorServiceConfigurator" |
|||
executor = "nova.monadic_sfx.executors.JavaFXEventThreadExecutorServiceConfigurator" |
|||
throughput = 1 |
|||
} |
@ -0,0 +1,7 @@ |
|||
package nova.monadic_sfx |
|||
|
|||
import nova.monadic_sfx.actors.ActorModule |
|||
import nova.monadic_sfx.ui.UiModule |
|||
import nova.monadic_sfx.http.HttpModule |
|||
|
|||
trait MainModule extends ActorModule with UiModule with HttpModule |
@ -0,0 +1,49 @@ |
|||
package nova.monadic_sfx.actors |
|||
|
|||
import io.odin.Logger |
|||
import monix.eval.Task |
|||
import cats.effect.Resource |
|||
import akka.actor._ |
|||
import akka.actor.typed.scaladsl.adapter._ |
|||
import akka.actor.typed.scaladsl.Behaviors |
|||
import com.softwaremill.macwire._ |
|||
import akka.actor.typed.Behavior |
|||
import akka.actor.typed.DispatcherSelector |
|||
|
|||
trait ActorModule { |
|||
def actorResource(logger: Logger[Task]): Resource[Task, ActorSystem] = |
|||
Resource.make(logger.info("Creating Actor System") >> Task { |
|||
ActorSystem( |
|||
name = "FXActorSystem" |
|||
) |
|||
})(sys => |
|||
logger.info("Shutting down actor system") >> Task.fromFuture( |
|||
sys.terminate() |
|||
) >> logger.info("Actor System terminated") |
|||
) |
|||
|
|||
def testActor( |
|||
system: ActorSystem |
|||
): akka.actor.typed.ActorRef[Counter.Command] = { |
|||
val behaviour: Behavior[Counter.Command] = |
|||
Behaviors.setup(context => wire[Counter]) |
|||
system.spawn( |
|||
behaviour, |
|||
"CounterActor", |
|||
DispatcherSelector.fromConfig("javafx-dispatcher") |
|||
) |
|||
} |
|||
|
|||
def testActorL( |
|||
system: ActorSystem |
|||
): Task[akka.actor.typed.ActorRef[Counter.Command]] = |
|||
Task { |
|||
val behaviour: Behavior[Counter.Command] = |
|||
Behaviors.setup(context => wire[Counter]) |
|||
system.spawn( |
|||
behaviour, |
|||
"CounterActor", |
|||
DispatcherSelector.fromConfig("javafx-dispatcher") |
|||
) |
|||
} |
|||
} |
@ -0,0 +1,34 @@ |
|||
package nova.monadic_sfx.actors |
|||
|
|||
import akka.actor.typed._ |
|||
import akka.actor.typed.scaladsl._ |
|||
|
|||
object Counter { |
|||
sealed trait Command |
|||
case object Increment extends Command |
|||
final case class GetValue(replyTo: ActorRef[Value]) extends Command |
|||
final case class Value(n: Int) |
|||
|
|||
def apply(): Behavior[Command] = { |
|||
Behaviors.setup(context => new Counter(context)) |
|||
} |
|||
} |
|||
|
|||
class Counter(context: ActorContext[Counter.Command]) |
|||
extends AbstractBehavior[Counter.Command](context) { |
|||
import Counter._ |
|||
|
|||
private var n = 0 |
|||
|
|||
override def onMessage(msg: Command): Behavior[Counter.Command] = { |
|||
msg match { |
|||
case Increment => |
|||
n += 1 |
|||
context.log.debug("Incremented counter to [{}]", n) |
|||
this |
|||
case GetValue(replyTo) => |
|||
replyTo ! Value(n) |
|||
Behaviors.stopped |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,5 @@ |
|||
package nova.monadic_sfx.executors |
|||
|
|||
trait ExecutorsModule { |
|||
lazy val schedulers = new Schedulers() |
|||
} |
@ -1,10 +0,0 @@ |
|||
package nova.monadic_sfx.http |
|||
|
|||
import sttp.client.asynchttpclient.monix.AsyncHttpClientMonixBackend |
|||
import nova.monadic_sfx.AppTypes |
|||
|
|||
object Backend { |
|||
val backend = AsyncHttpClientMonixBackend |
|||
.resource() |
|||
def apply() = { backend } |
|||
} |
@ -0,0 +1,28 @@ |
|||
package nova.monadic_sfx.http |
|||
|
|||
import nova.monadic_sfx.http.requests.DummyRequest |
|||
import nova.monadic_sfx.AppTypes |
|||
|
|||
trait HttpModule { |
|||
def requesters( |
|||
backend: AppTypes.HttpBackend, |
|||
system: akka.actor.ActorSystem |
|||
): Requesters = { |
|||
import com.softwaremill.macwire._ |
|||
val dummyRequester = wire[DummyRequest] |
|||
wire[Requesters] |
|||
} |
|||
} |
|||
|
|||
class Requesters(val dummyRequester: DummyRequest) |
|||
|
|||
// object Requesters { |
|||
// def apply( |
|||
// backend: AppTypes.HttpBackend, |
|||
// system: akka.actor.ActorSystem |
|||
// ): Requesters = { |
|||
// import com.softwaremill.macwire._ |
|||
// val dummyRequester = wire[DummyRequest] |
|||
// wire[Requesters] |
|||
// } |
|||
// } |
@ -1,79 +0,0 @@ |
|||
package nova.monadic_sfx.modules |
|||
|
|||
import nova.monadic_sfx.executors.Schedulers |
|||
import monix.execution.Scheduler |
|||
import nova.monadic_sfx.http.requests.DummyRequest |
|||
import monix.eval.Task |
|||
import akka.{actor => classic} |
|||
import cats.effect.Resource |
|||
import nova.monadic_sfx.AppTypes |
|||
|
|||
trait MainModule { |
|||
import com.softwaremill.macwire._ |
|||
// val schedulers: Schedulers = new Schedulers() |
|||
|
|||
// implicit val defaultScheduler: Scheduler = schedulers.fx |
|||
|
|||
// val program = |
|||
// for { |
|||
// backend <- Backend() |
|||
// fxActorSystem <- |
|||
// Resource |
|||
// .make(Task { |
|||
// classic.ActorSystem( |
|||
// name = "FXActorSystem" |
|||
// ) |
|||
// })(sys => Task(sys.terminate())) |
|||
|
|||
// } yield { |
|||
// val dummyRequester = wire[DummyRequest] |
|||
// dummyRequester.send() |
|||
// } |
|||
|
|||
// val program = Backend().use(backend => |
|||
// Resource |
|||
// .make(Task { |
|||
// classic.ActorSystem( |
|||
// name = "FXActorSystem" |
|||
// ) |
|||
// })(sys => Task(sys.terminate())) |
|||
// .use { implicit system => |
|||
// // system.spa |
|||
// // system.typed |
|||
// // val javaFxActor = system.actorOf( |
|||
// // Props[JavaFxActor]().withDispatcher("javafx-dispatcher"), |
|||
// // "javaFxActor" |
|||
// // ) |
|||
// // val swingActor = system.actorOf( |
|||
// // Props[SwingActor]().withDispatcher("swing-dispatcher"), |
|||
// // "swingActor" |
|||
// // ) |
|||
// Task(new DummyRequest(backend)) >> |
|||
// Task.unit |
|||
// } |
|||
// ) |
|||
def schedulers: Schedulers |
|||
|
|||
def defaultScheduler: Scheduler |
|||
|
|||
def backendTask: Task[AppTypes.HttpBackend] |
|||
def actorSystemTask: Task[classic.ActorSystem] |
|||
|
|||
def deps = |
|||
for { |
|||
backend <- backendTask |
|||
actorSystem <- actorSystemTask |
|||
dummyRequesterTask <- Task { |
|||
wireDeps(backend, actorSystem) |
|||
} |
|||
} yield dummyRequesterTask |
|||
|
|||
def wireDeps( |
|||
backend: AppTypes.HttpBackend, |
|||
system: classic.ActorSystem |
|||
): DummyRequest = { |
|||
wire[DummyRequest] |
|||
// new DummyRequest(backend) |
|||
} |
|||
|
|||
} |
@ -1,39 +0,0 @@ |
|||
package nova.monadic_sfx.pages |
|||
import nova.monadic_sfx.AppTypes |
|||
import scalafx.scene.control.TextField |
|||
import scalafx.scene.control._ |
|||
import scalafx.scene.layout.VBox |
|||
import scalafx.scene.Node |
|||
import scalafx.Includes._ |
|||
import scalafx.scene.layout.HBox |
|||
import scalafx.scene.text.Text |
|||
import scalafx.scene.Parent |
|||
import scalafx.application.JFXApp.PrimaryStage |
|||
|
|||
class HomePage( |
|||
backend: AppTypes.HttpBackend, |
|||
system: akka.actor.ActorSystem, |
|||
onLogout: () => Unit |
|||
) { |
|||
private lazy val root = new HBox { |
|||
children = List( |
|||
new Text { |
|||
text = "hello" |
|||
}, |
|||
new Button { |
|||
text = "logout" |
|||
onAction = () => onLogout() |
|||
} |
|||
) |
|||
} |
|||
def render = root |
|||
} |
|||
|
|||
object HomePage { |
|||
def apply( |
|||
backend: AppTypes.HttpBackend, |
|||
system: akka.actor.ActorSystem, |
|||
onLogout: () => Unit |
|||
): Parent = |
|||
new HomePage(backend, system, onLogout).render |
|||
} |
@ -1,102 +0,0 @@ |
|||
package nova.monadic_sfx.pages |
|||
import nova.monadic_sfx.AppTypes |
|||
import scalafx.scene.control.TextField |
|||
import scalafx.scene.control._ |
|||
import scalafx.scene.layout.VBox |
|||
import scalafx.scene.Node |
|||
import scalafx.Includes._ |
|||
import scalafx.scene.Parent |
|||
import scalafx.application.JFXApp.PrimaryStage |
|||
import nova.monadic_sfx.http.requests.DummyRequest |
|||
import monix.eval.Task |
|||
import monix.execution.Scheduler |
|||
// import io.odin.syntax._ |
|||
// import _root_.monix.eval.Task |
|||
// import io.odin.monix._ |
|||
// import javafx.beans.property.ObjectProperty |
|||
// import javafx.event.{ActionEvent, EventHandler} |
|||
class LoginPage( |
|||
appStage: PrimaryStage, |
|||
backend: AppTypes.HttpBackend, |
|||
system: akka.actor.ActorSystem |
|||
) { |
|||
|
|||
val dummyRequester = new DummyRequest(backend) |
|||
|
|||
//pure function callbacks, but with side effects still |
|||
private def onLogout(stage: PrimaryStage) = |
|||
for { |
|||
_ <- Task { println("logging out") } |
|||
root <- render |
|||
_ <- Task(stage.scene().setRoot(root)) |
|||
} yield () |
|||
|
|||
private def onLogin(stage: PrimaryStage) = |
|||
Task.deferAction { implicit Scheduler => |
|||
for { |
|||
_ <- Task(println("logging in")) |
|||
root <- Task { |
|||
stage |
|||
.scene() |
|||
.setRoot( |
|||
HomePage( |
|||
backend, |
|||
system, |
|||
() => runFxTask(onLogout(appStage)) |
|||
) |
|||
) |
|||
} |
|||
} yield () |
|||
} |
|||
|
|||
private lazy val root = Task.deferAction(implicit scheduler => |
|||
Task { |
|||
new VBox { |
|||
children = Seq( |
|||
new Label { |
|||
text = "username" |
|||
}, |
|||
new TextField(), |
|||
new Label { |
|||
text = "password" |
|||
}, |
|||
new TextField(), |
|||
new Button { |
|||
text = "Login" |
|||
onAction = () => |
|||
runFxTask { |
|||
Task |
|||
.parZip2( |
|||
dummyRequester |
|||
.send(), |
|||
// .executeOn(Scheduler.global) |
|||
onLogin(appStage) |
|||
) |
|||
} |
|||
} |
|||
) |
|||
} |
|||
} |
|||
) |
|||
def render: Task[Parent] = root |
|||
|
|||
/** |
|||
* Implicitly runs monix task as fire and forget. \ |
|||
* For use in ScalaFX callbacks. |
|||
* |
|||
* @param task |
|||
* @param s |
|||
*/ |
|||
def runFxTask[T](task: => Task[T])(implicit s: Scheduler) = { |
|||
task.runAsyncAndForget |
|||
} |
|||
|
|||
} |
|||
|
|||
object LoginPage { |
|||
def apply( |
|||
appStage: PrimaryStage, |
|||
backend: AppTypes.HttpBackend, |
|||
system: akka.actor.ActorSystem |
|||
) = new LoginPage(appStage, backend, system).render |
|||
} |
@ -0,0 +1,90 @@ |
|||
package nova.monadic_sfx.ui |
|||
|
|||
import scalafx.application.JFXApp |
|||
import nova.monadic_sfx.executors.Schedulers |
|||
import monix.execution.Scheduler |
|||
import monix.eval.Task |
|||
import nova.monadic_sfx.screens.LoginScreen |
|||
import nova.monadic_sfx.AppTypes |
|||
import scalafx.application.Platform |
|||
import scala.concurrent.duration._ |
|||
import io.odin.Logger |
|||
import monix.execution.Callback |
|||
import com.softwaremill.macwire._ |
|||
import nova.monadic_sfx.http.Requesters |
|||
|
|||
import akka.actor._ |
|||
import akka.actor.typed.Behavior |
|||
import akka.actor.typed.scaladsl.adapter._ |
|||
import akka.actor.typed.scaladsl.Behaviors |
|||
import nova.monadic_sfx.actors.Counter |
|||
import akka.actor.typed.DispatcherSelector |
|||
|
|||
class MyFxApp( |
|||
logger: Logger[Task], |
|||
backend: AppTypes.HttpBackend, |
|||
actorSystem: akka.actor.ActorSystem, |
|||
requesters: Requesters, |
|||
schedulers: Schedulers |
|||
) extends JFXApp { |
|||
|
|||
implicit lazy val defaultScheduler: Scheduler = schedulers.fx |
|||
|
|||
lazy val application = |
|||
for { |
|||
appStage <- Task( |
|||
UiModule.makePrimaryStage(backend, actorSystem) |
|||
) |
|||
// _ <- Task { |
|||
// val counterActor = testActor(actorSystem) |
|||
// counterActor ! (Counter.Increment) |
|||
// } |
|||
_ <- Task { stage = appStage } |
|||
_ <- Task.sleep(2.seconds) |
|||
loginScene <- wire[LoginScreen].render |
|||
_ <- Task { |
|||
// appStage.maximized = true |
|||
appStage.height = 800 |
|||
appStage.width = 800 |
|||
appStage |
|||
.scene() |
|||
.setRoot( |
|||
loginScene |
|||
) |
|||
} |
|||
} yield () |
|||
|
|||
def testActor( |
|||
system: ActorSystem |
|||
): akka.actor.typed.ActorRef[Counter.Command] = { |
|||
val behaviour: Behavior[Counter.Command] = |
|||
Behaviors.setup(context => wire[Counter]) |
|||
system.spawn( |
|||
behaviour, |
|||
"CounterActor", |
|||
DispatcherSelector.fromConfig("javafx-dispatcher") |
|||
) |
|||
} |
|||
|
|||
application.timed.runAsync( |
|||
new Callback[Throwable, (FiniteDuration, Unit)] { |
|||
|
|||
override def onSuccess(value: (FiniteDuration, Unit)): Unit = { |
|||
val (duration, _) = value |
|||
println( |
|||
s"Application started successfully in ${duration.toSeconds} seconds" |
|||
) |
|||
} |
|||
|
|||
override def onError(e: Throwable): Unit = { |
|||
println("Application start failed. Reason -") |
|||
e.printStackTrace() |
|||
} |
|||
|
|||
} |
|||
) |
|||
|
|||
override def stopApp() = { |
|||
Platform.exit() |
|||
} |
|||
} |
@ -0,0 +1,37 @@ |
|||
package nova.monadic_sfx.ui |
|||
|
|||
import scalafx.application.JFXApp |
|||
import monix.eval.Task |
|||
import nova.monadic_sfx.AppTypes |
|||
import scalafx.application.JFXApp.PrimaryStage |
|||
import io.odin.Logger |
|||
import cats.effect.Resource |
|||
import com.softwaremill.macwire._ |
|||
import nova.monadic_sfx.http.Requesters |
|||
import nova.monadic_sfx.executors.Schedulers |
|||
|
|||
trait UiModule { |
|||
def fxAppResource( |
|||
logger: Logger[Task], |
|||
backend: AppTypes.HttpBackend, |
|||
actorSystem: akka.actor.ActorSystem, |
|||
requesters: Requesters, |
|||
schedulers: Schedulers |
|||
): Resource[Task, JFXApp] = |
|||
Resource.make(logger.info("Creating FX Application") >> Task { |
|||
val app: JFXApp = wire[MyFxApp] |
|||
app |
|||
})(app => logger.info("Stopping FX Application") >> Task(app.stopApp())) |
|||
|
|||
} |
|||
|
|||
object UiModule { |
|||
def makePrimaryStage( |
|||
backend: AppTypes.HttpBackend, |
|||
actorSystem: akka.actor.ActorSystem |
|||
) = { |
|||
new PrimaryStage { |
|||
scene = new DefaultUI().scene |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,45 @@ |
|||
package nova.monadic_sfx.screens |
|||
import nova.monadic_sfx.AppTypes |
|||
import scalafx.scene.control.TextField |
|||
import scalafx.scene.control._ |
|||
import scalafx.scene.layout.VBox |
|||
import scalafx.scene.Node |
|||
import scalafx.Includes._ |
|||
import scalafx.scene.layout.HBox |
|||
import scalafx.scene.text.Text |
|||
import scalafx.scene.Parent |
|||
import scalafx.application.JFXApp.PrimaryStage |
|||
import monix.eval.Task |
|||
import nova.monadic_sfx.util.Action |
|||
|
|||
class HomeScreen( |
|||
backend: AppTypes.HttpBackend, |
|||
system: akka.actor.ActorSystem, |
|||
onLogout: () => Task[Unit] |
|||
) { |
|||
private lazy val root = Task.deferAction { implicit s => |
|||
Task { |
|||
new HBox { |
|||
children = List( |
|||
new Text { |
|||
text = "hello" |
|||
}, |
|||
new Button { |
|||
text = "logout" |
|||
onAction = () => Action.asyncT(onLogout()) |
|||
} |
|||
) |
|||
} |
|||
} |
|||
} |
|||
def render = root |
|||
} |
|||
|
|||
object HomeScreen { |
|||
def apply( |
|||
backend: AppTypes.HttpBackend, |
|||
system: akka.actor.ActorSystem, |
|||
onLogout: () => Task[Unit] |
|||
): Task[Parent] = |
|||
new HomeScreen(backend, system, onLogout).render |
|||
} |
@ -0,0 +1,108 @@ |
|||
package nova.monadic_sfx.screens |
|||
import nova.monadic_sfx.AppTypes |
|||
import scalafx.scene.control.TextField |
|||
import scalafx.scene.control._ |
|||
import scalafx.scene.layout.VBox |
|||
import scalafx.scene.Node |
|||
import scalafx.Includes._ |
|||
import scalafx.scene.Parent |
|||
import scalafx.application.JFXApp.PrimaryStage |
|||
import nova.monadic_sfx.http.requests.DummyRequest |
|||
import monix.eval.Task |
|||
import monix.execution.Scheduler |
|||
import cats.effect.Effect |
|||
import cats.effect.implicits._ |
|||
import nova.monadic_sfx.util.Action |
|||
import io.odin.Logger |
|||
import nova.monadic_sfx.http.Requesters |
|||
import sttp.client.Response |
|||
import nova.monadic_sfx.models.HttpBinResponse |
|||
import sttp.client.ResponseError |
|||
import nova.monadic_sfx.executors.Schedulers |
|||
import nova.monadic_sfx.ui.screens.Screen |
|||
// import io.odin.syntax._ |
|||
// import _root_.monix.eval.Task |
|||
// import io.odin.monix._ |
|||
// import javafx.beans.property.ObjectProperty |
|||
// import javafx.event.{ActionEvent, EventHandler} |
|||
class LoginScreen( |
|||
override protected val appStage: PrimaryStage, |
|||
logger: Logger[Task], |
|||
backend: AppTypes.HttpBackend, |
|||
system: akka.actor.ActorSystem, |
|||
requesters: Requesters, |
|||
schedulers: Schedulers |
|||
) extends Screen { |
|||
val dummyRequester: DummyRequest = requesters.dummyRequester |
|||
//pure function callbacks, but with side effects still |
|||
|
|||
// lazy val hs = { |
|||
// import com.softwaremill.macwire._ |
|||
// lazy val action = () => onLogout(appStage) |
|||
// wire[HomeScreen] |
|||
// } |
|||
|
|||
private def onLogout(stage: PrimaryStage) = |
|||
for { |
|||
_ <- logger.info("Logging out") |
|||
root <- render |
|||
_ <- changeRootL(root) |
|||
} yield () |
|||
|
|||
private def onLogin(stage: PrimaryStage) = |
|||
for { |
|||
_ <- logger.info("Logging in") |
|||
homeScreen <- HomeScreen( |
|||
backend, |
|||
system, |
|||
() => onLogout(appStage) |
|||
) |
|||
_ <- Task { stage.scene().setRoot(homeScreen) } |
|||
} yield () |
|||
|
|||
private lazy val root = Task.deferAction(implicit scheduler => |
|||
Task { |
|||
new VBox { |
|||
children = Seq( |
|||
new Label { |
|||
text = "username" |
|||
}, |
|||
new TextField(), |
|||
new Label { |
|||
text = "password" |
|||
}, |
|||
new TextField(), |
|||
new Button { |
|||
text = "Login" |
|||
onAction = () => |
|||
Action.asyncT { |
|||
Task |
|||
.parSequence( |
|||
List( |
|||
testRequest, |
|||
// .executeOn(Scheduler.global) |
|||
onLogin(appStage) |
|||
) |
|||
) |
|||
} |
|||
} |
|||
) |
|||
} |
|||
} |
|||
) |
|||
def render: Task[Parent] = root |
|||
|
|||
val testRequest = for { |
|||
res <- dummyRequester.send() |
|||
_ <- logger.info(res.body.toString()) |
|||
} yield () |
|||
|
|||
} |
|||
|
|||
// object LoginScreen { |
|||
// def apply( |
|||
// appStage: PrimaryStage, |
|||
// backend: AppTypes.HttpBackend, |
|||
// system: akka.actor.ActorSystem |
|||
// ) = new LoginScreen(appStage, backend, system).render |
|||
// } |
@ -0,0 +1,13 @@ |
|||
package nova.monadic_sfx.ui.screens |
|||
|
|||
import scalafx.application.JFXApp.PrimaryStage |
|||
import scalafx.scene.Parent |
|||
import monix.eval.Task |
|||
|
|||
trait Screen { |
|||
protected def appStage: PrimaryStage |
|||
def changeRoot(root: Parent): Unit = { |
|||
appStage.scene().setRoot(root) |
|||
} |
|||
def changeRootL(root: Parent): Task[Unit] = Task(changeRoot(root)) |
|||
} |
@ -0,0 +1,23 @@ |
|||
package nova.monadic_sfx.util |
|||
|
|||
import monix.eval.Task |
|||
import monix.execution.Scheduler |
|||
import cats.effect.Effect |
|||
import cats.effect.implicits._ |
|||
|
|||
object Action { |
|||
|
|||
/** |
|||
* Implicitly runs monix task as fire and forget. \ |
|||
* For use in ScalaFX callbacks. |
|||
* |
|||
* @param task |
|||
* @param s |
|||
*/ |
|||
def asyncT[T](task: => Task[T])(implicit s: Scheduler): Unit = { |
|||
task.runAsyncAndForget |
|||
} |
|||
|
|||
def asyncF[F[_]: Effect, T](cb: => F[T]): Unit = |
|||
cb.toIO.unsafeRunAsyncAndForget() |
|||
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue