diff --git a/app.py b/app.py index 3230861..8f7a82e 100644 --- a/app.py +++ b/app.py @@ -282,6 +282,32 @@ def get_refresh_seconds(): return val if val in (10, 20, 30) else 10 +def get_kiosk_cycle_seconds(): + """Return the kiosk slide cycle interval in seconds. 0 = static price list; 5+ cycles QR and pricing.""" + cfg = load_booth_settings() + try: + val = int(cfg.get('kiosk_cycle_seconds', 10)) + except (ValueError, TypeError): + val = 10 + if val == 0: + return 0 + return max(5, val) + + +def get_kiosk_mode(): + """Return 'cycle', 'qr', or 'prices' based on kiosk_cycle_seconds setting.""" + cfg = load_booth_settings() + try: + val = int(cfg.get('kiosk_cycle_seconds', 10)) + except (ValueError, TypeError): + val = 10 + if val == -1: + return 'qr' + if val == 0: + return 'prices' + return 'cycle' + + def get_hermes_api_key(): """ Return the effective Hermes API key. @@ -847,6 +873,49 @@ def admin_pricing(): return render_template('admin/pricing.html', fixed=fixed, customs=customs) +@app.route('/kiosk') +def kiosk(): + """ + Public kiosk display page for the booth. + Shows open/closed banner, pricing, and optionally cycles with a QR code. + Auto-refreshes so pricing updates are picked up quickly. + """ + cfg = load_booth_settings() + pricing = cfg.get('pricing', {}) + + fixed_keys = { + 'one_song': 'One Song', + 'both_songs': 'Both Songs', + 'wav_per_song': 'WAV files / song', + 'stems_per_song': 'STEM files / song' + } + price_items = [] + for key, label in fixed_keys.items(): + val = pricing.get(key, '').strip() + if val: + price_items.append({'label': label, 'price': val}) + for i in range(1, 6): + entry = pricing.get(f'custom_{i}') + if isinstance(entry, dict): + name = entry.get('name', '').strip() + price = entry.get('price', '').strip() + if name and price: + price_items.append({'label': name, 'price': price}) + + cycle_seconds = get_kiosk_cycle_seconds() + mode = get_kiosk_mode() + booth_open = get_booth_open() + + return render_template( + 'kiosk.html', + booth_open=booth_open, + price_items=price_items, + cycle_seconds=cycle_seconds, + mode=mode, + refresh_seconds=30 + ) + + @app.route('/admin/request/', methods=['GET', 'POST']) def admin_request(rid): """ @@ -1248,6 +1317,28 @@ def admin_settings(): flash(f'Dashboard auto-refresh set to {val} seconds.', 'success') return redirect(url_for('admin_settings')) + elif action == 'save_kiosk_cycle': + # Update kiosk slide cycle interval. Special values: + # -1 = show QR only, 0 = show pricing only, 5+ = cycle every N seconds. + raw = request.form.get('kiosk_cycle_seconds', '10').strip() + try: + val = int(raw) + except ValueError: + val = 10 + if val not in (-1, 0) and val < 5: + val = 5 + cfg = load_booth_settings() + cfg['kiosk_cycle_seconds'] = val + save_booth_settings(cfg) + if val == -1: + label = 'QR code only' + elif val == 0: + label = 'pricing only' + else: + label = f'cycle every {val} seconds' + flash(f'Kiosk mode set to {label}.', 'success') + return redirect(url_for('admin_settings')) + elif action == 'save_booth_open': # Toggle whether the public request form is accepting submissions. cfg = load_booth_settings() @@ -1327,6 +1418,7 @@ def admin_settings(): upload_path=str(upload_root), current_max_revisions=current_max_revisions, current_refresh_seconds=current_refresh_seconds, + current_kiosk_cycle_seconds=get_kiosk_cycle_seconds(), booth_open=booth_open, email_form=email_form, metadata={ diff --git a/static/qr-code.png b/static/qr-code.png new file mode 100755 index 0000000..75bca74 Binary files /dev/null and b/static/qr-code.png differ diff --git a/templates/admin/dashboard.html b/templates/admin/dashboard.html index d3624f0..398a360 100644 --- a/templates/admin/dashboard.html +++ b/templates/admin/dashboard.html @@ -110,8 +110,9 @@
- +
+ Kiosk Pricing Sales Settings diff --git a/templates/admin/settings.html b/templates/admin/settings.html index 7e64c87..297737b 100644 --- a/templates/admin/settings.html +++ b/templates/admin/settings.html @@ -269,6 +269,19 @@
+ +
+

Kiosk Display Mode

+

Set how the public /kiosk page cycles. Use -1 for QR only, 0 for pricing only, or 5+ seconds to cycle between them.

+
+ + + +

Examples: -1 = QR only, 0 = pricing only, 10 = swap every 10 seconds.

+ +
+
+

Hermes API Key

diff --git a/templates/kiosk.html b/templates/kiosk.html new file mode 100644 index 0000000..52e7389 --- /dev/null +++ b/templates/kiosk.html @@ -0,0 +1,244 @@ + + + + + + Trollgorithm Booth โ€” Kiosk + {% if refresh_seconds and refresh_seconds > 0 %} + + {% endif %} + + + +
+
+ {% if booth_open %} + +
Booth is Open โœ…
+ {% else %} + +
Booth is Closed โŒ
+ {% endif %} +
+ +
+ {% if mode == 'qr' %} +
+

Scan to Order

+ Scan to order +

Point your camera at the code to start your request.

+
+ {% elif mode == 'prices' %} +
+
+

Pricing

+ {% if price_items %} +
    + {% for item in price_items %} +
  • + {{ item.label }} + {{ item.price }} +
  • + {% endfor %} +
+ {% else %} +

Pricing coming soon. Ask the booth operator!

+ {% endif %} +
+
+ {% else %} +
+

Scan to Order

+ Scan to order +

Point your camera at the code to start your request.

+
+ + {% endif %} +
+ + {% if mode == 'cycle' %} + + + {% endif %} + + +
+ +