import json import pickle import base64 import gettext import keyring import threading import configparser import flet as ft from i18n import * from utils import * from pages.home import * from pages.exams import * from pages.grades import * from pages.homework import * from pages.settings import * from sqlitehandlernr import * from pages.timetable import * from pages.behaviour import * from pages.attendance import * from constants import defconf, usrconf from sdk.src.interfaces.prometheus.context import * from sdk.src.interfaces.prometheus.interface import * config = configparser.ConfigParser() def sync(page: ft.Page): auth_context_raw = loadauth("Fuji", "Auth Context") auth_context = PrometheusAuthContext.model_validate_json(auth_context_raw) interface = PrometheusInterface( auth_context=auth_context, student_context=None, ) try: interface.login() except NoLoggedInException: print("NoLoggedInException, or in other words, vulcan shitted itself.") exit() students = interface.get_students() student = int(keyring.get_password("Fuji", "Student_Index")) interface.select_student(students[student].context) auth_context = interface.get_auth_context() jsoncontext = auth_context.model_dump_json() saveauth("Fuji", "Auth Context", jsoncontext) student = students[student] current_period = next(period for period in student.periods if period.current) grades = interface.get_grades(current_period.number) notes = interface.get_notes() create_notes_database(notes_list=notes) create_grades_database(grades_list=grades) def change_page(route): routes = { "/": HomePage(), "/grades": GradesPage(page), "/timetable": TimetablePage(), "/homework": HomeworkPage(), "/exams": ExamsPage(), "/attendance": AttendancePage(), "/behaviour": BehaviourPage(), "/settings": SettingsPage(page) } page.views.clear() view = ft.View(route, [ ft.Row([ bar, ft.Container(content=routes.get(route, HomePage()), expand=True) ], expand=True) ]) page.views.append(view) page.update() change_page(page.route) def main(page: ft.Page): global bar # Page settings page.title = "Fuji" page.theme = ft.Theme( color_scheme_seed=getattr(ft.Colors, getthemecolor()), font_family="Roboto", page_transitions=ft.PageTransitionsTheme( macos=ft.PageTransitionTheme.NONE, linux=ft.PageTransitionTheme.NONE, windows=ft.PageTransitionTheme.NONE ), ) # Sync s = threading.Thread(target=sync, args=(page,)) s.start() # Page routing def change_page(route): routes = { "/": HomePage(), "/grades": GradesPage(page), "/timetable": TimetablePage(), "/homework": HomeworkPage(), "/exams": ExamsPage(), "/attendance": AttendancePage(), "/behaviour": BehaviourPage(), "/settings": SettingsPage(page) } page.views.clear() view = ft.View(route, [ ft.Row([ bar, ft.Container(content=routes.get(route, HomePage()), expand=True) ], expand=True) ]) page.views.append(view) page.update() def on_route_change(e): change_page(e.route) # Navigation bar bar = ft.NavigationRail( selected_index=0, 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]) ) page.on_route_change = on_route_change page.go("/") def login(page: ft.Page): # Page settings page.title = "Log in" page.theme = ft.Theme( color_scheme_seed=ft.Colors.RED, font_family="Roboto", page_transitions=ft.PageTransitionsTheme( android=ft.PageTransitionTheme.PREDICTIVE, ios=ft.PageTransitionTheme.PREDICTIVE, macos=ft.PageTransitionTheme.PREDICTIVE, linux=ft.PageTransitionTheme.PREDICTIVE, windows=ft.PageTransitionTheme.PREDICTIVE ) ) interface = None data = {"usr": None, "passwd": None} # Saving credentials def changeusr(e): global usr data["usr"] = e.control.value #print(usr) def changepasswd(e): global passwd data["passwd"] = e.control.value #print(passwd) # Login event def loginev(e): global interface login = data["usr"] password = data["passwd"] if login and password: interface = PrometheusInterface(auth_context=PrometheusAuthContext(prometheus_web_credentials=PrometheusWebCredentials(username=login, password=password))) interface.login() page.go("/students") else: print("No credentials!") # Students fetching, dropdown and selection def students(): global interface students = interface.get_students() def on_change(e): selected_index = next((i for i, student in enumerate(students) if student.full_name == e.control.value), -1) interface.select_student(students[selected_index].context) keyring.set_password("Fuji", "Student_Index", str(selected_index)) auth_context = interface.get_auth_context() jsoncontext = auth_context.model_dump_json() saveauth("Fuji", "Auth Context", jsoncontext) config.read(f"{getconfigpath()}/config.ini") config['Settings']['isLogged'] = 'True' config['User']['fullName'] = students[selected_index].full_name config['User']['grade'] = students[selected_index].class_name with open(f"{getconfigpath()}/config.ini", "w") as file: config.write(file) page.go("/start") dropdown = ft.Dropdown( label="Select a Student", options=[ ft.dropdown.Option(student.full_name) for student in students ], on_change=on_change, width=300 ) return dropdown # Page routing def route_change(route): page.views.clear() # Welcome view if page.route == "/login": welcome_view = ft.View( route="/login", controls=[ ft.Container( content=ft.Column( [ ft.Image( src="src/assets/logo.png", width=256, height=256, fit=ft.ImageFit.CONTAIN, border_radius=ft.border_radius.all(100000) ), ft.Text(value=(_("Welcome to Fuji!")), size=64), ft.Button( (_("Get Started")), scale=2.0, width=230, on_click=lambda e: page.go("/login/eduvulcan") ), ], alignment=ft.MainAxisAlignment.CENTER, horizontal_alignment=ft.CrossAxisAlignment.CENTER, spacing=30 ), alignment=ft.alignment.center, expand=True, padding=ft.padding.all(20) ) ] ) page.views.append(welcome_view) # Login form view elif page.route == "/login/eduvulcan": login_view = ft.View( route="/login/eduvulcan", controls=[ ft.Container( content=ft.Column( [ ft.Text(value=(_("Log in")), size=32, weight="bold", text_align=ft.TextAlign.CENTER), ft.TextField( label=(_("Username")), autofill_hints=[ft.AutofillHint.USERNAME], width=300, on_change=changeusr ), ft.TextField( label=(_("Password")), password=True, can_reveal_password=True, autofill_hints=[ft.AutofillHint.PASSWORD], width=300, on_change=changepasswd ), ft.Button((_("Log in")), scale=1.25, width=250, on_click=loginev), ], alignment=ft.MainAxisAlignment.CENTER, horizontal_alignment=ft.CrossAxisAlignment.CENTER, spacing=30 ), alignment=ft.alignment.center, expand=True, padding=ft.padding.all(20) ) ] ) page.views.append(login_view) # Students view elif page.route == "/students": students_view = ft.View( route="/students", controls=[ ft.Container( content=ft.Column( [ ft.Text(value=(_("Select a student")), size=32, weight="bold", text_align=ft.TextAlign.CENTER), students(), ], alignment=ft.MainAxisAlignment.CENTER, horizontal_alignment=ft.CrossAxisAlignment.CENTER, spacing=30 ), alignment=ft.alignment.center, expand=True, padding=ft.padding.all(20) ) ] ) page.views.append(students_view) # Start view elif page.route == "/start": # start_view = ft.View( restart(page) page.update() def view_pop(view): page.views.pop() top_view = page.views[-1] page.go(top_view.route) page.on_route_change = route_change page.on_view_pop = view_pop page.go("/login") # App configuration if __name__ == "__main__": try: config.read(f"{getconfigpath()}/config.ini") isLogged = config['Settings']['isLogged'] match isLogged: case 'True': ft.app(target=main) case 'False': ft.app(target=login) except (FileNotFoundError, KeyError): os.makedirs(getconfigpath()) config['Settings'] = defconf config['User'] = usrconf with open(f"{getconfigpath()}/config.ini", "w") as file: config.write(file) ft.app(target=login) except FileExistsError: config['Settings'] = defconf config['User'] = usrconf with open(f"{getconfigpath()}/config.ini", "w") as file: config.write(file) ft.app(target=login)