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 { |
javafx-dispatcher { |
||||
type = "Dispatcher" |
type = "Dispatcher" |
||||
executor = "akka.dispatch.gui.JavaFXEventThreadExecutorServiceConfigurator" |
|
||||
|
executor = "nova.monadic_sfx.executors.JavaFXEventThreadExecutorServiceConfigurator" |
||||
throughput = 1 |
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