| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- using Statum;
- using Invercargill;
- using Invercargill.DataStructures;
- namespace Example {
- // Typed slot models — GObject properties mapped to/from Properties via
- // GObjectMapping. ActionDto fields round-trip as nested JSON.
- public class CounterPrivate : Object {
- public int delta { get; set; }
- }
- public class CounterPublic : Object {
- public int value { get; set; }
- public Model.ActionDto bump { get; set; }
- }
- public class PagePublic : Object {
- public Model.ActionDto login { get; set; }
- }
- public class AuthPublic : Object {
- public string name { get; set; }
- public string role { get; set; }
- public Model.ActionDto logout { get; set; }
- public Model.ActionDto update_announcement { get; set; }
- }
- public class AuthPrivate : Object {
- public bool is_admin { get; set; }
- }
- /** Global broadcast model — a simple announcement string. */
- public class AnnouncementPublic : Object {
- public string text { get; set; }
- }
- /** Derived model — a short preview of the announcement, produced by the topic modifier. */
- public class AnnouncementPreview : Object {
- public string summary { get; set; }
- public int chars { get; set; }
- }
- /** Topic: loads the current announcement from the global slot when triggered. */
- public class AnnouncementTopic : Statum.Topic<AnnouncementPublic> {
- private StateService state_service = Inversion.inject<StateService>();
- public override async AnnouncementPublic load(string topic_key) throws GLib.Error {
- var slot = state_service.get_slot(StateService.GLOBAL_KEY_PREFIX + "announcement");
- var model = new AnnouncementPublic();
- if (slot != null && ((!)slot).current_state != null) {
- try {
- model = GObjectMapping.from_properties_typed<AnnouncementPublic>(
- typeof(AnnouncementPublic), ((!)slot).current_state.public_data);
- } catch {}
- }
- return model;
- }
- }
- /** Modifier: derives an AnnouncementPreview from the AnnouncementPublic payload. */
- public class AnnouncementPreviewModifier : Statum.StateModifier {
- public override Type state_type { get { return typeof(AnnouncementPreview); } }
- public override GLib.Object? derive(GLib.Object payload, GLib.Object? current, HeldStates held) {
- var announcement = (AnnouncementPublic) payload;
- var preview = new AnnouncementPreview();
- preview.chars = announcement.text.length;
- preview.summary = announcement.text.length > 40 ? announcement.text.substring(0, 40) + "…" : announcement.text;
- return preview;
- }
- }
- /**
- * Entrypoint for the home page: hydrates counter + page slots with typed
- * models, embedding action references as fields.
- */
- public class HomeEntrypoint : StatumEntrypoint {
- public override async DirectiveBuilder handle() throws GLib.Error {
- var bump_private = new CounterPrivate();
- bump_private.delta = 1;
- var bump_ref = action_registry.author_private<BumpCounterAction, CounterPrivate>(bump_private);
- var counter = new CounterPublic();
- counter.value = 0;
- counter.bump = bump_ref;
- var page = new PagePublic();
- page.login = action_registry.author<LoginAction>();
- // Create a derived "preview" slot and register a topic watcher so it
- // updates live when the announcement changes.
- var preview_model = new AnnouncementPreview();
- preview_model.summary = "";
- preview_model.chars = 0;
- var preview_slot = state_service.new_slot(Scope.PAGE, new State() {
- type_name = "preview",
- public_data = GObjectMapping.to_properties(preview_model),
- private_data = new PropertyDictionary()
- });
- topic_registry.watch("announcement:latest", preview_slot.id,
- typeof(AnnouncementPreview).name(), request.held);
- return directives()
- .set_global("announcement")
- .subscribe_global("announcement")
- .set_typed<CounterPublic>("counter", Scope.PAGE, counter)
- .set_typed<PagePublic>("page", Scope.PAGE, page)
- .set(preview_slot)
- .subscribe(preview_slot.id);
- }
- }
- /**
- * Entrypoint for the guarded dashboard page.
- */
- public class DashboardEntrypoint : StatumEntrypoint {
- public override async DirectiveBuilder handle() throws GLib.Error {
- return directives()
- .set_global("announcement")
- .notify("info", "Welcome to your dashboard");
- }
- }
- }
|