public static IConnectableObservable <CourseSelectorState> Create(CourseSelectorActions actions, IObservable <IList <CourseData> > courseUpdates, IObservable <bool> isCourseEditorOpen) { var commands = actions.SelectCourse.Select(StoreAction.Create <string>("selectCourse")) .Merge(actions.DeselectCourse.Select(StoreAction.Create <Unit>("deselectCourse"))); // Only route commands when the course editor is open var filteredCommands = isCourseEditorOpen .Select(isOpen => isOpen ? commands : Observable.Empty <StoreAction <object> >()) .Switch() .StartWith(new StoreAction <object>("deselectCourse", Unit.Default)); return(courseUpdates .CombineLatest(filteredCommands, (courses, command) => { Maybe <string> selectedCourse = Maybe.Nothing <string>(); if (command.Id.Equals("selectCourse")) { var selectedCourseId = (string)command.Arguments; selectedCourse = courses .Find(c => c.Id.Equals(selectedCourseId)) .Select(c => c.Id); } return new CourseSelectorState( availableCourses: courses, selectedCourse: selectedCourse, // TODO Enable delete isUndoDeleteCoursePossible: false); }) .Replay(1)); }
public static IDisposable CourseUpdater(CourseStorageActions actions, string coursesDirectory) { var commands = actions.CreateCourse.Select(StoreAction.Create <Unit>("createCourse")) .Merge(actions.UpdateCourse.Select(StoreAction.Create <CourseData>("updateCourse"))) .Merge(actions.DeleteCourse.Select(StoreAction.Create <string>("deleteCourse"))) .Merge(actions.UndoDeleteCourse.Select(StoreAction.Create <Unit>("undoDeleteCourse"))); return(commands .Subscribe(command => { if (command.Id.Equals("createCourse")) { var newCourse = CourseData.CreateNew(); CreateCourse(coursesDirectory, newCourse); } else if (command.Id.Equals("updateCourse")) { var updatedCourse = (CourseData)command.Arguments; UpdateCourse(coursesDirectory, updatedCourse); } else if (command.Id.Equals("deleteCourse")) { var deletedCourseId = (string)command.Arguments; DeleteCourse(coursesDirectory, deletedCourseId); } else if (command.Id.Equals("undoDeleteCourse")) { var deletedCourseId = (string)command.Arguments; UndoDeleteCourse(coursesDirectory, deletedCourseId); } })); }
public static IObservable <CourseEditorState> Create(CourseEditorActions actions, CourseData courseData, Ref <ImmutableTransform> cameraTransform) { var commands = actions.CreateProp.Select(StoreAction.Create <Unit>("createProp")) .Merge(actions.CreatePropOnLocation.Select(StoreAction.Create <ImmutableTransform>("createPropOnLocation"))) .Merge(actions.DeleteProp.Select(StoreAction.Create <PropId>("deleteProp"))) .Merge(actions.DeleteSelectedProp.Select(StoreAction.Create <Unit>("deleteSelectedProp"))) .Merge(actions.UpdateProp.Select(StoreAction.Create <Tuple <PropId, ImmutableTransform> >("updateProp"))) .Merge(actions.HighlightProp.Select(StoreAction.Create <Maybe <PropId> >("highlightProp"))) .Merge(actions.SelectProp.Select(StoreAction.Create <Maybe <PropId> >("selectProp"))) .Merge(actions.SelectPropType.Select(StoreAction.Create <PropType>("selectPropType"))) .Merge(actions.ReorderProps.Select(StoreAction.Create <IImmutableList <PropId> >("reorderProps"))) .Merge(actions.Undo.Select(StoreAction.Create <Unit>("undo"))) .Merge(actions.Redo.Select(StoreAction.Create <Unit>("redo"))); var initialHistoricalState = courseData.ToCourseEditorState(); var updatesWithHistory = commands .Scan(new AppState <HistoricalCourseEditorState>(initialHistoricalState), (currentAppState, command) => { var currentState = currentAppState.CurrentState; AppState <HistoricalCourseEditorState> newAppState = currentAppState; if (command.Id.Equals("createProp")) { var propTransform = cameraTransform.Deref().TranslateLocally(new Vector3(0, 0, 30)); newAppState = History.AddNewState(currentAppState, currentState.AddProp(propTransform)); } else if (command.Id.Equals("createPropOnLocation")) { newAppState = History.AddNewState(currentAppState, currentState.AddProp((ImmutableTransform)command.Arguments)); } else if (command.Id.Equals("updateProp")) { var args = (Tuple <PropId, ImmutableTransform>)command.Arguments; var prop = currentState.Props[args._1]; var isTransformChanged = !prop.Transform.Equals(args._2); if (isTransformChanged) { var updatedProp = prop.UpdateTransform(args._2); newAppState = History.AddNewState(currentAppState, currentState.UpdateProp(updatedProp)); } else { newAppState = currentAppState; } } else if (command.Id.Equals("deleteProp")) { var propId = (PropId)command.Arguments; if (currentState.PropOrder.Contains(propId)) { newAppState = History.AddNewState(currentAppState, currentState.DeleteProp(propId)); } } else if (command.Id.Equals("deleteSelectedProp")) { if (currentState.SelectedProp.IsJust) { newAppState = History.AddNewState(currentAppState, currentState.DeleteProp(currentState.SelectedProp.Value)); } } else if (command.Id.Equals("selectProp")) { var selectedPropId = (Maybe <PropId>)command.Arguments; if (selectedPropId.IsNothing || (selectedPropId.IsJust && currentState.Props.ContainsKey(selectedPropId.Value))) { newAppState = History.AddNewState(currentAppState, currentState.SelectProp(selectedPropId)); } } else if (command.Id.Equals("selectPropType")) { newAppState = History.AddNewState(currentAppState, currentState.SelectPropType((PropType)command.Arguments)); } else if (command.Id.Equals("reorderProps")) { newAppState = History.AddNewState(currentAppState, currentState.UpdatePropOrder((IImmutableList <PropId>)command.Arguments)); } else if (command.Id.Equals("undo")) { newAppState = History.Undo(currentAppState); } else if (command.Id.Equals("redo")) { newAppState = History.Redo(currentAppState); } else { newAppState = currentAppState; } return(newAppState); }) .Select(appState => { return(appState.CurrentState.UpdateUndoRedoAvailability( !appState.UndoStack.IsEmpty, !appState.RedoStack.IsEmpty)); }) .StartWith(initialHistoricalState) .Publish(); var initialTransientState = new TransientCourseEditorState(courseData.Name, Maybe.Nothing <PropId>(), TransformTool.Move); var transientUpdates = actions.HighlightProp.Select(StoreAction.Create <Maybe <PropId> >("highlightProp")) .Merge(actions.SelectTransformTool.Select(StoreAction.Create <TransformTool>("selectTransformTool"))) .Merge(actions.UpdateName.Select(StoreAction.Create <string>("updateName"))) .Scan(initialTransientState, (state, command) => { if (command.Id.Equals("highlightProp")) { return(state.HighlightProp((Maybe <PropId>)command.Arguments)); } else if (command.Id.Equals("selectTransformTool")) { // TODO Prevent transform tool selection when no prop is selected return(state.SelectTransformTool((TransformTool)command.Arguments)); } else if (command.Id.Equals("updateName")) { return(state.UpdateName((string)command.Arguments)); } return(state); }) .DistinctUntilChanged() .StartWith(initialTransientState) .CombineLatest(updatesWithHistory, (transientState, histState) => { // Check if the highlighted prop still exists var highlightedProp = transientState.HighlightedProp; var isHighlightedItemDeleted = highlightedProp.IsJust && !histState.Props.ContainsKey(highlightedProp.Value); if (isHighlightedItemDeleted) { return(transientState.HighlightProp(Maybe.Nothing <PropId>())); } return(transientState); }); var updates = updatesWithHistory.CombineLatest( transientUpdates, (histState, transientState) => new CourseEditorState(histState, transientState)) .DistinctUntilChanged() .Replay(1); updates.Connect(); updatesWithHistory.Connect(); return(updates); }