Skip to content

Instantly share code, notes, and snippets.

@programmation
Forked from Clancey/StatefulSample.cs
Last active August 5, 2020 03:51
Show Gist options
  • Save programmation/4ec4693070732269908df1fca3734a67 to your computer and use it in GitHub Desktop.
Save programmation/4ec4693070732269908df1fca3734a67 to your computer and use it in GitHub Desktop.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Messaging
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
}
}
public abstract record Model { }
public abstract record Message { }
public abstract class View { }
public abstract class StatefulView<TMessage, TModel>
where TMessage : Message
where TModel : Model
{
public TModel State { get; private set; }
public StatefulView(TModel initial)
{
State = initial;
}
public virtual TModel Update(Message message, TModel model)
=> model;
public virtual void Dispatch(Message message)
{
State = Update(message, State);
}
public abstract View View(TModel model);
}
public record SampleModel : Model
{
public static SampleModel Initial()
=> new SampleModel { Step = 1 };
public int Count { get; set; }
public int Step { get; set; }
public bool IsTimerEnabled { get; set; }
}
public record Increment : Message { }
public record Decrement : Message { }
public record Reset : Message { }
public record SetStep : Message
{
public int Step { get; }
public SetStep(int step) { Step = step; }
}
public record ToggleTimer : Message
{
public bool IsTimerEnabled { get; }
public ToggleTimer(bool isTimerEnabled) { IsTimerEnabled = isTimerEnabled; }
}
public record TimedTick : Message { }
public class SampleStatefulView :
StatefulView<Message, SampleModel>
{
public SampleStatefulView(SampleModel initial)
: base(initial)
{
}
public override SampleModel Update(Message message, SampleModel model)
{
var newModel = message switch
{
Increment => model with { Count = model.Count + model.Step },
Decrement => model with { Count = model.Count - model.Step },
Reset => SampleModel.Initial(),
SetStep s => model with { Step = s.Step },
ToggleTimer t => HandleToggleTimer(t, model),
TimedTick => HandleTimerTick(model),
_ => model
};
return newModel;
}
private SampleModel HandleToggleTimer(ToggleTimer t, SampleModel model)
{
var newModel = model with { IsTimerEnabled = t.IsTimerEnabled };
if (newModel.IsTimerEnabled)
TickTimer();
return newModel;
}
private SampleModel HandleTimerTick(SampleModel model)
{
var newModel = model.IsTimerEnabled
? model with { Count = model.Count + model.Step }
: model;
if (newModel.IsTimerEnabled)
TickTimer();
return newModel;
}
private async void TickTimer()
{
await Task.Delay(200);
Dispatch(new TimedTick());
}
public override View View(SampleModel model)
=> new VStack
{
new Text($"{model.Count}"),
new Button("Increment", DispatchIncrement),
new Button("Decrement", DispatchDecrement),
new HStack
{
new Text("Timer"),
new Toggle(model.IsTimerEnabled, DispatchToggleTimer)
},
new Slider(model.Step, 10, DispatchSetStep),
new Text($"Step Size: {model.Step}"),
new Button("Reset", DispatchReset)
};
private void DispatchIncrement() => Dispatch(new Increment());
private void DispatchDecrement() => Dispatch(new Decrement());
private void DispatchToggleTimer(bool isEnabled) => Dispatch(new ToggleTimer(isEnabled));
private void DispatchSetStep(int step) => Dispatch(new SetStep(step));
private void DispatchReset() => Dispatch(new Reset());
}
// Demo View classes
public class HStack : View, IEnumerable<View>
{
public IEnumerator<View> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
public void Add(View view) { }
}
public class VStack : View, IEnumerable<View>
{
public IEnumerator<View> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
public void Add(View view) { }
}
public class Text : View
{
public Text(string text) { }
}
public class Toggle : View
{
public Toggle(bool isEnabled, Action<bool> trigger) { }
}
public class Button : View
{
public Button(string text, Action trigger) { }
}
public class Slider : View
{
public Slider(int step, int through, Action<int> onEditingChanged) { }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment