# Imports from KivyMD from kivymd.app import MDApp from kivymd.uix.datatables import MDDataTable # Imports from Kivy from kivy.uix.button import Button from kivy.uix.label import Label from kivy.metrics import dp from kivy.core.window import Window from kivy.lang import Builder from kivy.uix.screenmanager import ScreenManager, Screen from kivy.uix.anchorlayout import AnchorLayout from kivy.uix.boxlayout import BoxLayout from kivy.uix.gridlayout import GridLayout from kivy.clock import Clock # Main functionality from setup from Setup.setup import Setup from report import Report # Importing time for quiz timing import time # Import QuizClasses for quiz generation from QuizClasses.quiz import Quiz # Import Matplot to draw matrix as image import matplotlib as mpl import matplotlib.pyplot as plt import matplotlib.mathtext as mathtext # import os for deleting images import os # import numpy for checking answers import numpy as np # Constraining window sizes Window.minimum_height = 288 Window.minimum_width = 512 Window.maximum_height = 1080 Window.maximum_width = 1920 # Importing setup from setup.py S = Setup() class MenuScreen(Screen): def disable_login_registration(self): self.ids["log_in_button"].disabled = True self.ids["register_button"].disabled = True self.ids["practice_button"].disabled = False self.ids["report_button"].disabled = False def disable_registration(self): self.ids["register_button"].disabled = True class LoginScreen(Screen): login_data = [] current_user = "" def get_login_input(self): for textInput in list(self.ids)[1:]: self.login_data.append(self.ids[textInput].text) response = S.user_login(self.login_data) if response == "Incorrect password": self.ids["loginPasswordText"].error = True self.ids["loginPasswordText"].text = "" elif response == "User does not exist": self.ids["loginUsernameText"].error = True self.ids["loginUsernameText"].text = "" else: self.change_menu() self.parent.current = "MenuScreen" self.parent.transition.direction = "up" self.current_user = self.login_data[0] Clock.schedule_once(self.clear_errors, 3) def clear_errors(self, dt): for textfield in self.ids: self.ids[textfield].error = False def clear_login_input(self): self.login_data = [] def change_menu(self): menu = self.manager.get_screen('MenuScreen') menu.disable_login_registration() class RegistrationScreen(Screen): registration_data = [] def get_registration_input(self): for textInput in self.ids: self.registration_data.append(self.ids[textInput].text) response = S.user_register(self.registration_data) if response == "Passwords are not equal": self.ids["registrationRePasswordText"].error = True self.ids["registrationRePasswordText"].text = "" elif response == "Password does not meet requirements": self.ids["registrationPasswordText"].error = True self.ids["registrationPasswordText"].text = "" elif response == "Username does not meet requirements": self.ids["registrationUsernameText"].error = True self.ids["registrationUsernameText"].text = "" elif response[-6:] == "exists": self.ids["registrationUsernameText"].error = True self.ids["registrationUsernameText"].text = "" else: self.remove_registration_option() self.parent.current = "MenuScreen" self.parent.transition.direction = "down" Clock.schedule_once(self.clear_errors, 3) def clear_registration_input(self): self.registration_data = [] def clear_errors(self, dt): for textfield in self.ids: self.ids[textfield].error = False def remove_registration_option(self): menu = self.manager.get_screen('MenuScreen') menu.disable_registration() class PracticeScreen(Screen): def set_timer_true(self): tempScreen = self.manager.get_screen('QuestionSelectionScreen') tempScreen.set_timer_true() def set_timer_false(self): tempScreen = self.manager.get_screen('QuestionSelectionScreen') tempScreen.set_timer_false() class ReportScreen(Screen): def load_table(self): layout = BoxLayout(orientation='vertical') rep = Report(S.current_user.username, S.current_user.email) quizzes = rep.get_last_5_shortened() data_tables = MDDataTable( size_hint=(0.9, 0.6), pos_hint={"center_x": .5, "center_y": .5}, column_data=[("Date", dp(30)), ("Score", dp(30)), ("Time", dp(30)), ], row_data=quizzes ) title = Label(text='Report', size_hint=(1, .1)) button_email = Button( text='Email this table as a CSV file', size_hint=(1, .2)) button_email.bind(on_press=lambda x: rep.email_last_7()) button_export = Button( text='Email all results as a CSV file', size_hint=(1, .2)) button_export.bind(on_press=lambda x: rep.email_everything()) button_menu = Button(text='Back to the Menu', size_hint=(1, .2)) button_menu.bind(on_press=lambda x: self.fix()) layout.add_widget(title) layout.add_widget(data_tables) layout.add_widget(button_email) layout.add_widget(button_export) layout.add_widget(button_menu) self.add_widget(layout) def fix(self): self.manager.transition.direction = 'right' self.manager.current = 'MenuScreen' def on_enter(self): self.load_table() class ResetScreen(Screen): def reset_password(self): username = self.ids['resetUsernameText'].text response = S.user_login([username, ""]) if response != "User does not exist": password = self.ids["resetPasswordText"].text rePassword = self.ids["resetRePasswordText"].text if S.reset_password([username, password, rePassword]) == 'Reset': self.manager.transition.direction = 'right' self.manager.current = 'LoginScreen' class QuestionSelectionScreen(Screen): question_types = [] timed_quiz = False def mark_all(self): if self.ids["mark_all"].active == True: for checkbox in list(self.ids)[1:]: self.ids[checkbox].active = True else: for checkbox in list(self.ids)[1:]: self.ids[checkbox].active = False def set_types(self): self.question_types = [] for checkbox in list(self.ids)[1:-1]: if self.ids[checkbox].active == True: self.question_types.append(checkbox) def make_test(self): if self.question_types != []: S.current_quiz = Quiz(self.question_types, int(time.time())) self.parent.current = "QuestionScreen" def set_timer_true(self): self.timed_quiz = True def set_timer_false(self): self.timed_quiz = False def start_timer(self): if self.question_types != []: tempScreen = self.manager.get_screen('QuestionScreen') if self.timed_quiz == True: tempScreen.start_timer() else: tempScreen.ids["time_label"].text = "No Time Limit" class QuestionScreen(Screen): question_number = 0 current_time = 0 currently_rendering = 0 questions = [] answers = [["", "", ""] for i in range(10)] questions_right = [] question_instructions = { "+": "Please add the 2 matrices together", "*": "Please multiply the 2 matrices together", "-": "Please Subtract the second matrix from the first", "inv": "Please find the inverse of the matrix", "det": "Please find the determinant of the matrix", } def reset_details(self): self.question_number = 0 self.current_time = 0 self.currently_rendering = 0 self.answers.clear() self.questions.clear() self.questions_right.clear() self.increment_question() self.ids["question_back_button"].disabled = True def set_questions(self): self.questions = S.current_quiz.questions self.answers = [["", "", ""] for i in range(10)] def increment_question(self): self.question_number += 1 self.load_answer() if self.question_number < 11: self.ids["question_next_button"].disabled = False if self.question_number > 1: self.ids["question_back_button"].disabled = False else: self.mark_quiz() self.ids["question_label"].text = "Question "+str(self.question_number) try: self.ids["question_contents"].text = self.question_instructions.get( self.questions[self.question_number-1].operation) if os.path.exists("question"+str(self.question_number-1)+"A.png"): self.ids["matrix_a"].source = "question" + \ str(self.question_number-1)+"A.png" else: self.ids["matrix_a"].source = "empty.png" if os.path.exists("question"+str(self.question_number-1)+"B.png"): self.ids["matrix_b"].source = "question" + \ str(self.question_number-1)+"B.png" else: self.ids["matrix_b"].source = "empty.png" except: pass def save_current_answer(self): count = 0 for textfield in list(self.ids)[5:8]: self.answers[self.question_number - 1][count] = self.ids[textfield].text count += 1 def clear_current_answer(self): self.ids["rows_text"].text = "" self.ids["columns_text"].text = "" self.ids["matrix_text"].text = "" def load_answer(self): try: self.ids["rows_text"].text = self.answers[self.question_number-1][0] self.ids["columns_text"].text = self.answers[self.question_number-1][1] self.ids["matrix_text"].text = self.answers[self.question_number-1][2] except: pass def decrement_question(self): self.question_number -= 1 self.load_answer() if self.question_number == 1: self.ids["question_back_button"].disabled = True else: self.ids["question_back_button"].disabled = False self.ids["question_label"].text = "Question "+str(self.question_number) try: self.ids["question_contents"].text = self.question_instructions.get( self.questions[self.question_number-1].operation) if os.path.exists("question"+str(self.question_number-1)+"A.png"): self.ids["matrix_a"].source = "question" + \ str(self.question_number-1)+"A.png" else: self.ids["matrix_a"].source = "empty.png" if os.path.exists("question"+str(self.question_number-1)+"B.png"): self.ids["matrix_b"].source = "question" + \ str(self.question_number-1)+"B.png" else: self.ids["matrix_b"].source = "empty.png" except: pass def mark_quiz(self): for index in range(10): if self.answers[index][0] == "" and self.answers[index][1] == "": if self.answers[index][2] == self.listify(np.round(self.questions[index].answer_matrix, 0)): self.questions_right.append(index+1) else: if self.answers[index][2] == self.listify(self.questions[index].answer_matrix)[:-1]: self.questions_right.append(self.questions[index].num) S.current_quiz.set_time(int(time.time())) questions_done = [str(q.num) for q in self.questions] for i, q in enumerate(questions_done): if int(q) not in self.questions_right: questions_done[i] = q + 'X' else: questions_done[i] = q + 'O' S.current_quiz.write_to(S.current_user.username, S.date, questions_done) self.parent.transition.direction = 'left' self.parent.current = 'ResultsScreen' def get_score(self): if self.questions_right == 0: return 0 else: return len(self.questions_right) def listify(self, array): return str(array.flatten().tolist()).replace("[[", "").replace("]]", "").replace(" ", "").split(".", 1)[0][1:] def cancel_quiz(self): self.reset_details() self.delete_question_png() self.remove_timer() self.parent.transition.direction = 'right' self.parent.current = 'MenuScreen' def remove_timer(self): Clock.unschedule(self.increment_timer) def delete_question_png(self): AB = ["A", "B"] for index in range(10): for x in AB: if os.path.exists("question"+str(index)+x+".png"): os.remove("question"+str(index)+x+".png") def start_timer(self): Clock.schedule_once(self.call_mark_quiz, 600) Clock.schedule_interval(self.increment_timer, 1) def call_mark_quiz(self, dt): self.mark_quiz() def increment_timer(self, dt): self.current_time += 1 self.ids["time_label"].text = "Time: "+str(self.current_time) def pretty(self, a): lines = str(a).replace('[[', '[').replace(']]', ']').replace( " [", "[").replace(" ]", "]").splitlines() stringVersion = "" for l in lines: stringVersion += l + '\n' return stringVersion.replace(" ", " ") def render_matrix(self, number, which): mpl.rcParams['font.size'] = 12 mpl.rcParams['figure.figsize'] = [1, 1] matrix_text = self.pretty( self.questions[number].matrices_dict.get(which)) if matrix_text != "None" or None: plt.text(0, 0, matrix_text, color="white") fig = plt.gca() fig.axes.axis('off') plt.savefig(f'question{number}'+which+'.png', transparent=True, bbox_inches='tight', pad_inches=0) for txt in fig.texts: txt.set_visible(False) def draw_questions(self): for question in self.questions: if question.q_type == 1 or question.q_type == 2 or question.q_type == 3: self.render_matrix(self.currently_rendering, "A") self.render_matrix(self.currently_rendering, "B") else: self.render_matrix(self.currently_rendering, "A") self.currently_rendering += 1 class ResultsScreen(Screen): score = 0 def set_score(self): self.score = self.get_score() self.ids['score_label'].text = "Your score was: " + \ str(self.score) + "/10" def get_score(self): temporary_screen = self.manager.get_screen('QuestionScreen') return temporary_screen.get_score() def cancel_quiz(self): temporary_screen = self.manager.get_screen('QuestionScreen') temporary_screen.reset_details() temporary_screen.delete_question_png() temporary_screen.remove_timer() self.parent.transition.direction = 'right' self.parent.current = 'MenuScreen' class Team16App(MDApp): def build(self): self.theme_cls.theme_style = 'Dark' self.theme_cls.primary_palette = 'Amber' pass if __name__ == '__main__': Team16App().run()