Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,20 @@ def get_base_path():
app = Flask("Beamer+",
static_folder=os.path.join(BASE_PATH, 'static'),
template_folder=BASE_PATH)
socketio = SocketIO(app, cors_allowed_origins='*', async_mode='threading')
# socketio allows different webpages in our app (viewer, index, etc) to share data
socketio = SocketIO(app,
cors_allowed_origins='*', # meaning of *: all webpages can communicate
async_mode='threading')

# Store active surveys and responses
surveys = {}
survey_responses = defaultdict(list)

# Store current presentation
UPLOAD_FOLDER = 'uploads'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
# exist_ok=True ensures that even if '/uploads' already exists,
# the program shouldn't crash

current_presentation = {
'file': None,
Expand Down Expand Up @@ -146,12 +151,28 @@ def upload_presentation():
'models': available_models
})

@app.route('/api/presentation/current')
# Getter for upload.zip:
@app.route('/api/presentation/current') # by default: methods=['GET']
def get_current_presentation():
if current_presentation['file'] and os.path.exists(current_presentation['file']):
return send_file(current_presentation['file'], as_attachment=True, download_name='presentation.zip')
return jsonify({'error': 'No presentation loaded'}), 404

# Getter for metadata about upload.zip
@app.route('/api/presentation/info') # by default: methods=['GET']
def get_presentation_info():
if current_presentation['file'] and os.path.exists(current_presentation['file']):
return jsonify({
'loaded': True,
'models': current_presentation.get('available_models', []),
'filename': os.path.basename(current_presentation['file'])
})

return jsonify({
'loaded': False
})


# Model endpoints
@app.route('/api/models')
def get_models():
Expand Down Expand Up @@ -384,4 +405,4 @@ def handle_screen_frame(data):
emit("screen_frame", data, room='viewer')

if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', port=5000, debug=True)
socketio.run(app, host='0.0.0.0', port=5000, debug=False)
7 changes: 4 additions & 3 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.0/jszip.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.min.js"></script>
<script>
pdfjsLib.GlobalWorkerOptions.workerSrc =
'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js';
pdfjsLib.GlobalWorkerOptions.workerSrc = 'https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.16.105/pdf.worker.min.js';
</script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
Expand Down Expand Up @@ -73,7 +72,9 @@
}, 2000);
});
</script>
<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/4.0.0/model-viewer.min.js"></script>

<!-- script for the 3D Model viewer: -->
<script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/4.0.0/model-viewer.min.js"></script>
<script type="module" src="/static/js/main.js"></script>
</body>
</html>
4 changes: 3 additions & 1 deletion static/css/button.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
background-color: #bbbbbb;
}

.btn:disabled {

.btn:disabled, .not-in-use {
/* .not-in-use applies to viewer-slide-navigator icons when switchToPresentation == false */
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
Expand Down
9 changes: 5 additions & 4 deletions static/css/canvas.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* Beamer+ Canvas and Display Styles */

#pdf-container,
#viewer-container {
#viewer-container,
#switch-presentation-container {
width: calc(100% - 75px);
height: calc(100vh - 60px);
position: relative;
Expand All @@ -13,13 +14,13 @@
background: #f0f0f0;
}

#pdf-container video {
#pdf-container video, #switch-presentation-container video {
position: absolute;
object-fit: contain;
pointer-events: auto;
}

#pdf-canvas {
#pdf-canvas, #viewer-pdf-canvas {
position: absolute;
z-index: 1;
background-color: #ffffff;
Expand All @@ -29,7 +30,7 @@
aspect-ratio: 4 / 3;
}

#pdf-canvas canvas {
#pdf-canvas canvas, #viewer-pdf-canvas canvas {
width: 100% !important;
height: 100% !important;
display: block;
Expand Down
4 changes: 2 additions & 2 deletions static/css/shared.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ input[type=file] {
}

/* Slide Navigator */
#slide-navigator {
#slide-navigator, #viewer-slide-navigator {
position: fixed;
left: 0;
top: 60px;
Expand All @@ -40,7 +40,7 @@ input[type=file] {
}

/* Hide scrollbar for Chrome, Safari and Opera */
#slide-navigator::-webkit-scrollbar {
#slide-navigator::-webkit-scrollbar, #viewer-slide-navigator::-webkit-scrollbar {
display: none;
}

Expand Down
36 changes: 36 additions & 0 deletions static/css/viewer-panel.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#viewer-panel {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10px;
background: #ccc;
color: white;
gap: 10px;
box-sizing: border-box;
flex-wrap: wrap;
position: relative;
position: relative;
z-index: 200;
border-bottom: 2px solid #666;
}

#viewer-left {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
flex: 0 1 auto;
}

#viewer-right {
display: flex;
align-items: center;
gap: 10px;
flex-wrap: wrap;
flex: 0 0 auto;
margin-left: auto;
}

.hidden {
display: none !important;
}
110 changes: 110 additions & 0 deletions static/css/viewer.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
@font-face {
font-family: "Computer Modern Sans";
src: url("https://mirrors.ctan.org/fonts/cm-unicode/fonts/otf/cmunss.otf");
font-display: swap;
}

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

html,
body {
width: 100%;
height: 100%;
overflow: hidden;
background: #fcfcfc;
font-family: "Computer Modern Sans", sans-serif;
}

/* Viewer container */
#viewer-container {
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
inset: 0;
z-index: 1;
background: #fcfcfc;
padding: 0;
}

#screen-display {
width: 100%;
height: 100%;
object-fit: contain;
display: none;
}

/* Waiting message */
#waiting-message {
text-align: center;
color: #666;
}

#waiting-message h2 {
font-size: 28px;
margin-bottom: 20px;
margin-top: 20px;
font-weight: 700;
color: #333;
}

#waiting-message p {
font-size: 16px;
color: #666;
}

/* Scribble animation matching Beamer+ modal style */
.viewer-squiggle {
width: 120px;
height: 40px;
display: block;
margin: 0 auto;
}

.viewer-squiggle path {
fill: none;
stroke: #666;
stroke-width: 3;
stroke-linecap: round;
stroke-linejoin: round;
stroke-dasharray: 150;
stroke-dashoffset: 150;
animation: draw-squiggle 1.6s ease-in-out infinite;
}

@keyframes draw-squiggle {
0% {
stroke-dashoffset: 150;
opacity: 0.6;
}
40% {
stroke-dashoffset: 0;
opacity: 1;
}
100% {
stroke-dashoffset: -150;
opacity: 0.6;
}
}

/* FPS counter in corner */
#stream-info {
position: fixed;
top: 20px;
right: 20px;
font-size: 14px;
font-weight: 600;
color: #333;
background: #eee;
padding: 6px 12px;
border-radius: 4px;
border: 1px solid #999;
opacity: 0.9;
display: none;
}
Loading