Cleanup and added some methods to actionObservable

This commit is contained in:
Rohan Sircar 2020-12-17 12:20:57 +05:30
parent f95f50574e
commit 857fd03bf1
13 changed files with 101 additions and 109 deletions

View File

@ -12,8 +12,8 @@ import com.softwaremill.macwire._
import io.odin._ import io.odin._
import io.odin.syntax._ import io.odin.syntax._
import nova.monadic_sfx.executors._ import nova.monadic_sfx.executors._
import nova.monadic_sfx.util.IOUtils._ // import nova.monadic_sfx.util.IOUtils._
import sttp.client.httpclient.monix.HttpClientMonixBackend // import sttp.client.httpclient.monix.HttpClientMonixBackend
object Main extends MainModule with BIOApp { object Main extends MainModule with BIOApp {
def appResource(startTime: Long) = def appResource(startTime: Long) =

View File

@ -7,6 +7,7 @@ import nova.monadic_sfx.executors.Schedulers
import nova.monadic_sfx.implicits.JFXButton import nova.monadic_sfx.implicits.JFXButton
import nova.monadic_sfx.implicits.JavaFXMonixObservables._ import nova.monadic_sfx.implicits.JavaFXMonixObservables._
import nova.monadic_sfx.ui.MyFxApp import nova.monadic_sfx.ui.MyFxApp
import nova.monadic_sfx.ui.components.todo.TodoListStore
import nova.monadic_sfx.ui.components.todo.TodoListView import nova.monadic_sfx.ui.components.todo.TodoListView
import org.gerweck.scalafx.util._ import org.gerweck.scalafx.util._
import scalafx.Includes._ import scalafx.Includes._
@ -21,7 +22,6 @@ import scalafx.scene.control.TableView
import scalafx.scene.layout.HBox import scalafx.scene.layout.HBox
import scalafx.scene.paint.Color import scalafx.scene.paint.Color
import scalafx.scene.shape.Rectangle import scalafx.scene.shape.Rectangle
import nova.monadic_sfx.ui.components.todo.TodoListStore
class MainApp( class MainApp(
// spawnProtocol: ActorSystem[SpawnProtocol.Command], // spawnProtocol: ActorSystem[SpawnProtocol.Command],
@ -131,8 +131,8 @@ class MainApp(
def createTodoComponent: Task[Unit] = def createTodoComponent: Task[Unit] =
for { for {
store <- TodoListStore(logger) store <- TodoListStore(logger)
lv <- TodoListView(store) rootNode <- TodoListView(store)
_ <- Task(_scene.getChildren += lv) _ <- Task(_scene.getChildren += rootNode)
} yield () } yield ()
} }

View File

@ -1,13 +1,13 @@
package nova.monadic_sfx.implicits package nova.monadic_sfx.implicits
import monix.execution.Scheduler
import monix.reactive.Observable import monix.reactive.Observable
import monix.reactive.Observer import monix.reactive.Observer
import monix.{eval => me} import monix.{eval => me}
import monix.execution.Scheduler
class ActionObservableExecuter[T]( class ActionObservableExecutor[T](
delegate: Observable[T] private val delegate: Observable[T]
) { ) extends AnyVal {
def -->(sub: Observer[T])(implicit s: Scheduler) = def -->(sub: Observer[T])(implicit s: Scheduler) =
delegate delegate
.doOnNext(el => me.Task(sub.onNext(el))) .doOnNext(el => me.Task(sub.onNext(el)))
@ -15,23 +15,69 @@ class ActionObservableExecuter[T](
} }
class ActionObservableBuilder[A]( class ActionObservableBuilder[A](
observableAction: Observable[A] private val observableAction: Observable[A]
) { ) extends AnyVal {
def useLazy[T](v: => T) = def useLazyEval[T](v: => me.Task[T]) =
new ActionObservableExecuter[T](observableAction.mapEval(_ => me.Task(v))) new ActionObservableExecutor[T](observableAction.mapEval(_ => v))
def use[T](cb: A => T) = def useEval[T](cb: A => me.Task[T]) =
new ActionObservableExecuter[T]( new ActionObservableExecutor[T](
observableAction.mapEval(ae => me.Task(cb(ae))) observableAction.mapEval(cb)
) )
def useIterable[T](cb: A => collection.immutable.Iterable[T]) = def useIterableEval[T](cb: A => collection.immutable.Iterable[T]) =
new ActionObservableExecuter[T]( new ActionObservableExecutor[T](
observableAction.flatMap(a => observableAction.flatMap(a =>
Observable.suspend(Observable.fromIterable(cb(a))) Observable.suspend(Observable.fromIterable(cb(a)))
) )
) )
def map[B](cb: A => B) = def doOnNext(cb: A => me.Task[Unit]): ActionObservableBuilder[A] =
new ActionObservableBuilder(observableAction.mapEval(v => me.Task(cb(v)))) new ActionObservableBuilder(observableAction.doOnNext(cb))
def mapEval[B](cb: A => me.Task[B]) =
new ActionObservableBuilder(observableAction.mapEval(cb))
def underlying = observableAction
// def publish[B](f: Observable[A] => Observable[B]) =
// new ActionObservableBuilder(observableAction.publishSelector(f))
def useEval2[B, C](f: A => me.Task[B], g: A => me.Task[C]) =
new ActionObservableExecutor[(B, C)](
observableAction.publishSelector(conn =>
conn
.mapEval(f)
.switchMap(b =>
conn.mapEval(a =>
for {
c <- g(a)
} yield (b, c)
)
)
)
)
def bifurcate[B, C](
f: ActionObservableBuilder[A] => B,
g: ActionObservableBuilder[A] => C
)(implicit s: Scheduler) =
observableAction
.publishSelector(conn =>
Observable(
Observable.unit.doOnNext(_ =>
me.Task(f(new ActionObservableBuilder[A](conn))) >> me.Task.unit
),
Observable.unit.doOnNext(_ =>
me.Task(g(new ActionObservableBuilder[A](conn))) >> me.Task.unit
)
).merge
)
.subscribe()
// def useEval2[B,C](a1: ActionObservableBuilder[A] => B, a2: ActionObservableBuilder[A] => C) = observableAction.publishSelector(conn =>
// new ActionObservableBuilder[]
// )
} }
// class MappedActionExecutor(actionMap: Map[])

View File

@ -14,9 +14,6 @@ object JFXButton {
if (v != null) v.delegate else null if (v != null) v.delegate else null
} }
// extends ButtonBase(delegate)
// with SFXDelegate[jfoenixc.JFXButton]
class JFXButton( class JFXButton(
override val delegate: jfoenixc.JFXButton = new jfoenixc.JFXButton override val delegate: jfoenixc.JFXButton = new jfoenixc.JFXButton
) extends Button(delegate) { ) extends Button(delegate) {

View File

@ -2,6 +2,8 @@ package nova.monadic_sfx.implicits
import javafx.beans.property.ObjectProperty import javafx.beans.property.ObjectProperty
import javafx.collections.ObservableList import javafx.collections.ObservableList
import javafx.event.ActionEvent
import javafx.event.EventHandler
import javafx.scene.{input => jfxsi} import javafx.scene.{input => jfxsi}
import javafx.{event => jfxe} import javafx.{event => jfxe}
import monix.bio.Task import monix.bio.Task
@ -13,18 +15,15 @@ import monix.reactive.Observer
import monix.reactive.OverflowStrategy import monix.reactive.OverflowStrategy
import monix.tail.Iterant import monix.tail.Iterant
import monix.{eval => me} import monix.{eval => me}
import org.gerweck.scalafx.util._
import scalafx.Includes._ import scalafx.Includes._
import scalafx.beans.property.Property import scalafx.beans.property.Property
import scalafx.beans.property.ReadOnlyProperty
import scalafx.beans.value.ObservableValue import scalafx.beans.value.ObservableValue
import scalafx.collections.ObservableBuffer import scalafx.collections.ObservableBuffer
import scalafx.scene.Scene import scalafx.scene.Scene
import scalafx.scene.control.ButtonBase import scalafx.scene.control.ButtonBase
import scalafx.beans.property.ReadOnlyProperty
import javafx.event.ActionEvent
import javafx.event.EventHandler
import javafx.scene.{control => jfxsc}
import scalafx.scene.control.MenuItem import scalafx.scene.control.MenuItem
import org.gerweck.scalafx.util._
object JavaFXMonixObservables { object JavaFXMonixObservables {
@ -80,8 +79,8 @@ object JavaFXMonixObservables {
op.onNext(prop.value) op.onNext(prop.value)
} }
def -->(op: Property[T, J]) = { def ==>(op: Property[T, J]) = {
op() = prop.value op <== prop
} }
def <--(obs: Observable[T])(implicit s: Scheduler) = { def <--(obs: Observable[T])(implicit s: Scheduler) = {
@ -90,13 +89,12 @@ object JavaFXMonixObservables {
def asOption = prop.map(Option(_)) def asOption = prop.map(Option(_))
def observableChange[J1 >: J]() def observableChange[J1 >: J](): Observable[J1] = {
: Observable[(ObservableValue[T, J], J1, J1)] = {
import monix.execution.cancelables.SingleAssignCancelable import monix.execution.cancelables.SingleAssignCancelable
Observable.create(OverflowStrategy.Unbounded) { sub => Observable.create(OverflowStrategy.Unbounded) { sub =>
val c = SingleAssignCancelable() val c = SingleAssignCancelable()
val canc = prop.onChange((a, b, c) => sub.onNext((a, b, c))) val canc = prop.onChange((a, b, c) => sub.onNext(c))
c := Cancelable(() => canc.cancel()) c := Cancelable(() => canc.cancel())
c c
@ -107,18 +105,9 @@ object JavaFXMonixObservables {
implicit final class BindObs2[A](private val prop: ObjectProperty[A]) implicit final class BindObs2[A](private val prop: ObjectProperty[A])
extends AnyVal { extends AnyVal {
// def -->(sub: Var[A]) =
// prop.onChange((a, b, c) => sub := c)
def -->(sub: Observer[A]) = def -->(sub: Observer[A]) =
prop.onChange((a, b, c) => if (c != null) sub.onNext(c)) prop.onChange((a, b, c) => if (c != null) sub.onNext(c))
// def -->[J1 >: A, T](
// op: Observable[J1] => me.Task[T]
// )(implicit s: Scheduler) = {
// op(prop.observableChange().map(_._3)).runToFuture
// }
def -->(op: Property[A, A]) = { def -->(op: Property[A, A]) = {
prop.onChange((a, b, c) => if (c != null) op() = c) prop.onChange((a, b, c) => if (c != null) op() = c)
} }
@ -147,21 +136,16 @@ object JavaFXMonixObservables {
op.onNext(prop.value) op.onNext(prop.value)
} }
def -->(op: Property[T, J]) = { def ==>(op: Property[T, J]) = {
op <== prop op <== prop
} }
// def <--(obs: Observable[T])(implicit s: Scheduler) = { def observableChange[J1 >: J](): Observable[J1] = {
// obs.doOnNext(v => me.Task(prop.value = v)).subscribe()
// }
def observableChange[J1 >: J]()
: Observable[(ObservableValue[T, J], J1, J1)] = {
import monix.execution.cancelables.SingleAssignCancelable import monix.execution.cancelables.SingleAssignCancelable
Observable.create(OverflowStrategy.Unbounded) { sub => Observable.create(OverflowStrategy.Unbounded) { sub =>
val c = SingleAssignCancelable() val c = SingleAssignCancelable()
val canc = prop.onChange((a, b, c) => sub.onNext((a, b, c))) val canc = prop.onChange((a, b, c) => sub.onNext(c))
c := Cancelable(() => canc.cancel()) c := Cancelable(() => canc.cancel())
c c
@ -227,17 +211,6 @@ object JavaFXMonixObservables {
implicit final class OnActionObservable( implicit final class OnActionObservable(
private val button: ButtonBase private val button: ButtonBase
) extends AnyVal { ) extends AnyVal {
// def -->[T](
// op: Observable[jfxe.ActionEvent] => me.Task[T]
// )(implicit s: Scheduler) = {
// op(button.observableAction()).runToFuture
// }
// def -->(
// sub: ConcurrentSubject[jfxe.ActionEvent, jfxe.ActionEvent]
// ) = {
// button.onAction = value => sub.onNext(value)
// }
def observableAction(): Observable[jfxe.ActionEvent] = { def observableAction(): Observable[jfxe.ActionEvent] = {
import monix.execution.cancelables.SingleAssignCancelable import monix.execution.cancelables.SingleAssignCancelable
@ -262,19 +235,8 @@ object JavaFXMonixObservables {
} }
implicit final class MenuItemActionObservable( implicit final class MenuItemActionObservable(
private val et: MenuItem private val item: MenuItem
) extends AnyVal { ) extends AnyVal {
// def -->[T](
// op: Observable[jfxe.ActionEvent] => me.Task[T]
// )(implicit s: Scheduler) = {
// op(button.observableAction()).runToFuture
// }
// def -->(
// sub: ConcurrentSubject[jfxe.ActionEvent, jfxe.ActionEvent]
// ) = {
// button.onAction = value => sub.onNext(value)
// }
def observableAction(): Observable[jfxe.ActionEvent] = { def observableAction(): Observable[jfxe.ActionEvent] = {
import monix.execution.cancelables.SingleAssignCancelable import monix.execution.cancelables.SingleAssignCancelable
@ -286,9 +248,9 @@ object JavaFXMonixObservables {
} }
} }
et.onAction = l item.onAction = l
c := Cancelable(() => c := Cancelable(() =>
et.removeEventHandler( item.removeEventHandler(
jfxe.ActionEvent.ACTION, jfxe.ActionEvent.ACTION,
l l
) )

View File

@ -1,8 +1,9 @@
package nova.monadic_sfx.implicits package nova.monadic_sfx.implicits
import JavaFXMonixObservables._
import scalafx.scene.{control => sfxc} import scalafx.scene.{control => sfxc}
import JavaFXMonixObservables._
class MenuItem extends sfxc.MenuItem { class MenuItem extends sfxc.MenuItem {
def obsAction = def obsAction =
new ActionObservableBuilder(this.observableAction()) new ActionObservableBuilder(this.observableAction())

View File

@ -14,6 +14,7 @@ import nova.monadic_sfx.implicits.FontIcon
import nova.monadic_sfx.implicits.IconLiteral import nova.monadic_sfx.implicits.IconLiteral
import nova.monadic_sfx.implicits.JFXListView import nova.monadic_sfx.implicits.JFXListView
import nova.monadic_sfx.implicits.JavaFXMonixObservables._ import nova.monadic_sfx.implicits.JavaFXMonixObservables._
import nova.monadic_sfx.util.reactive._
import scalafx.Includes._ import scalafx.Includes._
import scalafx.beans.property.StringProperty import scalafx.beans.property.StringProperty
import scalafx.collections.ObservableBuffer import scalafx.collections.ObservableBuffer
@ -23,7 +24,6 @@ import scalafx.scene.control.MenuItem
import scalafx.scene.control.SelectionMode import scalafx.scene.control.SelectionMode
import scalafx.scene.layout.HBox import scalafx.scene.layout.HBox
import scalafx.scene.text.Text import scalafx.scene.text.Text
import nova.monadic_sfx.util.reactive._
class TodoListViewOld( class TodoListViewOld(
val listView: JFXListView[Todo] = TodoListViewOld.defaultListView, val listView: JFXListView[Todo] = TodoListViewOld.defaultListView,

View File

@ -1,14 +1,12 @@
package nova.monadic_sfx.ui.components.todo package nova.monadic_sfx.ui.components.todo
import nova.monadic_sfx.util.reactive.Store import com.softwaremill.quicklens._
import nova.monadic_sfx.util.reactive.Reducer import io.circe.generic.JsonCodec
import nova.monadic_sfx.util.reactive.Middlewares.actionLoggerMiddleware
import io.odin.Logger import io.odin.Logger
import monix.bio.Task import monix.bio.Task
import io.odin._ import nova.monadic_sfx.util.reactive.Middlewares.actionLoggerMiddleware
import io.odin.syntax._ import nova.monadic_sfx.util.reactive.Reducer
import io.circe.generic.JsonCodec import nova.monadic_sfx.util.reactive.Store
import com.softwaremill.quicklens._
case class Todo(id: Int, content: String) case class Todo(id: Int, content: String)
@ -34,28 +32,15 @@ object TodoListStore {
todos = state.todos :+ Todo(state.counter, content), todos = state.todos :+ Todo(state.counter, content),
counter = state.counter + 1 counter = state.counter + 1
) )
case Edit(id, content) => case Edit(_id, content) =>
val condition: Todo => Boolean = _.id == _id
state state
.modify(_.todos.eachWhere(_.id == id)) .modify(_.todos.eachWhere(condition))
.using(_.copy(content = content)) .using(_.copy(content = content))
case Delete(id) => case Delete(id) =>
state.copy(state.todos.filterNot(_.id == id)) state.copy(state.todos.filterNot(_.id == id))
} }
def updateTodo(id: Int, content: String, todos: Vector[Todo]) =
todos.view.zipWithIndex
.find {
case (todo, index) => todo.id == id
}
.map {
case (todo, index) => todo.copy(content = content) -> index
}
.map {
case (todo, index) => todos.updated(index, todo)
}
val middlewareLogger = consoleLogger[Task]().withAsync()
def apply(logger: Logger[Task]) = def apply(logger: Logger[Task]) =
Store Store
.createL[Command, State]( .createL[Command, State](

View File

@ -12,11 +12,11 @@ import nova.monadic_sfx.implicits.JFXButton
import nova.monadic_sfx.implicits.JFXListView import nova.monadic_sfx.implicits.JFXListView
import nova.monadic_sfx.implicits.JFXTextArea import nova.monadic_sfx.implicits.JFXTextArea
import nova.monadic_sfx.implicits.JFXTextField import nova.monadic_sfx.implicits.JFXTextField
import nova.monadic_sfx.ui.components.todo.TodoListComponentOld
import scalafx.collections.ObservableBuffer import scalafx.collections.ObservableBuffer
import scalafx.scene.control.Label import scalafx.scene.control.Label
import scalafx.scene.layout.HBox import scalafx.scene.layout.HBox
import scalafx.scene.paint.Color import scalafx.scene.paint.Color
import nova.monadic_sfx.ui.components.todo.TodoListComponentOld
class TodoController(todoListComponent: TodoListComponentOld) { class TodoController(todoListComponent: TodoListComponentOld) {
import AnimFX._ import AnimFX._

View File

@ -1,8 +1,8 @@
package nova.monadic_sfx.util.reactive package nova.monadic_sfx.util.reactive
import io.odin.Logger import io.odin.Logger
import monix.reactive.Observable
import monix.bio.Task import monix.bio.Task
import monix.reactive.Observable
import nova.monadic_sfx.util.IOUtils._ import nova.monadic_sfx.util.IOUtils._
// object Middleware { // object Middleware {

View File

@ -1,11 +1,12 @@
package nova.monadic_sfx.util.reactive package nova.monadic_sfx.util.reactive
import scala.concurrent.Future
import monix.execution.Ack
import monix.execution.Cancelable import monix.execution.Cancelable
import monix.reactive.Observable import monix.reactive.Observable
import monix.reactive.Observer import monix.reactive.Observer
import scala.concurrent.Future
import monix.reactive.observers.Subscriber import monix.reactive.observers.Subscriber
import monix.execution.Ack
object MonixProSubject { object MonixProSubject {
def from[I, O]( def from[I, O](

View File

@ -1,8 +1,8 @@
package nova.monadic_sfx.util.reactive package nova.monadic_sfx.util.reactive
import monix.reactive.ObservableLike
import cats.implicits._ import cats.implicits._
import monix.reactive.Observable import monix.reactive.Observable
import monix.reactive.ObservableLike
object Reducer { object Reducer {

View File

@ -1,11 +1,11 @@
package nova.monadic_sfx.util.reactive package nova.monadic_sfx.util.reactive
import cats.effect.Sync
import monix.bio.Task
import monix.execution.Scheduler
import monix.reactive.Observable
import monix.reactive.OverflowStrategy import monix.reactive.OverflowStrategy
import monix.reactive.subjects.ConcurrentSubject import monix.reactive.subjects.ConcurrentSubject
import monix.reactive.Observable
import monix.bio.Task
import cats.effect.Sync
import monix.execution.Scheduler
object Store { object Store {
def createL[A, M]( def createL[A, M](