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 HistoricalCourseEditorState ToCourseEditorState(this CourseData courseData) { var selectedPropType = PropType.RingNormal; var propOrder = ImmutableList <PropId> .Empty; var props = ImmutableDictionary <PropId, EditorProp> .Empty; for (int i = 0; i < courseData.Props.Count; i++) { var prop = courseData.Props[i]; var editorProp = new EditorProp { Id = PropId.CreateRandomId(), PropType = prop.PropType, Transform = prop.Transform }; propOrder = propOrder.Add(editorProp.Id); props = props.Add(editorProp.Id, editorProp); selectedPropType = editorProp.PropType; } // Automatically select the first prop if possible //var selectedProp = propOrder.Count > 0 ? Maybe.Just(propOrder[0]) : Maybe.Nothing<PropId>(); var selectedProp = Maybe.Nothing <PropId>(); return(new HistoricalCourseEditorState(courseData.Id, selectedPropType, selectedProp, props, propOrder, false, false)); }
public static void CreateCourse(string coursesDirectory, CourseData courseData) { var tempFilePath = "~" + FileName(courseData) + ".temp." + Guid.NewGuid(); tempFilePath = Path.Combine(coursesDirectory, tempFilePath); Write2Disk(tempFilePath, courseData); var coursePath = Path.Combine(coursesDirectory, FileName(courseData)); File.Delete(coursePath); File.Move(tempFilePath, coursePath); }
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); }
public static void UpdateCourse(string coursesDirectory, CourseData courseData) { PermanentlyDeleteCourse(coursesDirectory, courseData.Id); CreateCourse(coursesDirectory, courseData); }
public static void Write2Disk(string courseFileName, CourseData courseData) { using (var writer = File.CreateText(courseFileName)) { CourseSerialization.Serializer.Serialize(writer, courseData); } }
public static string FileName(CourseData courseData) { return(FileName(courseData.Id, courseData.Name)); }