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
46 changes: 23 additions & 23 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def login():
login_user(user)
return redirect(url_for('dashboard'))

return render_template('login.html', error='Invalid credentials')
return render_template('login.html', error=_('Invalid credentials'))

return render_template('login.html')

Expand Down Expand Up @@ -239,17 +239,17 @@ def refresh_token():
def add_memory(connection_id):
connection = Connection.get_by_id(connection_id)
if not connection or not connection.involves_user(current_user.id):
return jsonify({'success': False, 'error': 'Connection not found'}), 404
return jsonify({'success': False, 'error': _('Connection not found')}), 404

data = request.get_json(silent=True) or {}
memory_text = (data.get('memory_text') or '').strip()
memory_date = (data.get('memory_date') or '').strip()

if not memory_text or len(memory_text) > 200:
return jsonify({'success': False, 'error': 'Invalid memory text'}), 400
return jsonify({'success': False, 'error': _('Invalid memory text')}), 400

if not validate_memory_date(memory_date):
return jsonify({'success': False, 'error': 'Invalid memory date'}), 400
return jsonify({'success': False, 'error': _('Invalid memory date')}), 400

memory_id = ConnectionMemory.create(connection_id, current_user.id, memory_text, memory_date)
return jsonify({'success': True, 'memory_id': memory_id})
Expand All @@ -260,10 +260,10 @@ def add_memory(connection_id):
def approve_memory(connection_id, memory_id):
connection = Connection.get_by_id(connection_id)
if not connection or not connection.involves_user(current_user.id):
return jsonify({'success': False, 'error': 'Connection not found'}), 404
return jsonify({'success': False, 'error': _('Connection not found')}), 404

if not ConnectionMemory.approve(connection_id, memory_id, current_user.id):
return jsonify({'success': False, 'error': 'Unable to approve memory'}), 400
return jsonify({'success': False, 'error': _('Unable to approve memory')}), 400

return jsonify({'success': True})

Expand Down Expand Up @@ -293,7 +293,7 @@ def connection_page(connection_id):
connection = Connection.get_by_id(connection_id)

if not connection or not connection.involves_user(current_user.id):
return render_template('error.html', message='Connection not found')
return render_template('error.html', message=_('Connection not found'))

other_user = connection.get_other_user(current_user.id)
return render_template('connection.html', connection=connection, other_user=other_user)
Expand All @@ -304,7 +304,7 @@ def clipboard(connection_id):
connection = Connection.get_by_id(connection_id)

if not connection or not connection.involves_user(current_user.id):
return render_template('error.html', message='Connection not found')
return render_template('error.html', message=_('Connection not found'))

clipboard_data = SharedClipboard.get_by_connection(connection_id)
other_user = connection.get_other_user(current_user.id)
Expand All @@ -319,7 +319,7 @@ def clipboard(connection_id):
def memories(connection_id):
connection = Connection.get_by_id(connection_id)
if not connection or not connection.involves_user(current_user.id):
return render_template('error.html', message='Connection not found')
return render_template('error.html', message=_('Connection not found'))

other_user = connection.get_other_user(current_user.id)
memories = ConnectionMemory.get_for_connection(connection_id)
Expand All @@ -334,7 +334,7 @@ def drawing_game(connection_id):
connection = Connection.get_by_id(connection_id)

if not connection or not connection.involves_user(current_user.id):
return render_template('error.html', message='Connection not found')
return render_template('error.html', message=_('Connection not found'))

game = DrawingGame.get_by_connection(connection_id)
other_user = connection.get_other_user(current_user.id)
Expand All @@ -350,7 +350,7 @@ def chat(connection_id):
connection = Connection.get_by_id(connection_id)

if not connection or not connection.involves_user(current_user.id):
return render_template('error.html', message='Connection not found')
return render_template('error.html', message=_('Connection not found'))

other_user = connection.get_other_user(current_user.id)
messages = ChatMessage.get_messages(connection_id)
Expand All @@ -376,7 +376,7 @@ def admin_login():
if secrets.compare_digest(password, admin_password):
session['is_admin'] = True
return redirect(url_for('admin_panel'))
return render_template('admin_login.html', error='Invalid password')
return render_template('admin_login.html', error=_('Invalid password'))

return render_template('admin_login.html')

Expand Down Expand Up @@ -615,23 +615,23 @@ def handle_drawing_start(data):

# Validate access
if not validate_connection_access(connection_id, drawer_id):
return {'success': False, 'error': 'Access denied'}
return {'success': False, 'error': _('Access denied')}

# Validate answer (limit to 50 characters)
answer = answer.strip()[:50]
if not answer:
return {'success': False, 'error': 'Answer required'}
return {'success': False, 'error': _('Answer required')}

# Get or create session
session = DrawingSession.get_active_session(connection_id)
if not session:
return {'success': False, 'error': 'No active session'}
return {'success': False, 'error': _('No active session')}

if session.waiting_for_partner:
return {'success': False, 'error': 'Waiting for partner to join'}
return {'success': False, 'error': _('Waiting for partner to join')}

if session.is_session_complete():
return {'success': False, 'error': 'Session complete'}
return {'success': False, 'error': _('Session complete')}

# Start the round
session.start_next_round(drawer_id, answer)
Expand Down Expand Up @@ -721,15 +721,15 @@ def handle_end_game_early(data):
session_id = data.get('session_id')

if not validate_connection_access(connection_id, current_user.id):
return {'success': False, 'error': 'Access denied'}
return {'success': False, 'error': _('Access denied')}

session = DrawingSession.get_by_id(session_id)
if not session or session.connection_id != connection_id:
return {'success': False, 'error': 'Invalid session'}
return {'success': False, 'error': _('Invalid session')}

# Ensure the session is still active
if not session.is_active:
return {'success': False, 'error': 'Session is not active'}
return {'success': False, 'error': _('Session is not active')}

# End the session
session.end_session()
Expand All @@ -749,7 +749,7 @@ def handle_create_new_game_session(data):
connection_id = data.get('connection_id')

if not validate_connection_access(connection_id, current_user.id):
return {'success': False, 'error': 'Access denied'}
return {'success': False, 'error': _('Access denied')}

# Create new session (this will deactivate old ones)
session_id = DrawingSession.create(connection_id, current_user.id, DEFAULT_ROUNDS_PER_SESSION)
Expand All @@ -773,11 +773,11 @@ def handle_send_message(data):

# Validate access
if not validate_connection_access(connection_id, current_user.id):
return {'success': False, 'error': 'Access denied'}
return {'success': False, 'error': _('Access denied')}

# Validate message length (max 1000 chars)
if not message or len(message) > 1000:
return {'success': False, 'error': 'Invalid message'}
return {'success': False, 'error': _('Invalid message')}

# Save message
message_id = ChatMessage.create(connection_id, current_user.id, message)
Expand Down
54 changes: 46 additions & 8 deletions static/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -449,11 +449,13 @@ body {
border-radius: var(--border-radius);
background: #ffffff;
padding: 0.5rem;
flex: 1;
min-height: 400px;
}

.clipboard-drawing-wrap canvas {
width: 100%;
height: auto;
height: 100%;
border-radius: var(--border-radius);
background: #ffffff;
display: block;
Expand All @@ -469,15 +471,15 @@ body {
}

.clipboard-display.drawing-active .clipboard-drawing-wrap {
display: block;
display: flex;
}

.clipboard-display.drawing-active {
min-height: 360px;
min-height: 400px;
}

.clipboard-pane.other-pane .clipboard-display.drawing-active {
min-height: 320px;
min-height: 400px;
}

.clipboard-container.handwriting-mode {
Expand All @@ -493,7 +495,7 @@ body {
}

.clipboard-container.handwriting-mode .clipboard-pane.other-pane .clipboard-display.drawing-active {
min-height: 180px;
min-height: 300px;
}

.clipboard-textarea {
Expand Down Expand Up @@ -600,11 +602,16 @@ body {

.memory-page {
margin-top: 1rem;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
}

.memory-pane.standalone-memory {
box-shadow: 0 2px 10px rgba(30, 64, 175, 0.12);
border-left-color: #4f46e5;
padding: 1rem;
border-radius: var(--border-radius);
}

.toolbar-btn.link-btn {
Expand Down Expand Up @@ -660,8 +667,20 @@ body {
display: flex;
flex-direction: column;
gap: 0.5rem;
border-top: 1px solid #e2e8f0;
padding-top: 0.75rem;
margin-top: 0.75rem;
}

.memory-pane h3 {
font-size: 1.1rem;
color: #1f2937;
margin-bottom: 0.75rem;
display: flex;
align-items: center;
gap: 0.5rem;
}

.memory-pane h3 i {
color: #4f46e5;
}

.memory-form input,
Expand Down Expand Up @@ -1069,6 +1088,22 @@ body {
font-size: 0.9rem;
}

.clipboard-drawing-wrap {
min-height: 150px;
}

.clipboard-display.drawing-active {
min-height: 150px;
}

.clipboard-pane.other-pane .clipboard-display.drawing-active {
min-height: 150px;
}

.clipboard-container.handwriting-mode .clipboard-pane.other-pane .clipboard-display.drawing-active {
min-height: 120px;
}

.clipboard-toolbar {
flex-direction: column;
align-items: flex-start;
Expand All @@ -1093,7 +1128,8 @@ body {
}

.memory-pane {
display: none;
display: flex;
flex-direction: column;
}

.memory-pane.is-open {
Expand All @@ -1106,6 +1142,8 @@ body {

.memory-page {
margin-top: 0.5rem;
grid-template-columns: 1fr;
gap: 1rem;
}

.memory-list {
Expand Down
39 changes: 18 additions & 21 deletions templates/clipboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -417,19 +417,18 @@ <h3><i class="fas fa-user"></i> {{ _('Your Area (%(username)s)', username=curren
lastY = e.clientY - rect.top;
myDrawingCtx.beginPath();
myDrawingCtx.moveTo(lastX, lastY);
emitDrawing({ type: 'stroke_start', x: lastX, y: lastY });
}

function drawStroke(x, y) {
myDrawingCtx.lineWidth = 4;
myDrawingCtx.lineCap = 'round';
myDrawingCtx.lineJoin = 'round';
myDrawingCtx.strokeStyle = '#1f2937';
myDrawingCtx.lineTo(x, y);
myDrawingCtx.stroke();
myDrawingCtx.beginPath();
myDrawingCtx.moveTo(x, y);
localDrawingHasContent = true;
lastX = x;
lastY = y;
emitDrawing({ type: 'draw', x, y });
}

Expand All @@ -438,8 +437,6 @@ <h3><i class="fas fa-user"></i> {{ _('Your Area (%(username)s)', username=curren
const rect = myDrawingCanvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
myDrawingCtx.beginPath();
myDrawingCtx.moveTo(lastX, lastY);
drawStroke(x, y);
lastX = x;
lastY = y;
Expand Down Expand Up @@ -487,7 +484,6 @@ <h3><i class="fas fa-user"></i> {{ _('Your Area (%(username)s)', username=curren
lastY = touch.clientY - rect.top;
myDrawingCtx.beginPath();
myDrawingCtx.moveTo(lastX, lastY);
emitDrawing({ type: 'stroke_start', x: lastX, y: lastY });
}, { passive: false });

myDrawingCanvas.addEventListener('touchmove', (event) => {
Expand All @@ -497,9 +493,9 @@ <h3><i class="fas fa-user"></i> {{ _('Your Area (%(username)s)', username=curren
const rect = myDrawingCanvas.getBoundingClientRect();
const x = touch.clientX - rect.left;
const y = touch.clientY - rect.top;
myDrawingCtx.beginPath();
myDrawingCtx.moveTo(lastX, lastY);
drawStroke(x, y);
lastX = x;
lastY = y;
}, { passive: false });

myDrawingCanvas.addEventListener('touchend', (event) => {
Expand All @@ -521,7 +517,7 @@ <h3><i class="fas fa-user"></i> {{ _('Your Area (%(username)s)', username=curren
drawingPoints.push(drawing);
}
otherLastStroke = Date.now();
if (drawing.type === 'stroke_start' || drawing.type === 'draw') {
if (drawing.type === 'draw') {
setRemoteDrawingActive(true);
}
lastRemoteTimestamp = drawing.ts || lastRemoteTimestamp;
Expand Down Expand Up @@ -586,21 +582,22 @@ <h3><i class="fas fa-user"></i> {{ _('Your Area (%(username)s)', username=curren
}
return;
}
if (drawing.type === 'stroke_end' || drawing.type === 'stroke_start') {
if (drawing.type === 'stroke_end') {
ctx.beginPath();
if (drawing.type === 'stroke_start') {
ctx.moveTo(drawing.x, drawing.y);
}
return;
}
ctx.lineWidth = 4;
ctx.strokeStyle = '#1f2937';
ctx.lineTo(drawing.x, drawing.y);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(drawing.x, drawing.y);
if (ctx === otherDrawingCtx) {
otherDrawingHasContent = true;
if (drawing.type === 'draw') {
ctx.lineWidth = 4;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
ctx.strokeStyle = '#1f2937';
ctx.lineTo(drawing.x, drawing.y);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(drawing.x, drawing.y);
if (ctx === otherDrawingCtx) {
otherDrawingHasContent = true;
}
}
}

Expand Down
Loading