Open lopezbec opened 1 month ago
Done
Antes: En la versión anterior del código, el número de lecciones en cada módulo se manejaba manualmente cuando se configuraban los menús de los módulos. El código conocía la cantidad de lecciones porque este número se pasaba explícitamente como un parámetro al momento de configurar cada módulo.
Ejemplo del Código Anterior:
self.modulo1_btn = self.setup_modulos_menu("Modulo 1", 5)
self.modulo2_btn = self.setup_modulos_menu("Modulo 2", 3)
self.modulo3_btn = self.setup_modulos_menu("Modulo 3", 5)
self.modulo4_btn = self.setup_modulos_menu("Modulo 4", 5)
self.modulo5_btn = self.setup_modulos_menu("Modulo 5", 7)
Ahora: Con la implementación de identificadores únicos para cada módulo, hemos centralizado la configuración de los módulos y el manejo del número de lecciones. Ahora, toda la información relevante (nombre del módulo y número de lecciones) se encapsula en un solo objeto o diccionario. Esto no solo mejora la claridad y la mantenibilidad del código, sino que también reduce la posibilidad de errores.
# Definir módulos con identificadores únicos
self.modulos = {
"modulo_1": {"nombre": "Módulo 1", "lecciones": 5},
"modulo_2": {"nombre": "Módulo 2", "lecciones": 3},
"modulo_3": {"nombre": "Módulo 3", "lecciones": 5},
"modulo_4": {"nombre": "Módulo 4", "lecciones": 5},
"modulo_5": {"nombre": "Módulo 5", "lecciones": 7}
}
# Crear botones de módulos basados en identificadores únicos
self.modulo1_btn = self.setup_modulos_menu("modulo_1")
self.modulo2_btn = self.setup_modulos_menu("modulo_2")
self.modulo3_btn = self.setup_modulos_menu("modulo_3")
self.modulo4_btn = self.setup_modulos_menu("modulo_4")
self.modulo5_btn = self.setup_modulos_menu("modulo_5")
Ventajas:
1. setup_modulos_menu
Antes:
def setup_modulos_menu(self, nombre_modulo, numero_lecciones):
modulos_btn = QtWidgets.QToolButton()
modulos_btn.setText(nombre_modulo)
modulos_btn.setStyleSheet(
f"""
background-color: {self.styles['submit_button_color']};
font-size: {self.styles['font_size_buttons']}px;
border: 2px solid black;
border-radius: 10px;
padding: 5px;
"""
)
modulos_btn.setFixedSize(171, 80) # Ajusta el tamaño (ancho, alto)
modulos_menu = QtWidgets.QMenu()
self.añadir_submenu(nombre_modulo, numero_lecciones, modulos_menu)
modulos_btn.setMenu(modulos_menu)
modulos_btn.setPopupMode(QtWidgets.QToolButton.ToolButtonPopupMode.InstantPopup)
return modulos_btn
Ahora:
def setup_modulos_menu(self, id_modulo):
datos_modulo = self.modulos[id_modulo]
modulos_btn = QtWidgets.QToolButton()
modulos_btn.setText(datos_modulo["nombre"])
modulos_btn.setStyleSheet(
f"""
background-color: {self.styles['submit_button_color']};
font-size: {self.styles['font_size_buttons']}px;
border: 2px solid black;
border-radius: 10px;
padding: 5px;
"""
)
modulos_btn.setFixedSize(171, 80) # Ajusta el tamaño (ancho, alto)
modulos_menu = QtWidgets.QMenu()
self.añadir_submenu(id_modulo, modulos_menu)
modulos_btn.setMenu(modulos_menu)
modulos_btn.setPopupMode(QtWidgets.QToolButton.ToolButtonPopupMode.InstantPopup)
return modulos_btn
2. añadir_submenu
Antes:
def añadir_submenu(self, nombre_modulo, numero_lecciones, boton_modulo):
estado_modulo = self.progreso_usuario.get(nombre_modulo.replace(" ", ""), {})
estado_completado = self.load_lesson_completed(self.usuario_actual)
for leccion_numero in range(1, numero_lecciones + 1):
leccion_clave = f"Leccion{leccion_numero}"
estado_leccion = estado_modulo.get(leccion_clave, False)
leccion_completada = estado_completado.get(nombre_modulo.replace(" ", ""), {}).get(
f"Leccion_completada{leccion_numero}", False)
if leccion_completada:
icono = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Icons', 'completado_icon.png')
elif estado_leccion:
icono = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Icons', 'abierto_icon.png')
else:
icono = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Icons', 'cerrado_icon.jpg')
accion_leccion = QAction(f"Lección {leccion_numero}", self)
accion_leccion.setIcon(QIcon(icono))
accion_leccion.triggered.connect(lambda _, n=leccion_numero, m=nombre_modulo: self.abrir_leccion(m, n))
boton_modulo.addAction(accion_leccion)
Ahora:
def añadir_submenu(self, id_modulo, boton_modulo):
datos_modulo = self.modulos[id_modulo]
estado_modulo = self.progreso_usuario.get(id_modulo, {})
estado_completado = self.load_lesson_completed(self.usuario_actual)
for leccion_numero in range(1, datos_modulo["lecciones"] + 1):
leccion_clave = f"Leccion{leccion_numero}"
estado_leccion = estado_modulo.get(leccion_clave, False)
leccion_completada = estado_completado.get(id_modulo, {}).get(f"Leccion_completada{leccion_numero}", False)
if leccion_completada:
icono = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Icons', 'completado_icon.png')
elif estado_leccion:
icono = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Icons', 'abierto_icon.png')
else:
icono = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'Icons', 'cerrado_icon.jpg')
accion_leccion = QAction(f"Lección {leccion_numero}", self)
accion_leccion.setIcon(QIcon(icono))
accion_leccion.triggered.connect(lambda _, n=leccion_numero, m=id_modulo: self.abrir_leccion(m, n))
boton_modulo.addAction(accion_leccion)
3. abrir_leccion
Antes:
def abrir_leccion(self, nombre_modulo, numero_leccion):
# Lógica basada en nombre_modulo
if nombre_modulo == "Modulo 1":
# Código para abrir lecciones de Modulo 1
elif nombre_modulo == "Modulo 2":
# Código para abrir lecciones de Modulo 2
# Continúa para los demás módulos
Ahora:
def abrir_leccion(self, id_modulo, numero_leccion):
try:
if id_modulo == "modulo_1":
# Código para abrir lecciones de modulo_1
elif id_modulo == "modulo_2":
# Código para abrir lecciones de modulo_2
# Continúa para los demás módulos
except Exception as e:
print(f"Error al abrir {id_modulo} - Lección {numero_leccion}: {e}")
print(f"Error en línea {sys.exc_info()[2].tb_lineno}")
4. actualizar_lecciones
Antes:
def actualizar_lecciones(self, estado_usuario):
# Modulo 1
self.estado_lecciones = {
"Modulo1": {
"Leccion1": estado_usuario.get("Modulo1", {}).get("Leccion1", False),
"Leccion2": estado_usuario.get("Modulo1", {}).get("Leccion2", False),
"Leccion3": estado_usuario.get("Modulo1", {}).get("Leccion3", False),
"Leccion4": estado_usuario.get("Modulo1", {}).get("Leccion4", False),
"Leccion5": estado_usuario.get("Modulo1", {}).get("Leccion5", False),
},
# Continúa para los demás módulos
}
Ahora:
def actualizar_lecciones(self, estado_usuario):
# Módulo 1
self.estado_lecciones = {
"modulo_1": {
"Leccion1": estado_usuario.get("modulo_1", {}).get("Leccion1", False),
"Leccion2": estado_usuario.get("modulo_1", {}).get("Leccion2", False),
"Leccion3": estado_usuario.get("modulo_1", {}).get("Leccion3", False),
"Leccion4": estado_usuario.get("modulo_1", {}).get("Leccion4", False),
"Leccion5": estado_usuario.get("modulo_1", {}).get("Leccion5", False),
},
# Continúa para los demás módulos
}
Para soportar el uso de identificadores únicos (id_modulo), también fue necesario modificar la estructura de los archivos JSON utilizados en el proyecto.
1. progreso.json:
2. leccion_completada.json:
Nueva Estructura de los Archivos JSON
{
"Daniel": {
"modulo_1": {
"Leccion_completada1": true,
"Leccion_completada2": true,
"Leccion_completada3": true,
"Leccion_completada4": true,
"Leccion_completada5": true
},
"modulo_2": {
"Leccion_completada1": true,
"Leccion_completada2": true,
"Leccion_completada3": true
},
"modulo_3": {
"Leccion_completada1": true,
"Leccion_completada2": true,
"Leccion_completada3": true,
"Leccion_completada4": true,
"Leccion_completada5": true
},
"modulo_4": {
"Leccion_completada1": true,
"Leccion_completada2": true,
"Leccion_completada3": true,
"Leccion_completada4": true,
"Leccion_completada5": true
},
"modulo_5": {
"Leccion_completada1": true,
"Leccion_completada2": true,
"Leccion_completada3": true,
"Leccion_completada4": true,
"Leccion_completada5": true,
"Leccion_completada6": true,
"Leccion_completada7": true
}
}
}
actualizar_progreso_usuario - Código Anterior
def actualizar_progreso_usuario(self, modulo, leccion_completada):
try:
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'progreso.json'), 'r', encoding='UTF-8') as file:
progreso = json.load(file)
progreso_usuario = progreso.get(self.usuario_actual, {})
# Calcula el número de la siguiente lección para desbloquearla en progreso.json
numero_leccion_actual = int(leccion_completada.replace("Leccion", ""))
siguiente_leccion = f'Leccion{numero_leccion_actual + 1}'
if modulo in progreso_usuario:
progreso_usuario[modulo][siguiente_leccion] = True # Desbloquea la siguiente lección
with open(os.path.join(os.path.dirname(os.path.abspath(__file__))), 'progreso.json'), 'w', encoding='UTF-8') as file:
json.dump(progreso, file, indent=4)
except Exception as e:
print(f"Error al actualizar el progreso: {e}")
actualizar_progreso_usuario - Código Nuevo
def actualizar_progreso_usuario(self, id_modulo, leccion_completada):
try:
with open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'progreso.json'), 'r', encoding='UTF-8') as file:
progreso = json.load(file)
progreso_usuario = progreso.get(self.usuario_actual, {})
# Calcula el número de la siguiente lección para desbloquearla en progreso.json
numero_leccion_actual = int(leccion_completada.replace("Leccion", ""))
siguiente_leccion = f'Leccion{numero_leccion_actual + 1}'
if id_modulo in progreso_usuario:
progreso_usuario[id_modulo][siguiente_leccion] = True # Desbloquea la siguiente lección
with open(os.path.join(os.path.dirname(os.path.abspath(__file__))), 'progreso.json'), 'w', encoding='UTF-8') as file:
json.dump(progreso, file, indent=4)
except Exception as e:
print(f"Error al actualizar el progreso: {e}")
actualizar_leccion_completada - Código Anterior
def actualizar_leccion_completada(self, modulo, leccion_completada):
try:
with open(os.path.join(os.path.dirname(os.path.abspath(__file__))), 'leccion_completada.json'), 'r', encoding='UTF-8') as file:
leccion_completada_data = json.load(file)
leccion_completada_usuario = leccion_completada_data.get(self.usuario_actual, {})
# Marca la lección actual como completada en leccion_completada.json
if modulo not in leccion_completada_usuario:
leccion_completada_usuario[modulo] = {}
leccion_completada_usuario[modulo][f"Leccion_completada{leccion_completada.replace('Leccion', '')}"] = True
leccion_completada_data[self.usuario_actual] = leccion_completada_usuario
with open(os.path.join(os.path.dirname(os.path.abspath(__file__))), 'leccion_completada.json'), 'w', encoding='UTF-8') as file:
json.dump(leccion_completada_data, file, indent=4)
except Exception as e:
print(f"Error al actualizar lección completada: {e}")
actualizar_leccion_completada - Código Nuevo
def actualizar_leccion_completada(self, id_modulo, leccion_completada):
try:
with open(os.path.join(os.path.dirname(os.path.abspath(__file__))), 'leccion_completada.json'), 'r', encoding='UTF-8') as file:
leccion_completada_data = json.load(file)
leccion_completada_usuario = leccion_completada_data.get(self.usuario_actual, {})
# Marca la lección actual como completada en leccion_completada.json
if id_modulo not in leccion_completada_usuario:
leccion_completada_usuario[id_modulo] = {}
leccion_completada_usuario[id_modulo][f"Leccion_completada{leccion_completada.replace('Leccion', '')}"] = True
leccion_completada_data[self.usuario_actual] = leccion_completada_usuario
with open(os.path.join(os.path.dirname(os.path.abspath(__file__))), 'leccion_completada.json'), 'w', encoding='UTF-8') as file:
json.dump(leccion_completada_data, file, indent=4)
except Exception as e:
print(f"Error al actualizar lección completada: {e}")
switch_page - Código Anterior
def switch_page(self, forward=True):
current_index = self.stacked_widget.currentIndex()
if forward:
next_index = current_index + 1
else:
self.submit_button.hide()
self.continue_button.show()
next_index = current_index - 1
current_page_type = self.stacked_widget.currentWidget().page_type.lower() # Obtener el tipo de página actual
self.log_event(
f"{current_page_type.capitalize()} Page Close Time") # Registrar el evento de cierre de la página actual
current_widget = self.stacked_widget.currentWidget()
if hasattr(current_widget, "lesson_completed"):
self.lesson_finished_successfully = True
# Si el siguiente índice es menor que el número total de páginas, continuar navegando
if next_index < self.stacked_widget.count():
if forward:
self.update_highest_page(next_index)
next_index = current_index + 1
self.XP_Ganados += 1
self.progress_bar.increment_page()
else:
self.is_rollback = True
self.submit_button.hide()
self.continue_button.show()
next_index = current_index - 1
self.XP_Ganados -= 1
self.progress_bar.decrement_page()
# Antes de cambiar de página, añadimos un punto y log para debug.
self.stacked_widget.setCurrentIndex(next_index) # Cambiar a la siguiente página
self.log_part_change() # Registrar el cambio a la "Parte 1"
current_page_type = self.stacked_widget.currentWidget().page_type.lower() # Obtener el tipo de página actualizado
self.log_event(
f"{current_page_type.capitalize()} Page Open Time") # Registrar el evento de apertura de la nueva página
if current_page_type == "pedagogical" or current_page_type == "pedagogical2":
self.SubmitHideContinueShow(True,
False) # Si la nueva página es una pregunta, mostrar el botón de envío y ocultar el botón de continuar
elif current_page_type == "practica":
self.SubmitHideContinueShow(False,
True) # Si la nueva página no es una pregunta, y es práctica, ocultar el botón de envío y el de continuar, y mostrar el de practica
else:
self.SubmitHideContinueShow(False,
False) # Si la nueva página no es una pregunta, ocultar el botón de envío y mostrar el botón de continuar
if not forward:
self.submit_button.hide()
self.continue_button.show()
self.back_button.hide()
# Sí se alcanza el final del recorrido de páginas, guardar el registro y cerrar la aplicación
elif not next_index < self.stacked_widget.count():
self.continue_button.hide()
self.terminar_button.show()
self.save_log(modulo=1, leccion=1)
self.XP_Ganados += 5 # 5 puntos por terminar la lección.
self.actualizar_puntos_en_leaderboard(self.usuario_actual, self.XP_Ganados)
self.actualizar_progreso_usuario('Modulo1', 'Leccion1')
self.actualizar_leccion_completada('Modulo1', 'Leccion1')
update_lesson_status(self.usuario_actual, 'Modulo1', 'Leccion1', self.all_correct)
if self.streak.get_current_streak() > 0:
update_streak(self.usuario_actual, self.streak.get_current_streak())
#Badge verification correct anwers streak
check_streak_badges(int(read_stored_streak(self.usuario_actual)), self.usuario_actual)
get_badge_level(self, score=self.leaderboard_window_instace.get_current_user_score() + self.XP_Ganados)
update_lesson_dates(self.usuario_actual, "Modulo1", "Leccion_completada1")
if are_lessons_completed_same_day(self.usuario_actual, "Modulo1") and not is_badge_earned(self.usuario_actual, 'modulo_rapido'):
display_badge('modulo_rapido')
update_badge_progress(self.usuario_actual, 'modulo_rapido')
if are_two_lessons_completed_same_day(self.usuario_actual, "Modulo1") and not is_badge_earned(self.usuario_actual, 'doble_aprendizaje'):
display_badge('doble_aprendizaje')
update_badge_progress(self.usuario_actual, 'doble_aprendizaje')
if are_three_modules_completed(self.usuario_actual) and not is_badge_earned(self.usuario_actual, 'Explorador_curioso'):
display_badge('Explorador_curioso')
update_badge_progress(self.usuario_actual, 'Explorador_curioso')
if check_module_streak_per_user(self.usuario_actual) and not is_badge_earned(self.usuario_actual, 'dominador_modulo'):
display_badge('dominador_modulo')
update_badge_progress(self.usuario_actual, 'dominador_modulo')
self.close()
else:
print("¡La leccion no se completó, se cerró!.")
self.close()
switch_page - Código Nuevo
def switch_page(self, forward=True):
current_index = self.stacked_widget.currentIndex()
if forward:
next_index = current_index + 1
else:
self.submit_button.hide()
self.continue_button.show()
next_index = current_index - 1
current_page_type = self.stacked_widget.currentWidget().page_type.lower() # Obtener el tipo de página actual
self.log_event(
f"{current_page_type.capitalize()} Page Close Time") # Registrar el evento de cierre de la página actual
current_widget = self.stacked_widget.currentWidget()
if hasattr(current_widget, "lesson_completed"):
self.lesson_finished_successfully = True
# Si el siguiente índice es menor que el número total de páginas, continuar navegando
if next_index < self.stacked_widget.count():
if forward:
self.update_highest_page(next_index)
next_index = current_index + 1
self.XP_Ganados += 1
self.progress_bar.increment_page()
else:
self.is_rollback = True
self.submit_button.hide()
self.continue_button.show()
next_index = current_index - 1
self.XP_Ganados -= 1
self.progress_bar.decrement_page()
# Cambiar a la siguiente página
self.stacked_widget.setCurrentIndex(next_index)
self.log_part_change() # Registrar el cambio a la "Parte 1"
current_page_type = self.stacked_widget.currentWidget().page_type.lower() # Obtener el tipo de página actualizado
self.log_event(
f"{current_page_type.capitalize()} Page Open Time") # Registrar el evento de apertura de la nueva página
if current_page_type == "pedagogical" or current_page_type == "pedagogical2":
self.SubmitHideContinueShow(True, False) # Mostrar el botón de envío y ocultar el botón de continuar
elif current_page_type == "practica":
self.SubmitHideContinueShow(False, True) # Mostrar el botón de práctica y ocultar los demás
else:
self.SubmitHideContinueShow(False, False) # Mostrar el botón de continuar y ocultar el botón de envío
if not forward:
self.submit_button.hide()
self.continue_button.show()
self.back_button.hide()
# Sí se alcanza el final del recorrido de páginas, guardar el registro y cerrar la aplicación
elif not next_index < self.stacked_widget.count():
self.continue_button.hide()
self.terminar_button.show()
id_modulo = "modulo_1"
leccion = f"Leccion{self.lesson_number}"
self.save_log(modulo=id_modulo, leccion=self.lesson_number)
self.XP_Ganados += 5 # 5 puntos por terminar la lección.
self.actualizar_puntos_en_leaderboard(self.usuario_actual, self.XP_Ganados)
self.actualizar_progreso_usuario(id_modulo, leccion)
self.actualizar_leccion_completada(id_modulo, leccion)
update_lesson_status(self.usuario_actual, id_modulo, leccion, self.all_correct)
if self.streak.get_current_streak() > 0:
update_streak(self.usuario_actual, self.streak.get_current_streak())
# Verificación de insignias y actualizaciones
check_streak_badges(int(read_stored_streak(self.usuario_actual)), self.usuario_actual)
get_badge_level(self, score=self.leaderboard_window_instace.get_current_user_score() + self.XP_Ganados)
update_lesson_dates(self.usuario_actual, id_modulo, f"Leccion_completada{self.lesson_number}")
if are_lessons_completed_same_day(self.usuario_actual, id_modulo) and not is_badge_earned(
self.usuario_actual, 'modulo_rapido'):
display_badge('modulo_rapido')
update_badge_progress(self.usuario_actual, 'modulo_rapido')
if are_two_lessons_completed_same_day(self.usuario_actual, id_modulo) and not is_badge_earned(
self.usuario_actual, 'doble_aprendizaje'):
display_badge('doble_aprendizaje')
update_badge_progress(self.usuario_actual, 'doble_aprendizaje')
if are_three_modules_completed(self.usuario_actual) and not is_badge_earned(self.usuario_actual,
'Explorador_curioso'):
display_badge('Explorador_curioso')
update_badge_progress(self.usuario_actual, 'Explorador_curioso')
if check_module_streak_per_user(self.usuario_actual) and not is_badge_earned(self.usuario_actual,
'dominador_modulo'):
display_badge('dominador_modulo')
update_badge_progress(self.usuario_actual, 'dominador_modulo')
self.close()
else:
print("¡La lección no se completó, se cerró!.")
self.close()
if next_index == self.highest_page_reached and self.is_rollback:
self.is_rollback = False
self.json_windows[next_index].reset_button()
self.current_page += 1 # Incrementar el número de la página actual
# Verificación de insignias para la primera respuesta correcta
if self.current_page == 2 and not is_badge_earned(self.usuario_actual, 'gran_paso'):
if self.XP_Ganados > 0 and self.XP_Ganados <= 4:
display_badge('gran_paso')
update_badge_progress(self.usuario_actual, 'gran_paso')
en cada Main de las leccion recordar modificar la variable.
id_modulo = "modulo_1"
We need to add the accent to the word "modulo" in the app. I was trying to fix it by changing all the strings that show as "Modulo" in the "Main_Modules_Intro.py" file, but it looks like the file/logic that controls when the lesson and modules are open, also assumes the work without accent. (this is a very low priority)
@Elmerluis0129 , you might be better suited for this since I think the "lock" logic script/files might need to be updates as well