Module: Wintoast::Payload

Defined in:
lib/wintoast/payload.rb

Overview

Wintoast::Payload — the ToastGeneric XML builder.

A pure function with no OS calls: it turns a title/body plus presentation kwargs into the exact UTF-8 XML string that Wintoast.toast hands to the WinRT LoadXml call. Exposed publicly so you can inspect "what would you send?" and as the unit-test seam for the escaping / control-char / audio-table rules.

Wintoast::Payload.build("Build done", "42 files", audio: :mail)
# => "<toast>...<binding template=\"ToastGeneric\">...</toast>"

It validates only the kwargs that affect the XML (attribution:, image:, hero:, circle:, audio:, duration:, scenario:). aumid:/tag:/group:/expires_* are WinRT properties, not part of the XML, and are NOT accepted here.

Class Method Summary collapse

Class Method Details

.build(title, body = nil, attribution: nil, image: nil, hero: nil, circle: false, audio: :default, duration: :short, scenario: nil) ⇒ Object

Build the ToastGeneric XML. Returns a fresh, unfrozen UTF-8 String.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/wintoast/payload.rb', line 45

def build(title, body = nil,
          attribution: nil,
          image:       nil,
          hero:        nil,
          circle:      false,
          audio:       :default,
          duration:    :short,
          scenario:    nil)
  title_text = scrub_required(title, "title")
  body_text  = body.nil?        ? nil : scrub_text(body, "body")
  attr_text  = attribution.nil? ? nil : scrub_text(attribution, "attribution")

  unless DURATIONS.include?(duration)
    raise ArgumentError, "wintoast: duration: must be :short or :long, got #{duration.inspect}"
  end
  unless scenario.nil? || SCENARIOS.key?(scenario)
    raise ArgumentError,
          "wintoast: scenario: must be nil, :alarm, :incoming_call, or :urgent, got #{scenario.inspect}"
  end

  image_src = validate_image(image, "image")
  hero_src  = validate_image(hero,  "hero")
  if circle && image_src.nil?
    raise ArgumentError, "wintoast: circle: true requires image:"
  end

  audio_xml = build_audio(audio)

  toast_attrs = +""
  toast_attrs << %( duration="long") if duration == :long
  toast_attrs << %( scenario="#{SCENARIOS[scenario]}") if scenario

  xml = +"<toast#{toast_attrs}>"
  xml << "<visual><binding template=\"ToastGeneric\">"
  xml << "<text>#{esc(title_text)}</text>"
  xml << "<text>#{esc(body_text)}</text>" if body_text
  xml << "<text placement=\"attribution\">#{esc(attr_text)}</text>" if attr_text
  if image_src
    crop = circle ? %( hint-crop="circle") : ""
    xml << %(<image placement="appLogoOverride"#{crop} src="#{esc(image_src)}"/>)
  end
  if hero_src
    xml << %(<image placement="hero" src="#{esc(hero_src)}"/>)
  end
  xml << "</binding></visual>"
  xml << audio_xml if audio_xml
  xml << "</toast>"
  xml
end