using System; using System.Collections.Generic; namespace ShrinkTutorial; [Serializable] public sealed class ShrinkTutorialStep { public string StepId = string.Empty; public string Title = string.Empty; public string Body = string.Empty; public string Target = string.Empty; public ShrinkTutorialTargetMode TargetMode; public ShrinkTutorialCompleteCondition CompleteCondition = ShrinkTutorialCompleteCondition.ClickTarget; public ShrinkTutorialDialogAnchor DialogAnchor = ShrinkTutorialDialogAnchor.Auto; public ShrinkTutorialMaskShape MaskShape = ShrinkTutorialMaskShape.Rect; public string CustomEventName = string.Empty; public bool BlockInputOutsideTarget = true; } [Serializable] public sealed class ShrinkTutorialData { public string TutorialId = string.Empty; public List Steps = new(); } public sealed class ShrinkTutorialRunner { private readonly IShrinkTutorialStorage _storage; private ShrinkTutorialProgress _progress; public ShrinkTutorialRunner(IShrinkTutorialStorage storage) { _storage = storage ?? throw new ArgumentNullException(nameof(storage)); _progress = storage.Load() ?? new ShrinkTutorialProgress(); } public ShrinkTutorialData Current { get; private set; } public int StepIndex { get; private set; } = -1; public ShrinkTutorialStep CurrentStep => Current != null && StepIndex >= 0 && StepIndex < Current.Steps.Count ? Current.Steps[StepIndex] : null; public event Action StepChanged; public event Action Completed; public bool Start(ShrinkTutorialData tutorial) { if (tutorial == null || tutorial.Steps.Count == 0 || _progress.completedTutorials.Contains(tutorial.TutorialId)) return false; Current = tutorial; StepIndex = 0; StepChanged?.Invoke(CurrentStep); return true; } public bool CompleteStep(string customEventName = null) { var step = CurrentStep; if (step == null) return false; if (step.CompleteCondition == ShrinkTutorialCompleteCondition.CustomEvent && !string.Equals(step.CustomEventName, customEventName, StringComparison.Ordinal)) return false; StepIndex++; if (StepIndex < Current.Steps.Count) { StepChanged?.Invoke(CurrentStep); return true; } _progress.completedTutorials.Add(Current.TutorialId); _storage.Save(_progress); var id = Current.TutorialId; Current = null; StepIndex = -1; Completed?.Invoke(id); return true; } public void Reset() { Current = null; StepIndex = -1; _storage.Reset(); _progress = new ShrinkTutorialProgress(); } }