344 lines
16 KiB
Python
344 lines
16 KiB
Python
import flet as ft
|
|
import requests
|
|
import threading
|
|
import asyncio
|
|
import websockets
|
|
from websockets import connect # Ensure this is imported
|
|
import json
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
def get_initials(user_name: str):
|
|
if user_name:
|
|
return user_name[0].capitalize()
|
|
else:
|
|
return "E" # or any default value you prefer
|
|
|
|
|
|
def get_avatar_color(user_name: str):
|
|
colors_lookup = [
|
|
ft.colors.AMBER,
|
|
ft.colors.BLUE,
|
|
ft.colors.BROWN,
|
|
ft.colors.CYAN,
|
|
ft.colors.GREEN,
|
|
ft.colors.INDIGO,
|
|
ft.colors.LIME,
|
|
ft.colors.ORANGE,
|
|
ft.colors.PINK,
|
|
ft.colors.PURPLE,
|
|
ft.colors.RED,
|
|
ft.colors.TEAL,
|
|
]
|
|
return colors_lookup[hash(user_name) % len(colors_lookup)]
|
|
|
|
|
|
def student_main_page(page: ft.Page):
|
|
page.clean()
|
|
page.title = "Room Information"
|
|
page.theme_mode = ft.ThemeMode.LIGHT
|
|
|
|
page.vertical_alignment = ft.MainAxisAlignment.START # Align all content to the top
|
|
page.scroll = "adaptive"
|
|
page.padding = 20
|
|
|
|
# Container for lessons
|
|
lessons_container = ft.Column(
|
|
alignment=ft.MainAxisAlignment.CENTER, spacing=20)
|
|
|
|
def test(e):
|
|
print(e)
|
|
page.go("/test")
|
|
print("test")
|
|
|
|
def ausloggen(e=None):
|
|
page.go("/login")
|
|
print(page.session.get("access_token"))
|
|
|
|
def page_dialog_click(e, lesson_id):
|
|
dialog_leave = ft.AlertDialog(
|
|
modal=True,
|
|
title=ft.Text("Bitte bestätige"),
|
|
content=ft.Text("Möchtest du diesem Raum wirklich verlassen?"),
|
|
actions=[
|
|
ft.TextButton("Ja", on_click=lambda e: (page.close(
|
|
dialog_leave), leave_current_room(e, lesson_id))),
|
|
ft.TextButton(
|
|
"Nein", on_click=lambda e: page.close(dialog_leave)),
|
|
],
|
|
actions_alignment=ft.MainAxisAlignment.END,
|
|
)
|
|
page.dialog = dialog_leave
|
|
dialog_leave.open = True
|
|
page.update()
|
|
|
|
def leave_current_room(e=None, unique_id=None):
|
|
if not unique_id:
|
|
page.snack_bar = ft.SnackBar(
|
|
ft.Text("Kein Raum zum verlassen ausgewählt"))
|
|
page.snack_bar.open = True
|
|
page.update()
|
|
return
|
|
|
|
url = f"http://awesom-o.org:8000/student/leave_room/?unique_id={
|
|
unique_id}"
|
|
headers = {"accept": "application/json",
|
|
"Content-Type": "application/json"}
|
|
data = {"session_id": page.session.get("access_token")}
|
|
try:
|
|
response = requests.post(url, json=data, headers=headers)
|
|
response.raise_for_status()
|
|
if response:
|
|
get_rooms()
|
|
page.snack_bar = ft.SnackBar(
|
|
ft.Text("Raum erfolgreich verlassen"))
|
|
page.snack_bar.open = True
|
|
page.update()
|
|
get_rooms()
|
|
except requests.RequestException as error:
|
|
# Handle all bad responses
|
|
error_detail = "Something went wrong."
|
|
if hasattr(error, "response") and error.response:
|
|
try:
|
|
error_detail = error.response.json().get("detail", "Something went wrong.")
|
|
except json.JSONDecodeError:
|
|
error_detail = error.response.text or "Etwas ist schiefgelaufen"
|
|
page.snack_bar = ft.SnackBar(ft.Text(f"Error: {error_detail}"))
|
|
page.snack_bar.open = True
|
|
page.update()
|
|
|
|
async def get_rooms():
|
|
uri = "ws://localhost:8000/ws/student/my_room"
|
|
headers = {"session-id": page.session.get("access_token")}
|
|
|
|
try:
|
|
async with websockets.connect(uri, extra_headers=headers) as websocket:
|
|
while True:
|
|
message = await websocket.recv()
|
|
data = json.loads(message)
|
|
# Clear previous lessons
|
|
lessons_container.controls.clear()
|
|
|
|
if "error" in data:
|
|
# Show "No Rooms for Today" message
|
|
lessons_container.controls.append(
|
|
ft.Container(
|
|
content=ft.Text(
|
|
"Für heute wurden noch keine Räume ausgewählt.",
|
|
size=25,
|
|
text_align="center",
|
|
),
|
|
border=ft.Border(
|
|
top=ft.BorderSide(1, ft.colors.BLACK),
|
|
bottom=ft.BorderSide(1, ft.colors.BLACK),
|
|
left=ft.BorderSide(1, ft.colors.BLACK),
|
|
right=ft.BorderSide(1, ft.colors.BLACK)
|
|
),
|
|
border_radius=20,
|
|
padding=10,
|
|
height=150,
|
|
bgcolor=ft.colors.WHITE,
|
|
alignment=ft.alignment.center,
|
|
)
|
|
)
|
|
else:
|
|
rooms = data.get("rooms", [])
|
|
# Filter and sort lessons for today
|
|
today = datetime.now().date()
|
|
today_lessons = [
|
|
room for room in rooms if room["lesson_date"] == str(today)]
|
|
today_lessons.sort(key=lambda x: x["lesson_time"])
|
|
|
|
# Check if there are rooms on other dates
|
|
other_date_rooms = [
|
|
room for room in rooms if room["lesson_date"] != str(today)]
|
|
if today_lessons:
|
|
for lesson in today_lessons:
|
|
if lesson['current_students'] == lesson['max_students']:
|
|
BACKROUND_COLOR = "#f10d0c"
|
|
TEXT_COLOR = ft.colors.WHITE
|
|
else:
|
|
BACKROUND_COLOR = "#729fcf"
|
|
TEXT_COLOR = ft.colors.BLACK
|
|
# Create lesson card
|
|
room_card = ft.Card(
|
|
content=ft.Container(
|
|
content=ft.Row(
|
|
[
|
|
# Room details
|
|
ft.Column(
|
|
[
|
|
# Top line:
|
|
# room_number, info, location
|
|
ft.Text(
|
|
f"Heute, {
|
|
lesson['lesson_time']} Uhr",
|
|
size=16,
|
|
color=TEXT_COLOR
|
|
),
|
|
|
|
# Second line: first_name and last_name
|
|
ft.Text(
|
|
f"Lehrkraft: {lesson['first_name']} {
|
|
lesson['last_name']} - {lesson['subjects']}",
|
|
size=16,
|
|
color=TEXT_COLOR
|
|
),
|
|
# Third line: lesson_time
|
|
ft.Text(
|
|
f"Raum {lesson['room_number']} {
|
|
lesson['info']} | {lesson['location']}",
|
|
size=16,
|
|
color=TEXT_COLOR
|
|
),
|
|
|
|
ft.Text(
|
|
f"Belegte Plätze: {
|
|
lesson['current_students']}/{lesson['max_students']}",
|
|
size=16,
|
|
color=TEXT_COLOR
|
|
),
|
|
],
|
|
expand=True,
|
|
alignment=ft.MainAxisAlignment.CENTER,
|
|
),
|
|
# IconButton on the right
|
|
ft.Column(
|
|
[
|
|
ft.TextButton("Aus Raum abmelden", on_click=lambda e, lesson_id=lesson['unique_id']: page_dialog_click(e, lesson_id),
|
|
style=ft.ButtonStyle(
|
|
bgcolor=ft.colors.WHITE,
|
|
color=ft.colors.BLACK,
|
|
shape=ft.RoundedRectangleBorder(
|
|
radius=5),
|
|
padding=20,
|
|
)
|
|
),
|
|
ft.Text("ACHTUNG: Hierdurch wird", size=12), ft.Text(
|
|
"dein reservierter Platz für", size=12), ft.Text("jemand anderes freigegeben.", size=12),
|
|
]
|
|
)
|
|
],
|
|
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
|
|
),
|
|
padding=20, # Add padding inside the card
|
|
),
|
|
color=BACKROUND_COLOR,
|
|
margin=10,
|
|
)
|
|
lessons_container.controls.append(room_card)
|
|
else:
|
|
# Show "No Rooms for Today" message
|
|
lessons_container.controls.append(
|
|
ft.Container(
|
|
content=ft.Text(
|
|
"Für heute wurden noch keine Räume ausgewählt.",
|
|
size=25,
|
|
text_align="center",
|
|
),
|
|
border=ft.Border(
|
|
top=ft.BorderSide(1, ft.colors.BLACK),
|
|
bottom=ft.BorderSide(
|
|
1, ft.colors.BLACK),
|
|
left=ft.BorderSide(1, ft.colors.BLACK),
|
|
right=ft.BorderSide(1, ft.colors.BLACK)
|
|
),
|
|
border_radius=20,
|
|
padding=10,
|
|
height=150,
|
|
bgcolor=ft.colors.WHITE,
|
|
alignment=ft.alignment.center,
|
|
)
|
|
)
|
|
|
|
# Update page
|
|
page.update()
|
|
except Exception as e:
|
|
lessons_container.controls.clear()
|
|
lessons_container.controls.append(
|
|
ft.Text(f"Error: {e}", size=50, weight="bold", text_align="center"))
|
|
page.update()
|
|
|
|
def start_get_rooms():
|
|
# Ensure a new event loop in the thread
|
|
loop = asyncio.new_event_loop()
|
|
asyncio.set_event_loop(loop)
|
|
loop.run_until_complete(get_rooms())
|
|
|
|
# Start the WebSocket client in a thread
|
|
import threading
|
|
threading.Thread(target=start_get_rooms, daemon=True).start()
|
|
|
|
join_more_rooms_button = ft.Container(
|
|
content=ft.Text("Räume suchen", size=24, color=ft.colors.BLUE_900),
|
|
on_click=lambda e: page.go("/join"),
|
|
alignment=ft.alignment.center,
|
|
width=200,
|
|
height=60,
|
|
bgcolor='transparent',
|
|
ink=True,
|
|
)
|
|
|
|
navigation_bar = ft.Row(
|
|
[ft.Text("Home", size=23, weight=ft.FontWeight.BOLD,
|
|
width=100), join_more_rooms_button],
|
|
)
|
|
|
|
# Add components to page
|
|
page.add(
|
|
ft.Column(
|
|
[
|
|
ft.Row(
|
|
[
|
|
ft.Text(
|
|
"Daltonraum-Buchungssystem der IGS Garbsen", size=30),
|
|
ft.Column([
|
|
ft.PopupMenuButton(
|
|
items=[
|
|
ft.PopupMenuItem(content=ft.Text(f"Eingeloggt als: {page.session.get("username")}", weight=ft.FontWeight.BOLD)),
|
|
ft.PopupMenuItem(text="Profil anzeigen", on_click=test),
|
|
ft.PopupMenuItem(text="Ausloggen", on_click=ausloggen),
|
|
],
|
|
content=ft.CircleAvatar(
|
|
content=ft.Text(get_initials(
|
|
page.session.get("username"))),
|
|
color=ft.colors.WHITE,
|
|
bgcolor=get_avatar_color(
|
|
page.session.get("username")),
|
|
),
|
|
menu_position=ft.PopupMenuPosition.UNDER,
|
|
tooltip="",
|
|
|
|
)
|
|
|
|
],
|
|
# Align column content to the end (optional)
|
|
alignment=ft.MainAxisAlignment.END,
|
|
),
|
|
],
|
|
alignment=ft.MainAxisAlignment.SPACE_BETWEEN, # Space out the two elements
|
|
vertical_alignment=ft.CrossAxisAlignment.CENTER, # Align items vertically
|
|
),
|
|
|
|
navigation_bar,
|
|
ft.Row( # Wrap the Text in a Row
|
|
[
|
|
ft.Text(
|
|
"Du hast dich heute in folgende Daltonräume eingetragen:", size=25)
|
|
],
|
|
alignment=ft.MainAxisAlignment.CENTER # Center the Text horizontally
|
|
),
|
|
ft.Column(
|
|
[
|
|
lessons_container,
|
|
],
|
|
alignment=ft.MainAxisAlignment.CENTER,
|
|
expand=True, # Make it take available space vertically
|
|
),
|
|
],
|
|
expand=True, # This makes the outer column take available space as well
|
|
alignment=ft.MainAxisAlignment.CENTER, # Center the whole column vertically
|
|
)
|
|
)
|