Add better grades details
This commit is contained in:
parent
2f6a8fb398
commit
6477ad1f9b
3 changed files with 299 additions and 182 deletions
64
src/main.py
64
src/main.py
|
@ -23,7 +23,7 @@ from sdk.src.interfaces.prometheus.interface import *
|
||||||
|
|
||||||
config = configparser.ConfigParser()
|
config = configparser.ConfigParser()
|
||||||
|
|
||||||
def sync(page):
|
def sync(page: ft.Page):
|
||||||
auth_context_raw = loadauth("Fuji", "Auth Context")
|
auth_context_raw = loadauth("Fuji", "Auth Context")
|
||||||
auth_context = PrometheusAuthContext.model_validate_json(auth_context_raw)
|
auth_context = PrometheusAuthContext.model_validate_json(auth_context_raw)
|
||||||
|
|
||||||
|
@ -55,12 +55,7 @@ def sync(page):
|
||||||
|
|
||||||
create_grades_database(grades_list=grades)
|
create_grades_database(grades_list=grades)
|
||||||
|
|
||||||
# Get the current route to know which page to refresh
|
def change_page(route):
|
||||||
current_route = page.route
|
|
||||||
|
|
||||||
# Use the built-in change_page function to rewrite the current page
|
|
||||||
page.views.clear()
|
|
||||||
|
|
||||||
routes = {
|
routes = {
|
||||||
"/": HomePage(),
|
"/": HomePage(),
|
||||||
"/grades": GradesPage(page),
|
"/grades": GradesPage(page),
|
||||||
|
@ -72,64 +67,21 @@ def sync(page):
|
||||||
"/settings": SettingsPage(page)
|
"/settings": SettingsPage(page)
|
||||||
}
|
}
|
||||||
|
|
||||||
# Access the navigation bar from the main function
|
page.views.clear()
|
||||||
bar = get_navigation_bar(page)
|
view = ft.View(route, [
|
||||||
|
|
||||||
view = ft.View(current_route, [
|
|
||||||
ft.Row([
|
ft.Row([
|
||||||
bar,
|
bar,
|
||||||
ft.Container(content=routes.get(current_route, HomePage()), expand=True)
|
ft.Container(content=routes.get(route, HomePage()), expand=True)
|
||||||
], expand=True)
|
], expand=True)
|
||||||
])
|
])
|
||||||
|
|
||||||
page.views.append(view)
|
page.views.append(view)
|
||||||
page.update()
|
page.update()
|
||||||
|
|
||||||
# You'll need to make the navigation bar accessible
|
change_page(page.route)
|
||||||
def get_navigation_bar(page):
|
|
||||||
return ft.NavigationRail(
|
|
||||||
selected_index=get_index_from_route(page.route),
|
|
||||||
label_type=ft.NavigationRailLabelType.ALL,
|
|
||||||
extended=False,
|
|
||||||
min_width=50,
|
|
||||||
min_extended_width=400,
|
|
||||||
group_alignment=0,
|
|
||||||
destinations=[
|
|
||||||
ft.NavigationRailDestination(icon=ft.Icons.HOME_OUTLINED, selected_icon=ft.Icons.HOME, label=(_("Home"))),
|
|
||||||
ft.NavigationRailDestination(icon=ft.Icons.LOOKS_6_OUTLINED, selected_icon=ft.Icons.LOOKS_6, label=(_("Grades"))),
|
|
||||||
ft.NavigationRailDestination(icon=ft.Icons.BACKPACK_OUTLINED, selected_icon=ft.Icons.BACKPACK, label=(_("Timetable"))),
|
|
||||||
ft.NavigationRailDestination(icon=ft.Icons.BOOK_OUTLINED, selected_icon=ft.Icons.BOOK, label=(_("Homework"))),
|
|
||||||
ft.NavigationRailDestination(icon=ft.Icons.CALENDAR_TODAY_OUTLINED, selected_icon=ft.Icons.CALENDAR_TODAY, label=(_("Exams"))),
|
|
||||||
ft.NavigationRailDestination(icon=ft.Icons.EVENT_NOTE_OUTLINED, selected_icon=ft.Icons.EVENT_NOTE, label=(_("Attendance"))),
|
|
||||||
ft.NavigationRailDestination(icon=ft.Icons.STICKY_NOTE_2_OUTLINED, selected_icon=ft.Icons.STICKY_NOTE_2, label=(_("Behaviour"))),
|
|
||||||
ft.NavigationRailDestination(icon=ft.Icons.SETTINGS_OUTLINED, selected_icon=ft.Icons.SETTINGS_ROUNDED, label=(_("Settings"))),
|
|
||||||
],
|
|
||||||
on_change=lambda e: page.go([
|
|
||||||
"/",
|
|
||||||
"/grades",
|
|
||||||
"/timetable",
|
|
||||||
"/homework",
|
|
||||||
"/exams",
|
|
||||||
"/attendance",
|
|
||||||
"/behaviour",
|
|
||||||
"/settings"
|
|
||||||
][e.control.selected_index])
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_index_from_route(route):
|
|
||||||
route_to_index = {
|
|
||||||
"/": 0,
|
|
||||||
"/grades": 1,
|
|
||||||
"/timetable": 2,
|
|
||||||
"/homework": 3,
|
|
||||||
"/exams": 4,
|
|
||||||
"/attendance": 5,
|
|
||||||
"/behaviour": 6,
|
|
||||||
"/settings": 7
|
|
||||||
}
|
|
||||||
return route_to_index.get(route, 0)
|
|
||||||
|
|
||||||
def main(page: ft.Page):
|
def main(page: ft.Page):
|
||||||
|
global bar
|
||||||
|
|
||||||
# Page settings
|
# Page settings
|
||||||
page.title = "Fuji"
|
page.title = "Fuji"
|
||||||
page.theme = ft.Theme(
|
page.theme = ft.Theme(
|
||||||
|
|
|
@ -3,103 +3,145 @@ from sqlitehandlernr import fetch_all_grades
|
||||||
from i18n import _
|
from i18n import _
|
||||||
|
|
||||||
def parse_grade_value(value):
|
def parse_grade_value(value):
|
||||||
"""
|
|
||||||
Parse grade value with optional + or - suffix.
|
|
||||||
Args:
|
|
||||||
value (str): Grade value as a string
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
float: Parsed grade value, or None if unrecognized
|
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
base_value = float(value.rstrip('+-')) # Remove +/- suffix and convert to float
|
base_value = float(value.rstrip('+-'))
|
||||||
if value.endswith('+'):
|
if value.endswith('+'):
|
||||||
return base_value + 0.25 # Add 0.25 for "+" suffix
|
return base_value + 0.25
|
||||||
elif value.endswith('-'):
|
elif value.endswith('-'):
|
||||||
return base_value - 0.25 # Subtract 0.25 for "-" suffix
|
return base_value - 0.25
|
||||||
return base_value
|
return base_value
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return None # Ignore unrecognized values
|
return None
|
||||||
|
|
||||||
|
def format_date(dt):
|
||||||
|
return dt.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
def GradesPage(page):
|
def GradesPage(page):
|
||||||
"""
|
|
||||||
Generate grades page with subject-based panels and expandable content
|
|
||||||
|
|
||||||
Args:
|
|
||||||
page (flet.Page): Flet page instance
|
|
||||||
"""
|
|
||||||
|
|
||||||
# Retrieve all grades from SQLite database
|
|
||||||
grades = fetch_all_grades()
|
grades = fetch_all_grades()
|
||||||
|
|
||||||
# Create modal dialog for displaying grade details
|
|
||||||
modal = ft.AlertDialog(
|
|
||||||
modal=True,
|
|
||||||
title=ft.Text(_("Test modal")), # Set modal title with translated text
|
|
||||||
content=ft.Text(""), # Placeholder text that will be updated dynamically
|
|
||||||
actions=[
|
|
||||||
ft.TextButton("OK", on_click=lambda e: page.close(modal)), # Close modal when OK button clicked
|
|
||||||
],
|
|
||||||
actions_alignment=ft.MainAxisAlignment.END,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Initialize subject-based panels and data storage
|
|
||||||
panels = []
|
panels = []
|
||||||
subjects = {}
|
subjects = {}
|
||||||
|
|
||||||
# Group grades by subject
|
|
||||||
for grade in grades:
|
for grade in grades:
|
||||||
subject = grade.subject
|
subject = grade.subject
|
||||||
if subject not in subjects: # Create new subject entry if not already present
|
if subject not in subjects:
|
||||||
subjects[subject] = []
|
subjects[subject] = []
|
||||||
subjects[subject].append(grade) # Add grade to corresponding subject list
|
subjects[subject].append(grade)
|
||||||
|
|
||||||
def format_date(dt):
|
modal = ft.BottomSheet(
|
||||||
"""Format a datetime object to YYYY-MM-DD string"""
|
content=ft.Column([], spacing=5),
|
||||||
return dt.strftime("%Y-%m-%d")
|
enable_drag=True,
|
||||||
|
open=False,
|
||||||
|
)
|
||||||
|
|
||||||
def open_grade_modal(grade):
|
def open_grade_modal(grade):
|
||||||
"""
|
parsed_value = parse_grade_value(grade.value)
|
||||||
Open modal dialog with detailed grade information
|
grade_display = f"{grade.value}" if parsed_value is not None else _("Grade not recognized")
|
||||||
|
|
||||||
Args:
|
|
||||||
grade (dict): Grade dictionary containing details
|
|
||||||
"""
|
|
||||||
modal.title = ft.Text(_("Grade Details")) # Update modal title
|
|
||||||
parsed_value = parse_grade_value(grade.value) # Parse grade value for display
|
|
||||||
|
|
||||||
# Fixed line - don't use replace with None
|
|
||||||
grade_text = f"{_('Grade')}: {grade.value}"
|
|
||||||
if parsed_value is None:
|
|
||||||
grade_text = f"{_('Grade')}: {_('Grade not recognized')}"
|
|
||||||
|
|
||||||
modal.content = ft.Column([
|
modal.content = ft.Column([
|
||||||
ft.Text(f"{_('Subject')}: {grade.subject}", size=14), # Display subject and translated text
|
|
||||||
ft.Text(grade_text, size=14),
|
|
||||||
ft.Text(f"{_('Date')}: {format_date(grade.created_at)}", size=14), # Format datetime object
|
|
||||||
ft.Text(f"{_('Weight')}: {getattr(grade, 'weight', 1.0)}", size=14),
|
|
||||||
ft.Text(f"{_('Description')}: {grade.name}", size=14),
|
|
||||||
ft.Text(f"{_('Creator')}: {grade.creator}", size=14)
|
|
||||||
], expand=False)
|
|
||||||
page.open(modal) # Open modal dialog
|
|
||||||
|
|
||||||
# Generate subject-based panels with expandable content
|
|
||||||
for subject, grades_list in subjects.items():
|
|
||||||
header = ft.Container(
|
|
||||||
content=ft.Column(
|
|
||||||
[
|
|
||||||
ft.Text(subject, size=15), # Display subject name
|
|
||||||
ft.Row([
|
ft.Row([
|
||||||
ft.Text(f"{len(grades_list)} "+_("grades"), size=14), # Display number of grades and translated text
|
ft.Container(
|
||||||
ft.Text((_("Average"))+": {:.2f}".format(
|
content=ft.Column([
|
||||||
sum(parse_grade_value(g.value) for g in grades_list if parse_grade_value(g.value) is not None) / max(len([g for g in grades_list if parse_grade_value(g.value) is not None]), 1)
|
ft.Text(grade.subject, size=30, weight=ft.FontWeight.BOLD),
|
||||||
), size=14), # Calculate and display average grade
|
ft.Text(grade.name, size=18, color=ft.Colors.WHITE70),
|
||||||
])
|
], spacing=3, tight=True),
|
||||||
],
|
padding=ft.padding.only(left=20, top=-20, bottom=5, right=20),
|
||||||
alignment=ft.MainAxisAlignment.CENTER,
|
|
||||||
horizontal_alignment=ft.CrossAxisAlignment.START,
|
|
||||||
expand=True,
|
expand=True,
|
||||||
),
|
),
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Column([
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Text(grade_display, size=48, weight=ft.FontWeight.BOLD),
|
||||||
|
width=80,
|
||||||
|
height=80,
|
||||||
|
bgcolor=ft.Colors.GREEN_700,
|
||||||
|
border_radius=ft.border_radius.only(top_left=8, top_right=8),
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
margin=ft.margin.only(bottom=5, top=40)
|
||||||
|
),
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Row([
|
||||||
|
ft.Icon(name=ft.Icons.SCALE, size=16, color=ft.Colors.WHITE70),
|
||||||
|
ft.Text(f"{getattr(grade, 'weight', 1.0):.2f}", size=16),
|
||||||
|
], spacing=5, alignment=ft.MainAxisAlignment.CENTER),
|
||||||
|
width=80,
|
||||||
|
height=30,
|
||||||
|
bgcolor=ft.Colors.GREEN_700,
|
||||||
|
border_radius=ft.border_radius.only(bottom_left=8, bottom_right=8),
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
),
|
||||||
|
], spacing=0, alignment=ft.MainAxisAlignment.CENTER),
|
||||||
|
padding=ft.padding.only(right=20, top=-5, bottom=10),
|
||||||
|
),
|
||||||
|
], alignment=ft.MainAxisAlignment.SPACE_BETWEEN),
|
||||||
|
ft.Card(
|
||||||
|
content=ft.Row([
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Icon(name=ft.Icons.LOOKS_6_ROUNDED, size=20),
|
||||||
|
width=40,
|
||||||
|
height=40,
|
||||||
|
border_radius=8,
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
padding=ft.padding.only(left=10),
|
||||||
|
),
|
||||||
|
ft.Column([
|
||||||
|
ft.Text("Grade", size=14, color=ft.Colors.WHITE70),
|
||||||
|
ft.Text(grade_display, size=20),
|
||||||
|
], spacing=2, alignment=ft.MainAxisAlignment.CENTER, expand=True)
|
||||||
|
], spacing=15, alignment=ft.MainAxisAlignment.START, vertical_alignment=ft.CrossAxisAlignment.CENTER),
|
||||||
|
height=75,
|
||||||
|
color=ft.Colors.SURFACE_CONTAINER_HIGHEST,
|
||||||
|
),
|
||||||
|
ft.Card(
|
||||||
|
content=ft.Row([
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Icon(name=ft.Icons.SCALE, size=20),
|
||||||
|
width=40,
|
||||||
|
height=40,
|
||||||
|
border_radius=8,
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
padding=ft.padding.only(left=10),
|
||||||
|
),
|
||||||
|
ft.Column([
|
||||||
|
ft.Text("Weight", size=14, color=ft.Colors.WHITE70),
|
||||||
|
ft.Text(f"{getattr(grade, 'weight', 1.0):.2f}", size=20),
|
||||||
|
], spacing=2, alignment=ft.MainAxisAlignment.CENTER, expand=True)
|
||||||
|
], spacing=15, alignment=ft.MainAxisAlignment.START, vertical_alignment=ft.CrossAxisAlignment.CENTER),
|
||||||
|
height=75,
|
||||||
|
color=ft.Colors.SURFACE_CONTAINER_HIGHEST,
|
||||||
|
),
|
||||||
|
ft.Card(
|
||||||
|
content=ft.Row([
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Icon(name=ft.Icons.CALENDAR_TODAY, size=20),
|
||||||
|
width=40,
|
||||||
|
height=40,
|
||||||
|
border_radius=8,
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
padding=ft.padding.only(left=10),
|
||||||
|
),
|
||||||
|
ft.Column([
|
||||||
|
ft.Text("Date", size=14, color=ft.Colors.WHITE70),
|
||||||
|
ft.Text(format_date(grade.created_at), size=20),
|
||||||
|
], spacing=2, alignment=ft.MainAxisAlignment.CENTER, expand=True)
|
||||||
|
], spacing=15, alignment=ft.MainAxisAlignment.START, vertical_alignment=ft.CrossAxisAlignment.CENTER),
|
||||||
|
height=75,
|
||||||
|
color=ft.Colors.SURFACE_CONTAINER_HIGHEST,
|
||||||
|
),
|
||||||
|
], spacing=5)
|
||||||
|
modal.open = True
|
||||||
|
page.update()
|
||||||
|
|
||||||
|
for subject, grades_list in subjects.items():
|
||||||
|
header = ft.Container(
|
||||||
|
content=ft.Column([
|
||||||
|
ft.Text(subject, size=15),
|
||||||
|
ft.Row([
|
||||||
|
ft.Text(f"{len(grades_list)} " + _("grades"), size=14),
|
||||||
|
ft.Text((_("Average")) + ": {:.2f}".format(
|
||||||
|
sum(parse_grade_value(g.value) for g in grades_list if parse_grade_value(g.value) is not None) / max(len([g for g in grades_list if parse_grade_value(g.value) is not None]), 1)
|
||||||
|
), size=14),
|
||||||
|
])
|
||||||
|
], alignment=ft.MainAxisAlignment.CENTER, horizontal_alignment=ft.CrossAxisAlignment.START, expand=True),
|
||||||
padding=ft.padding.all(10),
|
padding=ft.padding.all(10),
|
||||||
expand=True,
|
expand=True,
|
||||||
)
|
)
|
||||||
|
@ -110,25 +152,21 @@ def GradesPage(page):
|
||||||
ft.Container(
|
ft.Container(
|
||||||
content=ft.Row([
|
content=ft.Row([
|
||||||
ft.Container(
|
ft.Container(
|
||||||
content=ft.Text(grade.value, text_align=ft.TextAlign.CENTER), # Display grade value
|
content=ft.Text(grade.value, text_align=ft.TextAlign.CENTER),
|
||||||
bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST,
|
bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST,
|
||||||
padding=ft.padding.symmetric(horizontal=12, vertical=8),
|
padding=ft.padding.symmetric(horizontal=12, vertical=8),
|
||||||
border_radius=5,
|
border_radius=5,
|
||||||
margin=ft.margin.all(5),
|
margin=ft.margin.all(5),
|
||||||
width=None, # Allow the container to size based on content
|
on_click=lambda e, grade=grade: open_grade_modal(grade),
|
||||||
on_click=lambda e, grade=grade: open_grade_modal(grade), # Open modal dialog when row clicked
|
|
||||||
),
|
),
|
||||||
ft.Column(
|
ft.Column([
|
||||||
[
|
ft.Text(grade.name),
|
||||||
ft.Text(grade.name), # Display grade name
|
|
||||||
ft.Row([
|
ft.Row([
|
||||||
ft.Text(format_date(grade.created_at)), # Format datetime object
|
ft.Text(format_date(grade.created_at)),
|
||||||
ft.Text((_("Weight"))+": {:.1f}".format(getattr(grade, 'weight', 1.0)))
|
ft.Text((_("Weight")) + ": {:.1f}".format(getattr(grade, 'weight', 1.0)))
|
||||||
])
|
])
|
||||||
],
|
], spacing=1)
|
||||||
spacing=1
|
], expand=True),
|
||||||
),
|
|
||||||
], expand=True), # Allow Row to expand and avoid tight squeezing
|
|
||||||
on_click=lambda e, grade=grade: open_grade_modal(grade),
|
on_click=lambda e, grade=grade: open_grade_modal(grade),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -137,14 +175,11 @@ def GradesPage(page):
|
||||||
header=header,
|
header=header,
|
||||||
content=ft.Column(grade_rows),
|
content=ft.Column(grade_rows),
|
||||||
expand=False,
|
expand=False,
|
||||||
#bgcolor=ft.Colors.SURFACE_CONTAINER_HIGHEST,
|
|
||||||
#can_tap_header=True,
|
|
||||||
)
|
)
|
||||||
panels.append(panel)
|
panels.append(panel)
|
||||||
|
|
||||||
return ft.Column([
|
return ft.Column([
|
||||||
ft.Text((_("Grades")), size=30, weight="bold"),
|
ft.Text((_("Grades")), size=30, weight="bold"),
|
||||||
ft.ExpansionPanelList(panels) # Display subject-based panels with expandable content
|
ft.ExpansionPanelList(panels),
|
||||||
],
|
modal
|
||||||
scroll=True
|
], scroll=True)
|
||||||
)
|
|
||||||
|
|
130
src/test.py
Normal file
130
src/test.py
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
import flet as ft
|
||||||
|
|
||||||
|
def main(page: ft.Page):
|
||||||
|
page.theme = ft.Theme(
|
||||||
|
color_scheme_seed=ft.Colors.PINK,
|
||||||
|
font_family="Roboto",
|
||||||
|
page_transitions=ft.PageTransitionsTheme(
|
||||||
|
macos=ft.PageTransitionTheme.NONE,
|
||||||
|
linux=ft.PageTransitionTheme.NONE,
|
||||||
|
windows=ft.PageTransitionTheme.NONE
|
||||||
|
),
|
||||||
|
)
|
||||||
|
page.theme_mode = ft.ThemeMode.DARK
|
||||||
|
|
||||||
|
modal = ft.BottomSheet(
|
||||||
|
content=ft.Column([
|
||||||
|
ft.Row([
|
||||||
|
# Subject details
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Column([
|
||||||
|
ft.Text("Wychowanie fizyczne", size=30, weight=ft.FontWeight.BOLD),
|
||||||
|
ft.Text("rozgrzewka", size=18, color=ft.Colors.WHITE70),
|
||||||
|
], spacing=3, tight=True),
|
||||||
|
padding=ft.padding.only(left=20, top=-20, bottom=5, right=20),
|
||||||
|
expand=True,
|
||||||
|
),
|
||||||
|
|
||||||
|
# Grade display
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Column([
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Text("5", size=48, weight=ft.FontWeight.BOLD),
|
||||||
|
width=80,
|
||||||
|
height=80,
|
||||||
|
bgcolor=ft.Colors.GREEN_700,
|
||||||
|
border_radius=ft.border_radius.only(top_left=8, top_right=8),
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
margin=ft.margin.only(bottom=5, top=40)
|
||||||
|
),
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Row([
|
||||||
|
ft.Icon(name=ft.Icons.SCALE, size=16),
|
||||||
|
ft.Text("1.00", size=16),
|
||||||
|
], spacing=5, alignment=ft.MainAxisAlignment.CENTER),
|
||||||
|
width=80,
|
||||||
|
height=30,
|
||||||
|
bgcolor=ft.Colors.GREEN_700,
|
||||||
|
border_radius=ft.border_radius.only(bottom_left=8, bottom_right=8),
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
),
|
||||||
|
], spacing=0, alignment=ft.MainAxisAlignment.CENTER),
|
||||||
|
padding=ft.padding.only(right=20, top=-5, bottom=10),
|
||||||
|
),
|
||||||
|
], alignment=ft.MainAxisAlignment.SPACE_BETWEEN),
|
||||||
|
|
||||||
|
|
||||||
|
# Grade details
|
||||||
|
ft.Card(
|
||||||
|
content=ft.Row([
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Icon(name=ft.Icons.SCALE, size=20),
|
||||||
|
width=40,
|
||||||
|
height=40,
|
||||||
|
border_radius=8,
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
padding=ft.padding.only(left=10),
|
||||||
|
),
|
||||||
|
ft.Column([
|
||||||
|
ft.Text("Grade", size=14, color=ft.Colors.WHITE70),
|
||||||
|
ft.Text("5", size=20)
|
||||||
|
], spacing=2, alignment=ft.MainAxisAlignment.CENTER, expand=True)
|
||||||
|
], spacing=15, alignment=ft.MainAxisAlignment.START, vertical_alignment=ft.CrossAxisAlignment.CENTER),
|
||||||
|
height=75,
|
||||||
|
color=ft.Colors.SURFACE_CONTAINER_HIGHEST,
|
||||||
|
margin=ft.margin.only(left=15, right=15, bottom=5),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
# Weight details
|
||||||
|
ft.Card(
|
||||||
|
content=ft.Row([
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Icon(name=ft.Icons.SCALE, size=20),
|
||||||
|
width=40,
|
||||||
|
height=40,
|
||||||
|
border_radius=8,
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
padding=ft.padding.only(left=10),
|
||||||
|
),
|
||||||
|
ft.Column([
|
||||||
|
ft.Text("Weight", size=14, color=ft.Colors.WHITE70),
|
||||||
|
ft.Text("1.00", size=20),
|
||||||
|
], spacing=2, alignment=ft.MainAxisAlignment.CENTER, expand=True), # Align and expand
|
||||||
|
], spacing=15, alignment=ft.MainAxisAlignment.START, vertical_alignment=ft.CrossAxisAlignment.CENTER),
|
||||||
|
height=75,
|
||||||
|
color=ft.Colors.SURFACE_CONTAINER_HIGHEST,
|
||||||
|
margin=ft.margin.only(left=15, right=15, top=5, bottom=5),
|
||||||
|
),
|
||||||
|
|
||||||
|
# Date details
|
||||||
|
ft.Card(
|
||||||
|
content=ft.Row([
|
||||||
|
ft.Container(
|
||||||
|
content=ft.Icon(name=ft.Icons.CALENDAR_TODAY, size=20),
|
||||||
|
width=40,
|
||||||
|
height=40,
|
||||||
|
border_radius=8,
|
||||||
|
alignment=ft.alignment.center,
|
||||||
|
padding=ft.padding.only(left=10),
|
||||||
|
),
|
||||||
|
ft.Column([
|
||||||
|
ft.Text("Date", size=14, color=ft.Colors.WHITE70),
|
||||||
|
ft.Text("2/10/25", size=20),
|
||||||
|
], spacing=2, alignment=ft.MainAxisAlignment.CENTER, expand=True), # Align and expand
|
||||||
|
], spacing=15, alignment=ft.MainAxisAlignment.START, vertical_alignment=ft.CrossAxisAlignment.CENTER),
|
||||||
|
height=75,
|
||||||
|
color=ft.Colors.SURFACE_CONTAINER_HIGHEST,
|
||||||
|
margin=ft.margin.only(left=15, right=15, bottom=5, top=5),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
], spacing=5),
|
||||||
|
enable_drag=True,
|
||||||
|
open=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add the modal directly to the page
|
||||||
|
page.add(ft.ElevatedButton("Open Grade Details", on_click=lambda _: page.open(modal)))
|
||||||
|
|
||||||
|
ft.app(target=main)
|
Loading…
Add table
Reference in a new issue