Module: Plushie::Effect

Defined in:
lib/plushie/effect.rb

Overview

Native platform effect requests.

Effects are asynchronous I/O operations handled by the renderer: file dialogs, clipboard access, notifications. Each method takes a symbol tag as its first argument and returns a Command. The tag flows through to the Effect event for clean pattern matching.

Only one effect per tag can be in flight at a time. Starting a new effect with a tag that already has a pending request discards the previous one.

Examples:

def update(model, event)
  case event
  in Event::Widget[type: :click, id: "open"]
    [model, Effect.file_open(:import, title: "Pick a file")]
  in Event::Effect[tag: :import, result: [:ok, result]]
    model.with(file: result["path"])
  in Event::Effect[tag: :import, result: :cancelled]
    model
  end
end

Constant Summary collapse

TIMEOUT_FILE =

Default timeout for file dialog effects (milliseconds).

120_000
TIMEOUT_CLIPBOARD =

Default timeout for clipboard effects (milliseconds).

5_000
TIMEOUT_NOTIFICATION =

Default timeout for notification effects (milliseconds).

5_000

Class Method Summary collapse

Class Method Details

.clipboard_clear(tag) ⇒ Command::Cmd

Clear the clipboard.

Parameters:

  • tag (Symbol)

Returns:



91
# File 'lib/plushie/effect.rb', line 91

def clipboard_clear(tag) = request(tag, :clipboard_clear)

.clipboard_read(tag) ⇒ Command::Cmd

Read clipboard text.

Parameters:

  • tag (Symbol)

Returns:



64
# File 'lib/plushie/effect.rb', line 64

def clipboard_read(tag) = request(tag, :clipboard_read)

.clipboard_read_html(tag) ⇒ Command::Cmd

Read HTML from clipboard.

Parameters:

  • tag (Symbol)

Returns:



75
# File 'lib/plushie/effect.rb', line 75

def clipboard_read_html(tag) = request(tag, :clipboard_read_html)

.clipboard_read_primary(tag) ⇒ Command::Cmd

Read primary clipboard (middle-click paste on Linux).

Parameters:

  • tag (Symbol)

Returns:



96
# File 'lib/plushie/effect.rb', line 96

def clipboard_read_primary(tag) = request(tag, :clipboard_read_primary)

.clipboard_write(tag, text) ⇒ Command::Cmd

Write text to clipboard.

Parameters:

  • tag (Symbol)
  • text (String)

Returns:



70
# File 'lib/plushie/effect.rb', line 70

def clipboard_write(tag, text) = request(tag, :clipboard_write, text: text)

.clipboard_write_html(tag, html, alt_text: nil) ⇒ Command::Cmd

Write HTML to clipboard.

Parameters:

  • tag (Symbol)
  • html (String)
  • alt_text (String, nil) (defaults to: nil)

    plain text fallback

Returns:



82
83
84
85
86
# File 'lib/plushie/effect.rb', line 82

def clipboard_write_html(tag, html, alt_text: nil)
  opts = {html: html}
  opts[:alt_text] = alt_text if alt_text
  request(tag, :clipboard_write_html, **opts)
end

.clipboard_write_primary(tag, text) ⇒ Command::Cmd

Write to primary clipboard.

Parameters:

  • tag (Symbol)
  • text (String)

Returns:



102
# File 'lib/plushie/effect.rb', line 102

def clipboard_write_primary(tag, text) = request(tag, :clipboard_write_primary, text: text)

.default_timeout(kind) ⇒ Integer

Returns the default timeout for the given effect kind.

Parameters:

  • kind (String, Symbol)

Returns:

  • (Integer)


140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/plushie/effect.rb', line 140

def default_timeout(kind)
  case kind.to_s
  when "file_open", "file_open_multiple", "file_save",
    "directory_select", "directory_select_multiple"
    TIMEOUT_FILE
  when "clipboard_read", "clipboard_write", "clipboard_read_html",
    "clipboard_write_html", "clipboard_clear",
    "clipboard_read_primary", "clipboard_write_primary"
    TIMEOUT_CLIPBOARD
  when "notification"
    TIMEOUT_NOTIFICATION
  else
    30_000
  end
end

.directory_select(tag, **opts) ⇒ Command::Cmd

Directory picker.

Parameters:

  • tag (Symbol)

Returns:



54
# File 'lib/plushie/effect.rb', line 54

def directory_select(tag, **opts) = request(tag, :directory_select, **opts)

.directory_select_multiple(tag, **opts) ⇒ Command::Cmd

Multi-directory picker.

Parameters:

  • tag (Symbol)

Returns:



59
# File 'lib/plushie/effect.rb', line 59

def directory_select_multiple(tag, **opts) = request(tag, :directory_select_multiple, **opts)

.file_open(tag, **opts) ⇒ Command::Cmd

Open-file dialog.

Parameters:

  • tag (Symbol)

    identifies this effect in the result event

Returns:



39
# File 'lib/plushie/effect.rb', line 39

def file_open(tag, **opts) = request(tag, :file_open, **opts)

.file_open_multiple(tag, **opts) ⇒ Command::Cmd

Multi-file open dialog.

Parameters:

  • tag (Symbol)

Returns:



44
# File 'lib/plushie/effect.rb', line 44

def file_open_multiple(tag, **opts) = request(tag, :file_open_multiple, **opts)

.file_save(tag, **opts) ⇒ Command::Cmd

Save-file dialog.

Parameters:

  • tag (Symbol)

Returns:



49
# File 'lib/plushie/effect.rb', line 49

def file_save(tag, **opts) = request(tag, :file_save, **opts)

.generate_idString

Returns unique wire correlation ID.

Returns:

  • (String)

    unique wire correlation ID



163
164
165
166
167
168
# File 'lib/plushie/effect.rb', line 163

def generate_id
  @counter_mutex.synchronize do
    @counter += 1
    "ef_#{@counter}"
  end
end

.notification(tag, title, body, **opts) ⇒ Command::Cmd

Show an OS notification.

On macOS, notifications may require the app to be bundled (.app) or have notification entitlements to display.

Parameters:

  • tag (Symbol)
  • title (String)
  • body (String)

Returns:



113
114
115
116
117
118
119
120
# File 'lib/plushie/effect.rb', line 113

def notification(tag, title, body, **opts)
  payload = {title: title, body: body}
  payload[:icon] = opts[:icon] if opts[:icon]
  payload[:timeout] = opts[:timeout] if opts[:timeout]
  payload[:urgency] = opts[:urgency].to_s if opts[:urgency]
  payload[:sound] = opts[:sound] if opts[:sound]
  request(tag, :notification, **payload)
end

.request(tag, kind, **opts) ⇒ Command::Cmd

Generic effect request.

Parameters:

  • tag (Symbol)

    identifies this effect in the result event

  • kind (Symbol)

    effect kind

  • opts (Hash)

    effect-specific parameters

Returns:



128
129
130
131
132
133
134
135
# File 'lib/plushie/effect.rb', line 128

def request(tag, kind, **opts)
  id = generate_id
  custom_timeout = opts.delete(:timeout)
  Command::Cmd.new(
    type: :effect,
    payload: {id: id, tag: tag, kind: kind.to_s, opts: opts, timeout: custom_timeout}
  )
end