Browse Source

Cleanup and added some methods to actionObservable

master
Rohan Sircar 4 months ago
parent
commit
857fd03bf1
13 changed files with 102 additions and 110 deletions
  1. +2
    -2
      src/main/scala/nova/monadic_sfx/Main.scala
  2. +3
    -3
      src/main/scala/nova/monadic_sfx/MainApp.scala
  3. +62
    -16
      src/main/scala/nova/monadic_sfx/implicits/ActionObservable.scala
  4. +0
    -3
      src/main/scala/nova/monadic_sfx/implicits/JFXButton.scala
  5. +14
    -52
      src/main/scala/nova/monadic_sfx/implicits/JavaFxMonixObservables.scala
  6. +2
    -1
      src/main/scala/nova/monadic_sfx/implicits/MenuItem.scala
  7. +1
    -1
      src/main/scala/nova/monadic_sfx/ui/components/todo/TodoListComponentOld.scala
  8. +8
    -23
      src/main/scala/nova/monadic_sfx/ui/components/todo/TodoListStore.scala
  9. +1
    -1
      src/main/scala/nova/monadic_sfx/ui/controller/TodoController.scala
  10. +1
    -1
      src/main/scala/nova/monadic_sfx/util/reactive/Middlewares.scala
  11. +3
    -2
      src/main/scala/nova/monadic_sfx/util/reactive/MonixProSubject.scala
  12. +1
    -1
      src/main/scala/nova/monadic_sfx/util/reactive/Reducer.scala
  13. +4
    -4
      src/main/scala/nova/monadic_sfx/util/reactive/Store.scala

+ 2
- 2
src/main/scala/nova/monadic_sfx/Main.scala View File

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

+ 3
- 3
src/main/scala/nova/monadic_sfx/MainApp.scala View File

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

+ 62
- 16
src/main/scala/nova/monadic_sfx/implicits/ActionObservable.scala View File

@ -1,13 +1,13 @@
package nova.monadic_sfx.implicits
import monix.execution.Scheduler
import monix.reactive.Observable
import monix.reactive.Observer
import monix.{eval => me}
import monix.execution.Scheduler
class ActionObservableExecuter[T](
delegate: Observable[T]
) {
class ActionObservableExecutor[T](
private val delegate: Observable[T]
) extends AnyVal {
def -->(sub: Observer[T])(implicit s: Scheduler) =
delegate
.doOnNext(el => me.Task(sub.onNext(el)))
@ -15,23 +15,69 @@ class ActionObservableExecuter[T](
}
class ActionObservableBuilder[A](
observableAction: Observable[A]
) {
def useLazy[T](v: => T) =
new ActionObservableExecuter[T](observableAction.mapEval(_ => me.Task(v)))
def use[T](cb: A => T) =
new ActionObservableExecuter[T](
observableAction.mapEval(ae => me.Task(cb(ae)))
private val observableAction: Observable[A]
) extends AnyVal {
def useLazyEval[T](v: => me.Task[T]) =
new ActionObservableExecutor[T](observableAction.mapEval(_ => v))
def useEval[T](cb: A => me.Task[T]) =
new ActionObservableExecutor[T](
observableAction.mapEval(cb)
)
def useIterable[T](cb: A => collection.immutable.Iterable[T]) =
new ActionObservableExecuter[T](
def useIterableEval[T](cb: A => collection.immutable.Iterable[T]) =
new ActionObservableExecutor[T](
observableAction.flatMap(a =>
Observable.suspend(Observable.fromIterable(cb(a)))
)
)
def map[B](cb: A => B) =
new ActionObservableBuilder(observableAction.mapEval(v => me.Task(cb(v))))
def doOnNext(cb: A => me.Task[Unit]): ActionObservableBuilder[A] =
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[])

+ 0
- 3
src/main/scala/nova/monadic_sfx/implicits/JFXButton.scala View File

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

+ 14
- 52
src/main/scala/nova/monadic_sfx/implicits/JavaFxMonixObservables.scala View File

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

+ 2
- 1
src/main/scala/nova/monadic_sfx/implicits/MenuItem.scala View File

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

+ 1
- 1
src/main/scala/nova/monadic_sfx/ui/components/todo/TodoListComponentOld.scala View File

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

+ 8
- 23
src/main/scala/nova/monadic_sfx/ui/components/todo/TodoListStore.scala View File

@ -1,14 +1,12 @@
package nova.monadic_sfx.ui.components.todo
import nova.monadic_sfx.util.reactive.Store
import nova.monadic_sfx.util.reactive.Reducer
import nova.monadic_sfx.util.reactive.Middlewares.actionLoggerMiddleware
import com.softwaremill.quicklens._
import io.circe.generic.JsonCodec
import io.odin.Logger
import monix.bio.Task
import io.odin._
import io.odin.syntax._
import io.circe.generic.JsonCodec
import com.softwaremill.quicklens._
import nova.monadic_sfx.util.reactive.Middlewares.actionLoggerMiddleware
import nova.monadic_sfx.util.reactive.Reducer
import nova.monadic_sfx.util.reactive.Store
case class Todo(id: Int, content: String)
@ -34,28 +32,15 @@ object TodoListStore {
todos = state.todos :+ Todo(state.counter, content),
counter = state.counter + 1
)
case Edit(id, content) =>
case Edit(_id, content) =>
val condition: Todo => Boolean = _.id == _id
state
.modify(_.todos.eachWhere(_.id == id))
.modify(_.todos.eachWhere(condition))
.using(_.copy(content = content))
case Delete(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]) =
Store
.createL[Command, State](

+ 1
- 1
src/main/scala/nova/monadic_sfx/ui/controller/TodoController.scala View File

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

+ 1
- 1
src/main/scala/nova/monadic_sfx/util/reactive/Middlewares.scala View File

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

+ 3
- 2
src/main/scala/nova/monadic_sfx/util/reactive/MonixProSubject.scala View File

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

+ 1
- 1
src/main/scala/nova/monadic_sfx/util/reactive/Reducer.scala View File

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

+ 4
- 4
src/main/scala/nova/monadic_sfx/util/reactive/Store.scala View File

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

Loading…
Cancel
Save