diff --git a/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/MainScene.scala b/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/MainScene.scala new file mode 100644 index 000000000..bb8786859 --- /dev/null +++ b/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/MainScene.scala @@ -0,0 +1,40 @@ +package lofi_acl.example.monotonic_acl + +import scalafx.geometry.Pos +import scalafx.scene.Scene +import scalafx.scene.control.{Button, TextField} +import scalafx.scene.layout.{BorderPane, HBox, VBox} + +class MainScene extends Scene { + private val viewModel = new MainSceneViewModel() + private val rootPane = new BorderPane() + + private val createNewDocumentButton: Button = new Button("Create new Travel Plan Document") + createNewDocumentButton.alignment = Pos.Center + createNewDocumentButton.onAction = _ => viewModel.createNewDocumentButtonPressed() + createNewDocumentButton.disable <== viewModel.documentIsOpen + + private val joinDocumentButton: Button = new Button("Join") + joinDocumentButton.alignment = Pos.Center + joinDocumentButton.onAction = _ => viewModel.joinDocumentButtonPressed() + joinDocumentButton.disable <== viewModel.documentIsOpen + + private val remoteDocumentUriTextField = new TextField { + promptText = "user@host:port" + // hgrow = Priority.Always + } + remoteDocumentUriTextField.disable <== viewModel.documentIsOpen + remoteDocumentUriTextField.text <==> viewModel.joinDocumentUri + + rootPane.center = VBox( + createNewDocumentButton, + HBox( + remoteDocumentUriTextField, + joinDocumentButton + ) + ) + + content = rootPane + + // TODO: Hook in the document view on document open +} diff --git a/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/MainSceneViewModel.scala b/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/MainSceneViewModel.scala new file mode 100644 index 000000000..59a590de3 --- /dev/null +++ b/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/MainSceneViewModel.scala @@ -0,0 +1,38 @@ +package lofi_acl.example.monotonic_acl + +import scalafx.beans.property.{BooleanProperty, StringProperty} +import scalafx.scene.layout.StackPane + +import scala.concurrent.ExecutionContext.global + +class MainSceneViewModel { + private var model: Option[TravelPlanModel] = None + + val bucketListViewContainer: StackPane = new StackPane() + bucketListViewContainer.minWidth = 400 + bucketListViewContainer.minHeight = 800 + + val expenseViewContainer: StackPane = new StackPane() + expenseViewContainer.minWidth = 400 + expenseViewContainer.minHeight = 800 + + val documentIsOpen: BooleanProperty = new BooleanProperty() + documentIsOpen.value = false + + val joinDocumentUri: StringProperty = new StringProperty() + + def createNewDocumentButtonPressed(): Unit = { + require(model.isEmpty) + documentIsOpen.value = true + global.execute { () => + model = Some(TravelPlanModel(None)) + } + } + + def joinDocumentButtonPressed(): Unit = { + documentIsOpen.value = true + global.execute { () => + model = Some(TravelPlanModel(Some(joinDocumentUri.value))) + } + } +} diff --git a/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/TravelPlannerController.scala b/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/TravelPlanModel.scala similarity index 57% rename from Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/TravelPlannerController.scala rename to Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/TravelPlanModel.scala index a107f467e..9378379c3 100644 --- a/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/TravelPlannerController.scala +++ b/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/TravelPlanModel.scala @@ -7,33 +7,22 @@ import lofi_acl.sync.acl.monotonic.SyncWithMonotonicAcl import java.util.concurrent.atomic.AtomicReference -class TravelPlannerController private (isNewDocument: Boolean) { +class TravelPlanModel(joinedDocument: Option[String]) { private val privateId: PrivateIdentity = IdentityFactory.createNewIdentity + + private val crdt = AtomicReference[TravelPlan]() + private val sync: SyncWithMonotonicAcl[TravelPlan] = SyncWithMonotonicAcl[TravelPlan]( privateId, List.empty, DeltaMapWithPrefix.empty ) sync.start() + joinedDocument.foreach(sync.connect) - println(sync.connectionString) - - def connect(connectionString: String): Unit = { - sync.connect(connectionString) - } + def connectionString: Option[String] = Some(sync.connectionString) def shutdown(): Unit = { sync.stop() } - - private val crdt = AtomicReference[TravelPlan]() -} - -object TravelPlannerController { - def forNewDocument: TravelPlannerController = TravelPlannerController(true) - - def forExistingDocument(connectionString: String): TravelPlannerController = - val controller = TravelPlannerController(false) - controller.connect(connectionString) - controller } diff --git a/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/TravelPlanView.scala b/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/TravelPlanView.scala new file mode 100644 index 000000000..3c9933865 --- /dev/null +++ b/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/TravelPlanView.scala @@ -0,0 +1,5 @@ +package lofi_acl.example.monotonic_acl + +class TravelPlanView { + +} diff --git a/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/TravelPlannerApp.scala b/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/TravelPlannerApp.scala index e275b43b1..afc7701cf 100644 --- a/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/TravelPlannerApp.scala +++ b/Modules/Local-first Access Control/Example/src/main/scala/lofi_acl/example/monotonic_acl/TravelPlannerApp.scala @@ -1,50 +1,15 @@ package lofi_acl.example.monotonic_acl import scalafx.application.JFXApp3 -import scalafx.scene.Scene -import scalafx.scene.control.{Button, TextField} -import scalafx.scene.layout.VBox - -object TravelPlannerAppMonotonic extends TravelPlannerApp - -class TravelPlannerApp extends JFXApp3 { - var controller: Option[TravelPlannerController] = None +object TravelPlannerApp extends JFXApp3 { override def start(): Unit = { - val createNewDocumentButton = new Button { - text = "Create new travel plan" - onAction = ev => { - controller = Some(TravelPlannerController.forNewDocument) - } - } - - val remoteDocumentUriTextField = new TextField { - promptText = "user@host:port" - // hgrow = Priority.Always - } - - val joinDocumentButton = new Button { - text = "Join travel document" - onAction = ev => { - controller = Some(TravelPlannerController.forExistingDocument(remoteDocumentUriTextField.getText)) - } - } - stage = new JFXApp3.PrimaryStage { - title.value = s"App with replicaId: ???" - scene = new Scene { - content = new VBox { - children = Seq( - createNewDocumentButton, - remoteDocumentUriTextField, - joinDocumentButton - ) - } - } + title = s"Travel Planner" + scene = new MainScene() + resizable = true } } - override def stopApp(): Unit = { - controller.foreach(_.shutdown()) - } + override def stopApp(): Unit = {} }