Skip to content

Commit

Permalink
Merge pull request binford2k#99 from binford2k/features/audience_feed…
Browse files Browse the repository at this point in the history
…back

Add audience interaction. Bumps version to 0.9.6
  • Loading branch information
Carthik Sharma committed Nov 13, 2013
2 parents f4da220 + 3cec58d commit ae0f14b
Show file tree
Hide file tree
Showing 22 changed files with 608 additions and 78 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
0.9.6
Ports client communication to websockets
Adds audience interaction
Pace feedback, slower/faster
Ask a question
Provide slide feedback
7 changes: 4 additions & 3 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@ Showoff's capabilities include:
* execute Javascript, Coffeescript or Ruby live and display results
* show a pre-show slideshow while you wait to start
* let audience members download slides, code samples or other supplementary material
* show a timer - elapsed / remaining
* show synchronized, hidden notes on another browser (like an iphone)

* Live audience tools:
* audience can pull up the presentation on their own browsers
* call up a menu of sections/slides at any time to jump around
* independent navigation so that audience members can go back / catch up as you talk
* allow viewers to set their view of the presentation to track the presenter's
* allow the audience to provide pace feedback and ask questions of the presenter
* allow the audience to provide contend feedback on the material

* Content creation and distribution functionality:
* generate supplemental material based on slide tags
Expand Down Expand Up @@ -101,10 +105,7 @@ presentation to Heroku or GitHub pages for archiving super easily.

Potential future capabilities might include:

* show a timer - elapsed / remaining
* perform simple animations of images moving between keyframes
* show synchronized, hidden notes on another browser (like an iphone)
* show audience questions / comments (twitter or direct)
* let audience members vote on sections (?)
* broadcast itself on Bonjour
* let you write on the slide with your mouse, madden-style via canvas
Expand Down
1 change: 1 addition & 0 deletions documentation/INSTALLATION.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Showoff is tested with Ruby 1.8.7, 1.9.3, and 2.0. It should install cleanly on
* Nokogiri
* json
* GLI
* sinatra-websocket
* PDFKit (optional, for generating PDF of presentation)
* Modern web browser to present or view slides
* Tested with Safari and Chrome, and to a lesser extent Firefox and Opera.
Expand Down
90 changes: 90 additions & 0 deletions documentation/INTERACTION.rdoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
= Audience Interaction

Showoff has a number of features for interacting with your audience. These
features work with all modern browsers, even with Internet Explorer from 2+
years ago!

== Viewer Functionality

There are several ways that the audience can interact with you and the presentation.
If there is a connection problem making this interaction unusable, the controls will
be disabled and a disconnected icon will appear in the lower left.

=== Presentation Control

[Navigation]
Pressing the left and right arrow keys, or the spacebar will cause the
presentation to change slides.

[Follow Mode]
Pressing +g+ will switch the viewer's presentation into follow mode. This
means that each time the presenter switches slides, the viewer's presentation
will follow along and switch to the same slide.

=== Presentation Feedback

The viewer will see a vertical grippy handle along the left side of the window.
If they move their mouse pointer over this handle, the <em>Feedback Panel</em> will
appear, exposing several control widgets.

To enable this functionality, please set the key <tt>"feedback": true</tt> in your
<tt>showoff.json</tt> files.

==== Live Interaction

[Provide Pace Feedback]
The viewer will have two buttons to click, <em>Slow Down</em> and <em>Speed Up</em>.
Each time a button is clicked, a message is sent to the presenter to help them
adjust their delivery pace appropriately.

[Ask a Question]
If the audience is large, the viewer is remote, or just doesn't want to ask in
front of peers, a question can be typed into this box and will appear in the
presenter's display control panel.

==== Material Feedback

[Provide Slide Feedback]
The viewer can rate a slide, from awful to awesome, and provide a bit of free text
explaining what could be made better on any given slide. The feedback and the current
slide name are recorded on the presenter's machine for later analysis.

== Presenter Functionality

The presentation control panel provides many tools for interacting with your audience.
They are summarized here. This information exists in greater detail in the USAGE document.

If there is a connection problem making interaction with your audience unusable, a
disconnected icon will appear in the top right of the presentation preview.

[Pace Feedback Gauge]
When the audience provides pace feedback for you, it will appear on this gauge. You should
aim to keep the gauge near the center. The left side indicates that you are moving too
slowly and the right side is too fast. The feedback messages decay over time and will
expire in about five minutes--meaning that the gauge will move back towards the center.

[Update Follower]
Allow viewers in <em>Follow Mode</em> to track your progress.

[Enable Remote]
Allow remote windows, including mobile devices, to control the presentation by
opening the presenter view.

[Audience Questions]
When an audience member uses the anonymous <em>Ask Question</em> feature, it will appear in this list.
The questions are listed in reverse order, with the newest at the top.

== Log Files

[<tt>viewstats.json</tt>]
Each time Showoff starts, it truncates and creates a new statistics log file. This file
records time that audience members spent looking at any one given slide. Only time that
is greater than one second is recorded, and only when the viewer is not in <em>follow mode</em>.

[<tt>feedback.json</tt>]
This log file is appended to each time an audience member has feedback for the material.
It should be reviewed on a regular basis--or better, consumed by an automatic process--for
important information on whether your material is having the desired impact on your audience.

This file contains a rating and a free text feedback field. It is keyed by the slide name, so
you can easily collate information grouped by slide name.
30 changes: 23 additions & 7 deletions documentation/USAGE.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,23 @@ tools that you should be familiar with.
Loads up all slides as a single monolithic page. Useful for printing or when an
ancient browser is used.

=== Slideshow Tree
=== Presenter Tools

On the left side of the browser window is a tree like view of the presentation. Each subsection is
displayed at the top level. Click on any of these subsections and it will expand to list all the
slides in that section, or collapse again. Click on any slide name and the presentation will
immediately jump to that slide.
[Countdown Timer]
This is just a simple countdown timer. Enter the time allotted to your presentation
and it will begin counting down for you, changing color as it approaches zero.

[Pace Feedback Gauge]
When the audience provides pace feedback for you, it will appear on this gauge. You should
aim to keep the gauge near the center. The left side indicates that you are moving too
slowly and the right side is too fast. The feedback messages decay over time and will
expire in about five minutes--meaning that the gauge will move back towards the center.

[Slideshow Tree]
On the left side of the browser window is a tree like view of the presentation. Each subsection is
displayed at the top level. Click on any of these subsections and it will expand to list all the
slides in that section, or collapse again. Click on any slide name and the presentation will
immediately jump to that slide.

=== Presentation Preview

Expand All @@ -127,9 +138,14 @@ and scale the contents as closely as possible. Several tools are attached to the
[Zoom]
Zoom in and out of the preview.

=== Presenter Notes
=== Presenter Information

[Audience Questions]
When an audience member uses the anonymous <em>Ask Question</em> feature, it will appear in this list.
The questions are listed in reverse order, with the newest at the top.

Just displays all presenter nodes, including any markup, syntax highlighting, etc.
[Notes]
Just displays all presenter nodes, including any markup, syntax highlighting, etc.

== Hotkeys

Expand Down
112 changes: 74 additions & 38 deletions lib/showoff.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class ShowOff < Sinatra::Application

set :server, 'thin'
set :sockets, []
set :presenters, []

set :verbose, false
set :pres_dir, '.'
Expand Down Expand Up @@ -565,11 +566,14 @@ def index(static=false)

@asset_path = "./"
end

# Check to see if the presentation has enabled feedback
@feedback = settings.showoff_config['feedback']
erb :index
end

def presenter
@issues = settings.showoff_config['issues']
@issues = settings.showoff_config['issues']
@@cookie ||= guid()
response.set_cookie('presenter', @@cookie)
erb :presenter
Expand Down Expand Up @@ -870,52 +874,83 @@ def valid_cookie
@logger.warn "Open sockets: #{settings.sockets.size}"
end
ws.onmessage do |data|
control = JSON.parse(data)
begin
control = JSON.parse(data)

@logger.warn "#{control.inspect}"

case control['message']
when 'update'
# websockets don't use the same auth standards
# we use a session cookie to identify the presenter
if valid_cookie()
slide = control['slide'].to_i

# check to see if we need to enable a download link
if @@downloads.has_key?(slide)
@logger.debug "Enabling file download for slide #{slide}"
@@downloads[slide][0] = true
end

# update the current slide pointer
@logger.debug "Updated current slide to #{slide}"
@@current = slide

# schedule a notification for all clients
EM.next_tick { settings.sockets.each{|s| s.send({ 'current' => @@current }.to_json) } }
end

@logger.info "#{control.inspect}"
when 'register'
# save a list of presenters
if valid_cookie()
remote = request.env['REMOTE_HOST'] || request.env['REMOTE_ADDR']
settings.presenters << ws
@logger.warn "Registered new presenter: #{remote}"
end

case control['message']
when 'update'
# websockets don't use the same auth standards
# we use a session cookie to identify the presenter
if valid_cookie()
slide = control['slide'].to_i
when 'track'
remote = request.env['REMOTE_HOST'] || request.env['REMOTE_ADDR']
slide = control['slide']
time = control['time'].to_f

# check to see if we need to enable a download link
if @@downloads.has_key?(slide)
@logger.debug "Enabling file download for slide #{slide}"
@@downloads[slide][0] = true
end
@logger.debug "Logged #{time} on slide #{slide} for #{remote}"

# update the current slide pointer
@logger.debug "Updated current slide to #{slide}"
@@current = slide
# a bucket for this slide
@@counter[slide] ||= Hash.new
# a counter for this viewer
@@counter[slide][remote] ||= 0
# and add the elapsed time
@@counter[slide][remote] += time

# schedule a notification for all clients
EM.next_tick { settings.sockets.each{|s| s.send({ 'current' => @@current }.to_json) } }
end
when 'position'
ws.send( { 'current' => @@current }.to_json ) unless @@cookie.nil?

when 'track'
remote = request.env['REMOTE_HOST'] || request.env['REMOTE_ADDR']
slide = control['slide'].to_i
time = control['time'].to_f
when 'pace', 'question'
# just forward to the presenter(s)
EM.next_tick { settings.presenters.each{|s| s.send(data) } }

@logger.debug "Logged #{time} on slide #{slide} for #{remote}"
when 'feedback'
slide = control['slide']
rating = control['rating']
feedback = control['feedback']

# a bucket for this slide
@@counter[slide] ||= Hash.new
# a counter for this viewer
@@counter[slide][remote] ||= 0
# and add the elapsed time
@@counter[slide][remote] += time
filename = 'feedback.json'
log = JSON.parse(File.read(filename)) if File.file?(filename)
log ||= Hash.new

when 'position'
ws.send( { 'current' => @@current }.to_json )
log[slide] ||= Array.new
log[slide] << { :rating => rating, :feedback => feedback }

else
@logger.debug "Unknown message <#{control['message']}> received."
end
File.write(filename, log.to_json)

else
@logger.warn "Unknown message <#{control['message']}> received."
@logger.warn control.inspect
end

rescue Exception => e
@logger.warn "Messaging error: #{e}"
end
end
ws.onclose do
@logger.warn("websocket closed")
Expand Down Expand Up @@ -968,8 +1003,9 @@ def valid_cookie

at_exit do
if defined?(@@counter)
viewstats = File.new("viewstats.json", "w")
viewstats.write @@counter.to_json
File.open("viewstats.json", "w") do |f|
f.write @@counter.to_json
end
end
end
end
2 changes: 1 addition & 1 deletion lib/showoff/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# No namespace here since ShowOff is a class and I'd have to inherit from
# Sinatra::Application (which we don't want to load here)
SHOWOFF_VERSION = '0.9.5.1'
SHOWOFF_VERSION = '0.9.6'
Binary file added public/css/disconnected-large.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/css/disconnected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/css/fast.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/css/grippy-close.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/css/grippy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/css/pace.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/css/paceMarker.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit ae0f14b

Please sign in to comment.