#----------------------------------------------------------------------------------------------------#
#                                                                                                    #
#                                               Imports                                              #
#                                                                                                    #
#----------------------------------------------------------------------------------------------------#

#******** Kivy ********
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.properties import StringProperty, ObjectProperty
from kivy.uix.gridlayout import GridLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivymd.uix.button import MDFlatButton
from kivymd.uix.dialog import MDDialog
from kivy.core.window import Window
from kivy.utils import get_color_from_hex
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivymd.uix.button import MDIconButton,MDFillRoundFlatButton
from kivymd.uix.boxlayout import MDBoxLayout
from kivy.metrics import dp
from kivy.clock import Clock
from kivy.storage.jsonstore import JsonStore
from kivy.uix.screenmanager import RiseInTransition,SlideTransition
from kivy.utils import platform
from kivymd.uix.textfield import MDTextField
from kivymd.uix.label import MDLabel
from kivymd.uix.selectioncontrol import MDCheckbox

#******** OS/Others ********
import socket
from urllib.request import Request, urlopen, URLError, HTTPError
import urllib.parse
import os
from os import path
from os import remove
import sys
import json
import random
from datetime import datetime
from datetime import timedelta

# Check de Plataforma en el arranque
if platform == 'android':
    from jnius import autoclass
    from android.permissions import request_permissions, Permission
    def request_permission_callback(permission, results):
        if all([res for res in results]):
            print("Permiso concedido.")
        else:
            print("Permiso denegado.")
    request_permissions([Permission.WRITE_EXTERNAL_STORAGE], callback=request_permission_callback)

#----------------------------------------------------------------------------------------------------#
#                                                                                                    #
#                                          Design App Kv                                             #
#                                                                                                    #
#----------------------------------------------------------------------------------------------------#

KV = '''
#:import Factory kivy.factory.Factory
#:import RiseInTransition kivy.uix.screenmanager.RiseInTransition
#:import SlideTransition kivy.uix.screenmanager.SlideTransition
<ElementCard@MDCard>:
    radius:'10px'
    spacing: '10px'
    padding: '10px'
    image: ''
    text: ''
    sub_text: ''
    orientation: 'vertical'
    ripple_behavior: True
    on_release:
        app.root.transition = RiseInTransition()
    Image: 
        source: root.image
    MDBoxLayout:
        orientation: 'vertical'
        MDLabel:
            text: root.text
            halign: 'center'
        MDLabel:
            text: root.sub_text
            halign: 'center'

<HabsView>:
    cols: 6
    rango: ''
    id_hab: ''
    estado: ''
    eos_val: ''
    hora_val: ''
    pax: ''
    dias_vacia: ''
    estado_libre: ''
    color: ''

    Button:
        id: id_hab
        halign: "center"
        size_hint: 0.20, 0
        bold: True
        font_size: '30sp'
        text: root.id_hab
        background_color: [0,0,0,0]
        on_release: app.abrir_hab(root.id_hab,root)
        #color: "#191A1A"
        canvas.before:
            Color:
                rgba: app.color_turquesa if root.eos_val == 'BLO' else app.color_rojo if root.color == '1' else app.color_verde
            RoundedRectangle:
                pos: self.pos
                size: self.size
                radius: [dp(12)]
    MDLabel:
        id: rango
        size_hint: 0.1, 0
        halign: "center"
        text: root.rango
    MDLabel:
        id: eos_val
        size_hint: 0.1, 0
        halign: "center"
        text: root.eos_val
    MDLabel:
        id: hora_val
        size_hint: 0.3, 0
        halign: "center"
        text: root.hora_val
    MDLabel:
        id: pax
        size_hint: 0.15, 0
        halign: "center"
        text: root.pax
    Label:
        id: dias_vacia
        size_hint_x: None
        width: dp(65)
        halign: "center"
        text: root.estado_libre if root.estado_libre != '0' else "Libre: " + root.dias_vacia + "d" if root.dias_vacia != '0' else " "
        color: "red"
        bold: True

<ParteView>:
    cols: 4
    id: ''
    hab: ''
    zona: ''
    apertura: ''
    estado: ''
    urgente: ''
    critico: ''
    hora: ''
    asunto: ''
    asignado: ''
    color: ''

    Button:
        id: hab
        halign: "center"
        size_hint: 0.15, 0
        bold: True
        font_size: '25sp'
        text: app.separar_texto(root.hab if root.hab != '' else root.zona, 6)
        background_color: [0,0,0,0]
        on_release: app.abrir_parte(root.id,root)
        canvas.before:
            Color:
                rgba: app.color_rojo if root.color == '1' else app.color_verde if root.color == '0' else app.color_turquesa
            RoundedRectangle:
                pos: self.pos
                size: self.size
                radius: [dp(12)]
    MDLabel:
        id: asunto
        size_hint: 0.15, 0
        halign: "center"
        color: app.color_naranja if root.asignado != '0' else (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
        markup: True
        text: root.asunto if root.asignado == '0' else root.asignado + "\\n" + root.asunto
    MDLabel:
        id: apertura
        size_hint: 0.2, 0
        halign: "center"
        text: root.apertura + "\\n" + root.hora
        markup: True
    Label:
        id: dias_vacia
        size_hint_x: None
        width: dp(65)
        halign: "center"
        text: "URGENTE" if root.urgente != '0' else "CRÍTICO" if root.critico != '0' else ""
        color: "red"
        bold: True

ScreenManager:
    MDScreen:
        name: 'screen_principal'
        md_bg_color: app.color_azul
        MDBoxLayout:
            orientation: 'vertical'
            
            Image:
                id: wifi_img
                source: 'img/no-wifi.png'
                size_hint: 0.2,0.15
                pos_hint: {"right": 1}
                opacity: 0

            Image:
                source: 'img/globales.png'
                size_hint: 1,0.35

            MDBoxLayout:
                size_hint: 1, .3
                orientation: 'horizontal'
                padding: '10px'
                MDCard:
                    radius:'5px'
                    padding:'10px'
                    MDBoxLayout:
                        orientation: 'vertical'
                        spacing: '0.5px'
                        MDLabel:
                            id: centro
                            text: "###### (0)"
                            bold: True
                            pos_hint: {'center_x': 0.5}
                        MDLabel:
                            id: perfil
                            text: "##### - #####"
                            pos_hint: {'center_x': 0.5}
                        MDLabel:
                            id: hora
                            text: "##:## - ##/##/####"
                            pos_hint: {'center_x': 0.5}
                        MDBoxLayout:
                            orientation: 'horizontal'
                            spacing: '0.5px'
                            pos_hint: {'center_x': 0.5}
                            MDLabel:
                                id: sent
                                text: "Envios: #"
                                
                            MDLabel:
                                id: wifi
                                text: ""
                                color: "red"
                                bold: True
                                
                    MDBoxLayout:
                        orientation: 'vertical'
                        spacing: '0.5px'
                        MDLabel:
                            id: modo_app
                            text: "Cambiar Estilo"
                            halign: 'center'
                        MDSwitch:
                            id: switch
                            widget_style: "ios"
                            pos_hint: {'center_x': 0.5}
                            valign: "top"
                            on_active:
                                app.show_change_dialog()
                                
            MDGridLayout:
                cols: 2
                size_hint: 1, 0.5
                padding: '10px'
                spacing: '10px'
                MDCard:
                    radius:'10px'
                    padding: '10px'
                    orientation: 'vertical'
                    ripple_behavior: True
                    on_release:
                        app.root.transition = RiseInTransition()
                        root.current = 'screen_gobernanta'
                        app.cargaDatosGober()
                    Image: 
                        source: 'img/gobernanta.png'
                    MDBoxLayout:
                        orientation: 'vertical'
                        MDLabel:
                            text: 'Gobernanta'
                            halign: 'center'
                MDCard:
                    radius:'10px'
                    padding: '10px'
                    orientation: 'vertical'
                    ripple_behavior: True
                    on_release:
                        app.root.transition = RiseInTransition()
                        root.current = 'screen_partes'
                        app.cargaDatosParte()
                    Image: 
                        source: 'img/partes.png'
                    MDBoxLayout:
                        orientation: 'vertical'
                        MDLabel:
                            text: 'Partes'
                            halign: 'center'

                MDCard:
                    radius:'10px'
                    padding: '10px'
                    orientation: 'vertical'
                    ripple_behavior: True
                    on_release:
                        app.root.transition = RiseInTransition()
                        app.recargar_datos_gober_buton(1)
                        app.cargadoGober = False
                        app.cargadoPartes = False
                    Image: 
                        source: 'img/actualizar.png'
                    MDBoxLayout:
                        orientation: 'vertical'
                        MDLabel:
                            text: 'Actualizar Datos'
                            halign: 'center'

                MDCard:
                    radius:'10px'
                    padding: '10px'
                    orientation: 'vertical'
                    ripple_behavior: True
                    on_release:
                        app.root.transition = RiseInTransition()
                        root.current = 'screen_ajustes'
                    Image: 
                        source: 'img/ajustes.png'
                    MDBoxLayout:
                        orientation: 'vertical'
                        MDLabel:
                            text: 'Ajustes'
                            halign: 'center'
    MDScreen:
        name: 'screen_gobernanta'
        MDBottomNavigation:
            MDBottomNavigationItem:
                name: "todas_habs"
                text: "Todas"
                icon: "alpha-t-box"
                MDFillRoundFlatButton:
                    text: 'Volver'
                    pos_hint: {'top': 0.97, 'x': 0.04}
                    font_size: "20sp"
                    on_release:
                        app.root.current = 'screen_principal'
                        app.root.transition = SlideTransition(direction='right')
                MDFlatButton:
                    id: filter_selected
                    text: 'Ordenado por: Habitacion'
                    pos_hint: {'top': 0.97, 'x': 0.28}
                MDFillRoundFlatButton:
                    text: 'Ordenar'
                    pos_hint: {'top': 0.97, 'x': 0.72}
                    font_size: "20sp"
                    on_release:
                        app.show_dropdown()
                
                MDBoxLayout:
                    size_hint: 0.95, 0.15
                    orientation: "horizontal"
                    pos_hint: {'top': 1, "center_x": .5}
                    padding: ['10px', '0px','10px', '0px']
                    spacing: 3
                    MDTextField:
                        mode: "round"
                        halign: "left"
                        valign: "center"
                        id: filtro_habs
                        size_hint: 1,0.32
                        hint_text: "Filtrar por Habitacion"
                        on_text: app.filtro_habs(filtro_habs.text,'Habs')
                    MDTextField:
                        mode: "round"
                        halign: "left"
                        valign: "center"
                        id: filtro_rango
                        size_hint: 1,0.32
                        hint_text: "Filtrar por Rango"
                        on_text: app.filtro_rango(filtro_rango.text,'Rango')
                    MDIconButton:
                        id: borrar_filtros
                        icon: "trash-can-outline"
                        size_hint: 0.32,0.32
                        on_press:
                            app.borrar_filtros(self)

                MDBoxLayout:
                    size_hint: 0.95, 0.83
                    orientation: "vertical"
                    pos_hint: {'top': 0.84, "center_x": .5}
                    padding: ['10px', '0px','10dp', '0px']
                    spacing: 3
                    RecycleView:
                        id: recycle_view
                        data: []
                        viewclass: 'HabsView'
                        RecycleBoxLayout:
                            default_size_hint: 1, None
                            default_height: '45dp'
                            padding: ['0px', '0px','0px', '0px']
                            spacing: 5
                            orientation: 'vertical'
                            size_hint_y: None
                            height: self.minimum_height

            MDBottomNavigationItem:
                id: entradas
                name: "ent_habs"
                text: "Entradas"
                icon: "alpha-e-box"
                MDFillRoundFlatButton:
                    text: 'Volver'
                    pos_hint: {'top': 0.97, 'x': 0.04}
                    font_size: "20sp"
                    on_release:
                        app.root.current = 'screen_principal'
                        app.root.transition = SlideTransition(direction='right')
                MDFlatButton:
                    id: filter_selected_entr
                    text: 'Ordenado por: Habitacion'
                    pos_hint: {'top': 0.97, 'x': 0.28}
                MDFillRoundFlatButton:
                    text: 'Ordenar'
                    pos_hint: {'top': 0.97, 'x': 0.72}
                    font_size: "20sp"
                    on_release:
                        app.show_dropdown()
                
                MDBoxLayout:
                    size_hint: 0.95, 0.15
                    orientation: "horizontal"
                    pos_hint: {'top': 1, "center_x": .5}
                    padding: ['10px', '0px','10px', '0px']
                    spacing: 3
                    MDTextField:
                        mode: "round"
                        halign: "left"
                        valign: "center"
                        id: filtro_habs_entr
                        size_hint: 1,0.32
                        hint_text: "Filtrar por Habitacion"
                        on_text: app.filtro_habs_entr(filtro_habs_entr.text,'Habs')
                    MDTextField:
                        mode: "round"
                        halign: "left"
                        valign: "center"
                        id: filtro_rango_entr
                        size_hint: 1,0.32
                        hint_text: "Filtrar por Rango"
                        on_text: app.filtro_habs_entr(filtro_rango_entr.text,'Rango')
                    MDIconButton:
                        id: borrar_filtros
                        icon: "trash-can-outline"
                        size_hint: 0.32,0.32
                        on_press:
                            app.borrar_filtros(self)

                MDBoxLayout:
                    size_hint: 0.95, 0.83
                    orientation: "vertical"
                    pos_hint: {'top': 0.84, "center_x": .5}
                    padding: ['10px', '0px','10dp', '0px']
                    spacing: 3
                    RecycleView:
                        id: recycle_view_entr
                        data: []
                        viewclass: 'HabsView'
                        RecycleBoxLayout:
                            default_size_hint: 1, None
                            default_height: '45dp'
                            padding: ['10px', '0px','10px', '0px']
                            spacing: 5
                            orientation: 'vertical'
                            size_hint_y: None
                            height: self.minimum_height

            MDBottomNavigationItem:
                id: salidas
                name: "sal_habs"
                text: "Salidas"
                icon: "alpha-s-box"
                MDFillRoundFlatButton:
                    text: 'Volver'
                    pos_hint: {'top': 0.97, 'x': 0.04}
                    font_size: "20sp"
                    on_release:
                        app.root.current = 'screen_principal'
                        app.root.transition = SlideTransition(direction='right')
                MDFlatButton:
                    id: filter_selected_sal
                    text: 'Ordenado por: Habitacion'
                    pos_hint: {'top': 0.97, 'x': 0.28}
                MDFillRoundFlatButton:
                    text: 'Ordenar'
                    pos_hint: {'top': 0.97, 'x': 0.72}
                    font_size: "20sp"
                    on_release:
                        app.show_dropdown()
                
                MDBoxLayout:
                    size_hint: 0.95, 0.15
                    orientation: "horizontal"
                    pos_hint: {'top': 1, "center_x": .5}
                    padding: ['10px', '0px','10px', '0px']
                    spacing: 3
                    MDTextField:
                        mode: "round"
                        halign: "left"
                        valign: "center"
                        id: filtro_habs_sal
                        size_hint: 1,0.32
                        hint_text: "Filtrar por Habitacion"
                        on_text: app.filtro_habs_sal(filtro_habs_sal.text,'Habs')
                    MDTextField:
                        mode: "round"
                        halign: "left"
                        valign: "center"
                        id: filtro_rango_sal
                        size_hint: 1,0.32
                        hint_text: "Filtrar por Rango"
                        on_text: app.filtro_rango_sal(filtro_rango_sal.text,'Rango')
                    MDIconButton:
                        id: borrar_filtros
                        icon: "trash-can-outline"
                        size_hint: 0.32,0.32
                        on_press:
                            app.borrar_filtros(self)

                MDBoxLayout:
                    size_hint: 0.95, 0.83
                    orientation: "vertical"
                    pos_hint: {'top': 0.84, "center_x": .5}
                    padding: ['10px', '0px','10dp', '0px']
                    spacing: 3
                    RecycleView:
                        id: recycle_view_sal
                        data: []
                        viewclass: 'HabsView'
                        RecycleBoxLayout:
                            default_size_hint: 1, None
                            default_height: '45dp'
                            padding: ['10px', '0px','10px', '0px']
                            spacing: 5
                            orientation: 'vertical'
                            size_hint_y: None
                            height: self.minimum_height
                            
            MDBottomNavigationItem:
                id: ocupadas
                name: "ocu_habs"
                text: "Ocupadas"
                icon: "alpha-o-box"
                MDFillRoundFlatButton:
                    text: 'Volver'
                    pos_hint: {'top': 0.97, 'x': 0.04}
                    font_size: "20sp"
                    on_release:
                        app.root.current = 'screen_principal'
                        app.root.transition = SlideTransition(direction='right')
                MDFlatButton:
                    id: filter_selected_ocu
                    text: 'Ordenado por: Habitacion'
                    pos_hint: {'top': 0.97, 'x': 0.28}
                MDFillRoundFlatButton:
                    text: 'Ordenar'
                    pos_hint: {'top': 0.97, 'x': 0.72}
                    font_size: "20sp"
                    on_release:
                        app.show_dropdown()
                
                MDBoxLayout:
                    size_hint: 0.95, 0.15
                    orientation: "horizontal"
                    pos_hint: {'top': 1, "center_x": .5}
                    padding: ['10px', '0px','10px', '0px']
                    spacing: 3
                    MDTextField:
                        mode: "round"
                        halign: "left"
                        valign: "center"
                        id: filtro_habs_ocu
                        size_hint: 1,0.32
                        hint_text: "Filtrar por Habitacion"
                        on_text: app.filtro_habs_ocu(filtro_habs_ocu.text,'Habs')
                    MDTextField:
                        mode: "round"
                        halign: "left"
                        valign: "center"
                        id: filtro_rango_ocu
                        size_hint: 1,0.32
                        hint_text: "Filtrar por Rango"
                        on_text: app.filtro_rango_ocu(filtro_rango_ocu.text,'Rango')
                    MDIconButton:
                        id: borrar_filtros
                        icon: "trash-can-outline"
                        size_hint: 0.32,0.32
                        on_press:
                            app.borrar_filtros(self)

                MDBoxLayout:
                    size_hint: 0.95, 0.83
                    orientation: "vertical"
                    pos_hint: {'top': 0.84, "center_x": .5}
                    padding: ['10px', '0px','10dp', '0px']
                    spacing: 3
                    RecycleView:
                        id: recycle_view_ocu
                        data: []
                        viewclass: 'HabsView'
                        RecycleBoxLayout:
                            default_size_hint: 1, None
                            default_height: '45dp'
                            padding: ['10px', '0px','10px', '0px']
                            spacing: 5
                            orientation: 'vertical'
                            size_hint_y: None
                            height: self.minimum_height

            MDBottomNavigationItem:
                id: libres
                name: "lib_habs"
                text: "Libres"
                icon: "alpha-l-box"
                MDFillRoundFlatButton:
                    text: 'Volver'
                    pos_hint: {'top': 0.97, 'x': 0.04}
                    font_size: "20sp"
                    on_release:
                        app.root.current = 'screen_principal'
                        app.root.transition = SlideTransition(direction='right')
                MDFlatButton:
                    id: filter_selected_lib
                    text: 'Ordenado por: Habitacion'
                    pos_hint: {'top': 0.97, 'x': 0.28}
                MDFillRoundFlatButton:
                    text: 'Ordenar'
                    pos_hint: {'top': 0.97, 'x': 0.72}
                    font_size: "20sp"
                    on_release:
                        app.show_dropdown()
                
                MDBoxLayout:
                    size_hint: 0.95, 0.15
                    orientation: "horizontal"
                    pos_hint: {'top': 1, "center_x": .5}
                    padding: ['10px', '0px','10px', '0px']
                    spacing: 3
                    MDTextField:
                        mode: "round"
                        halign: "left"
                        valign: "center"
                        id: filtro_habs_lib
                        size_hint: 1,0.32
                        hint_text: "Filtrar por Habitacion"
                        on_text: app.filtro_habs_lib(filtro_habs_lib.text,'Habs')
                    MDTextField:
                        mode: "round"
                        halign: "left"
                        valign: "center"
                        id: filtro_rango_lib
                        size_hint: 1,0.32
                        hint_text: "Filtrar por Rango"
                        on_text: app.filtro_rango_lib(filtro_rango_lib.text,'Rango')
                    MDIconButton:
                        id: borrar_filtros
                        icon: "trash-can-outline"
                        size_hint: 0.32,0.32
                        on_press:
                            app.borrar_filtros(self)

                MDBoxLayout:
                    size_hint: 0.95, 0.83
                    orientation: "vertical"
                    pos_hint: {'top': 0.84, "center_x": .5}
                    padding: ['10px', '0px','10dp', '0px']
                    spacing: 3
                    RecycleView:
                        id: recycle_view_lib
                        data: []
                        viewclass: 'HabsView'
                        RecycleBoxLayout:
                            default_size_hint: 1, None
                            default_height: '45dp'
                            padding: ['10px', '0px','10px', '0px']
                            spacing: 5
                            orientation: 'vertical'
                            size_hint_y: None
                            height: self.minimum_height
    MDScreen:
        name: 'screen_habitacion'
        MDBoxLayout:
            size_hint: 1,1
            orientation: 'vertical'
            MDBoxLayout:
                padding: [5,10,5,10]
                size_hint: 1,0.2
                orientation: 'horizontal'
                MDLabel:
                    id: hab_num
                    pos_hint: {'top': .7}
                    size_hint: 0.7,0.55
                    bold: True
                    font_size: "24sp"
                    color: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                    
                MDFillRoundFlatButton:
                    size_hint: 0.15,0.55
                    pos_hint: {'top': .7}
                    id: nuevo_parte
                    bold: True
                    line_color: "black"
                    font_size: "24sp"
                    text: "Nuevo Parte"
                    on_release:
                        app.show_open_dialog_hab(hab_num.text)
                        app.root.transition = SlideTransition(direction='right')
                        
            MDBoxLayout:
                size_hint: 1,0.7
                padding: [5,5,5,5]
                id: ObsGober
                orientation: 'vertical'
                text_size: self.size
                spacing: 10
                MDBoxLayout:
                    size_hint: 1,0.2
                    spacing: 10
                    MDTextField:
                        mode: "round"
                        halign: "center"
                        id: rango_txt
                        pos_hint: {'top': .85}
                        hint_text: 'Rango'
                        font_size: "18sp"
                        text_color_normal: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                        size_hint: 0.2,0.55
                        padding_y: [self.height / 2.0 - (self.line_height / 2.0) * len(self._lines), 0]
                        bold: True
                    MDFillRoundFlatButton:
                        size_hint: 0.5,0.55
                        pos_hint: {'top': .85,'right': 0.7}
                        id: Bt_Cambia_Rango
                        bold: True
                        line_color: "black"
                        font_size: "24sp"
                        text: "Cambiar Rango"
                        md_bg_color: app.color_light_naranja
                        on_release:
                            app.cambia_rango(rango_txt.text)
                            app.root.current = 'screen_gobernanta'
                            app.root.transition = SlideTransition(direction='right')
                    
                MDTextField:
                    hint_text: "Escriba Observaciones Gobernanta"
                    mode: "round"
                    id: text_ObsGober
                    pos_hint: {'top': 1}
                    size_hint: 1,0.4
                    font_size: '22dp'
                    bold: True
                    multiline: True
                MDFillRoundFlatButton:
                    size_hint: 0.97,0.1
                    padding: [5,10,5,10]
                    pos_hint: {"x": 0.02}
                    bold: True
                    line_color: "black"
                    font_size: "24sp"
                    md_bg_color: app.color_naranja
                    id: P_B_Obs_Gober
                    text: 'Enviar a GHOT'
                    disabled: True if len(text_ObsGober.text)==0 else False
                    on_release:
                        app.Obs_Gober_enviar()
                        app.root.current = 'screen_gobernanta'
                        app.root.transition = SlideTransition(direction='right')

            MDBoxLayout:
                orientation: 'vertical'
                size_hint: 1,0.1
                padding: [5,10,5,10]
                MDLabel:
                    id: tratamiento_txt
                    halign: 'center'
                    pos_hint: {'top': 1}
                    size_hint_y: 0.8
                    font_size: '20dp'
                    bold: True
                    text: "Tratamiento: Normal"

            MDBoxLayout:
                orientation: 'vertical'
                padding: [10,0,10,0]
                size_hint: 1,0.5
                MDTextField:
                    mode: "round"
                    size_hint: 1,1
                    id: tratamiento_info
                    font_size: '22dp'
                    bold: True
                    disabled: True
                    foreground_color: app.color_rojo
                    disabled_foreground_color: app.color_rojo
                    padding: [20,15,6,6]
                    multiline: True

            BoxLayout:
                size_hint: 1,0.15
                padding: [15,5,5,5]
                padding: 10
                spacing: 10
                MDBoxLayout:
                    MDFillRoundFlatIconButton:
                        size_hint: 1,0.95
                        icon: "exit-to-app"
                        text: 'Volver'
                        line_color: "black"
                        bold: True
                        font_size: "23sp"
                        on_release:
                            app.root.current = 'screen_gobernanta'
                            app.root.transition = SlideTransition(direction='right')

                MDFillRoundFlatIconButton:
                    id: btn_Limpio_Sucio
                    icon: "broom"
                    size_hint: 1,0.95
                    bold: True
                    font_size: "23sp"
                    md_bg_color: app.color_rojo
                    line_color: "black"
                    text: 'Marcar como SUCIA'
                    on_press:
                        app.act_limpia_sucia()
                        app.root.current = 'screen_gobernanta'
                        app.root.transition = SlideTransition(direction='right')

    MDScreen:
        name: 'screen_parte'
        MDBoxLayout:
            size_hint: 1,1
            orientation: 'vertical'
            padding: 5
            spacing: 5
            MDBoxLayout:
                size_hint: 1,0.1
                orientation: 'horizontal'
                MDLabel:
                    id: parte_num
                    pos_hint: {'top': .7}
                    bold: True
                    size_hint_x: 0.35
                    text: "Parte : "
                    font_size: '24sp'
                    pos_hint: {'center_y': 0.5}
                MDLabel:
                    id: asignado_txt
                    pos_hint: {'top': .7}
                    bold: True
                    size_hint_x: 0.35
                    text: "Assignado a : "
                    font_size: '24sp'
                    pos_hint: {'center_y': 0.5}
                MDFillRoundFlatButton:
                    id: asignado_btn
                    size_hint_x: 0.3
                    pos_hint: {'top': .7}
                    mode: "round"
                    font_size: '18sp'
                    text: "Asignarme Parte"
                    pos_hint: {'center_y': 0.5}
                    on_release:
                        app.asignarme_parte(parte_num.text)
                        app.root.current = 'screen_partes'
                        app.root.transition = SlideTransition(direction='right')

            MDBoxLayout:
                orientation: 'horizontal'
                size_hint: 1,0.05
                MDLabel:
                    size_hint_x: 0.3
                    text: "Zona/Hab:"
                    pos_hint: {'center_y': 0.5}
                MDTextField:
                    id: zona
                    size_hint_x: 0.5
                    text_color_normal: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                    mode: "round"
                    hint_text: "Zona"
                    max_text_length: 12
                    font_size: '18sp'
                    pos_hint: {'center_y': 0.5}
                    on_text: app.vaciar_campo_hab()
                MDTextField:
                    id: hab
                    size_hint_x: 0.2
                    text_color_normal: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                    mode: "round"
                    hint_text: "N.Hab"
                    font_size: '18sp'
                    pos_hint: {'center_y': 0.5}
                    on_text: app.vaciar_campo_zona()

            MDBoxLayout:
                orientation: 'horizontal'
                size_hint: 1,0.05
                MDLabel:
                    size_hint_x: 0.3
                    size_hint_y: 0.8
                    text: "Tipo Parte:"
                    pos_hint: {'center_y': 0.5}
                Spinner:
                    id: tipo
                    font_size: '16sp'
                    pos_hint: {'center_y': 0.5}
                    size_hint_x: 0.7
                    bold: True
                    color: "black"
                    text: 'Selecciona un tipo'
                    background_normal: ""
                    background_color: app.color_amarillo

            MDBoxLayout:
                orientation: 'horizontal'
                size_hint: 1,0.05
                MDLabel:
                    size_hint_x: 0.3
                    text: "Apertura:"
                    pos_hint: {'center_y': 0.5}
                MDLabel:
                    id: apertura
                    pos_hint: {'center_y': 0.5}
                    font_size: '14dp'
                    size_hint_x: 0.7
                    bold: True
                    text: ''
            MDBoxLayout:
                orientation: 'horizontal'
                size_hint: 1,0.05
                MDTextField:
                    hint_text: "Escriba la Descripción del Parte"
                    size_hint: 1,1
                    mode: "round"
                    text_color_normal: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                    id: parte_desc
                    font_size: '16sp'
                    bold: True
                    multiline: True

            MDBoxLayout:
                orientation: 'horizontal'
                size_hint: 1,0.05
                valign: 'center'
                MDLabel:
                    size_hint_x: 0.25
                    text: "Días Espera:"
                    pos_hint: {'center_y': 0.5}
                MDTextField:
                    id: dias_espera
                    text_color_normal: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                    size_hint_x: 0.25
                    hint_text: "0"
                    mode: "round"
                    pos_hint: {'center_y': 0.5}
                MDFillRoundFlatButton:
                    id: btn_espera
                    size_hint_x: 0.5
                    disabled: True if len(parte_espera_motivo.text)== 0 else False
                    mode: "round"
                    text: "Poner en Espera"
                    font_size: "20sp"
                    pos_hint: {'center_y': 0.5}
                    on_release:
                        app.poner_en_espera(parte_num.text)
                        app.root.current = 'screen_partes'
                        app.root.transition = SlideTransition(direction='right')
                
            MDBoxLayout:
                orientation: 'horizontal'
                size_hint: 1,0.05
                MDTextField:
                    hint_text: "Escribe Motivo Espera del Parte"
                    mode: "round"
                    text_color_normal: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                    size_hint: 1,1
                    pos_hint: {'center_y': 0.5}
                    id: parte_espera_motivo
                    font_size: '16sp'
                    bold: True
                    multiline: True

            MDBoxLayout:
                orientation: 'vertical'
                size_hint: 1,0.2
                MDBoxLayout:
                    orientation: 'horizontal'
                    size_hint: 1,0.4
                    MDLabel:
                        size_hint_x: 0.5
                        text:"Chat Recepción - Gobernanta/SSTT"
                        pos_hint: {'center_y': 0.5}
                    MDFillRoundFlatButton:
                        id: btn_chat
                        size_hint_x: 0.5
                        mode: "round"
                        text: "Escribir Mensaje"
                        font_size: "20sp"
                        pos_hint: {'center_y': 0.5}
                        on_release:
                            app.show_chat_dialog(parte_num.text)
                ScrollView:
                    size_hint: 1,1
                    MDTextField:
                        hint_text: "Chat Recepción"
                        mode: "round"
                        size_hint: 1,None
                        height: self.parent.height
                        id: parte_obs
                        text_color_normal: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                        font_size: '16sp'
                        pos_hint: {'center_y': 0.5}
                        bold: True
                        multiline: True

            MDBoxLayout:
                size_hint: 1,0.1
                spacing: 5
                MDFillRoundFlatIconButton:
                    id: atras_parte
                    icon: "exit-to-app"
                    text: 'Volver'
                    line_color: "black"
                    bold: True
                    size_hint_x: 0.3
                    font_size: "23sp"
                    pos_hint: {'center_y': 0.5}
                MDFillRoundFlatIconButton:
                    id: btn_parte_acc
                    icon: "broom"
                    pos_hint: {'center_y': 0.5}
                    bold: True
                    size_hint_x: 0.6
                    font_size: "23sp"
                    md_bg_color: app.color_rojo
                    line_color: "black"
                    text: 'Cerrar Parte'

    MDScreen:
        name: 'screen_parte_nuevo'
        MDBoxLayout:
            size_hint: 1,1
            orientation: 'vertical'
            padding: 5
            spacing: 5
            MDBoxLayout:
                size_hint: 1,0.1
                orientation: 'horizontal'
                MDLabel:
                    id: parte_num_nuevo
                    pos_hint: {'top': .7}
                    bold: True
                    size_hint_x: 0.35
                    text: "Parte : "
                    font_size: '24sp'
                    pos_hint: {'center_y': 0.5}
                MDLabel:
                    id: asignado_txt_nuevo
                    pos_hint: {'top': .7}
                    bold: True
                    size_hint_x: 0.35
                    text: "Assignado a : "
                    font_size: '24sp'
                    pos_hint: {'center_y': 0.5}
                MDFillRoundFlatButton:
                    id: asignado_btn_nuevo
                    size_hint_x: 0.3
                    pos_hint: {'top': .7}
                    mode: "round"
                    font_size: '18sp'
                    text: "Asignarme Parte"
                    pos_hint: {'center_y': 0.5}
                    on_release:
                        app.asignarme_parte(parte_num.text)
                        app.root.current = 'screen_partes'
                        app.root.transition = SlideTransition(direction='right')

            MDBoxLayout:
                orientation: 'horizontal'
                size_hint: 1,0.1
                MDLabel:
                    size_hint_x: 0.3
                    text: "Zona/Hab:"
                    pos_hint: {'center_y': 0.5}
                MDTextField:
                    id: zona_nuevo
                    size_hint_x: 0.5
                    text_color_normal: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                    mode: "round"
                    hint_text: "Zona"
                    max_text_length: 12
                    pos_hint: {'center_y': 0.5}
                    on_text: app.vaciar_campo_hab()
                MDTextField:
                    id: hab_nuevo
                    size_hint_x: 0.2
                    text_color_normal: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                    mode: "round"
                    hint_text: "N.Hab"
                    pos_hint: {'center_y': 0.5}
                    on_text: app.vaciar_campo_zona()

            MDBoxLayout:
                orientation: 'horizontal'
                size_hint: 1,0.1
                MDLabel:
                    size_hint_x: 0.3
                    size_hint_y: 0.8
                    text: "Tipo Parte:"
                    pos_hint: {'center_y': 0.5}
                Spinner:
                    id: tipo_nuevo
                    font_size: '16sp'
                    pos_hint: {'center_y': 0.5}
                    size_hint_x: 0.7
                    bold: True
                    color: "black"
                    text: 'Selecciona un tipo'
                    background_normal: ""
                    background_color: app.color_amarillo

            MDBoxLayout:
                orientation: 'horizontal'
                size_hint: 1,0.1
                MDLabel:
                    size_hint_x: 0.3
                    text: "Apertura:"
                    pos_hint: {'center_y': 0.5}
                MDLabel:
                    id: apertura_nuevo
                    pos_hint: {'center_y': 0.5}
                    font_size: '14dp'
                    size_hint_x: 0.7
                    bold: True
                    text: ''
            MDBoxLayout:
                orientation: 'horizontal'
                size_hint: 1,0.2
                MDTextField:
                    hint_text: "Escriba la Descripción del Parte"
                    size_hint: 1,1
                    mode: "round"
                    text_color_normal: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                    id: parte_desc_nuevo
                    font_size: '16sp'
                    bold: True
                    multiline: True

            MDBoxLayout:
                orientation: 'horizontal'
                size_hint: 1,0.1
                valign: 'center'
                MDLabel:
                    size_hint_x: 0.25
                    text: "Días Espera:"
                    pos_hint: {'center_y': 0.5}
                MDTextField:
                    id: dias_espera_nuevo
                    text_color_normal: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                    size_hint_x: 0.25
                    hint_text: "0"
                    mode: "round"
                    pos_hint: {'center_y': 0.5}
                MDFillRoundFlatButton:
                    id: btn_espera_nuevo
                    size_hint_x: 0.5
                    disabled: True if len(parte_espera_motivo.text)==0 else False
                    mode: "round"
                    text: "Poner en Espera"
                    font_size: "20sp"
                    pos_hint: {'center_y': 0.5}
                    on_release:
                        app.poner_en_espera(parte_num.text)
                        app.root.current = 'screen_partes'
                        app.root.transition = SlideTransition(direction='right')
                
            MDBoxLayout:
                orientation: 'horizontal'
                size_hint: 1,0.2
                MDTextField:
                    hint_text: "Escribe Motivo Espera del Parte"
                    mode: "round"
                    text_color_normal: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                    size_hint: 1,1
                    pos_hint: {'center_y': 0.5}
                    id: parte_espera_motivo_nuevo
                    font_size: '16sp'
                    bold: True
                    multiline: True

            MDBoxLayout:
                orientation: 'horizontal'
                size_hint: 1,0.2
                MDTextField:
                    hint_text: "Observaciones Recepción"
                    mode: "round"
                    size_hint: 1,1
                    id: parte_obs_nuevo
                    text_color_normal: (1, 1, 1, 1) if app.theme_cls.theme_style == "Dark" else (0, 0, 0, 1)
                    font_size: '16sp'
                    pos_hint: {'center_y': 0.5}
                    bold: True
                    multiline: True

            MDBoxLayout:
                size_hint: 1,0.1
                spacing: 5
                MDFillRoundFlatIconButton:
                    id: atras_parte_nuevo
                    icon: "exit-to-app"
                    text: 'Volver'
                    line_color: "black"
                    bold: True
                    size_hint_x: 0.3
                    font_size: "23sp"
                    pos_hint: {'center_y': 0.5}
                MDFillRoundFlatIconButton:
                    id: btn_parte_acc_nuevo
                    icon: "broom"
                    pos_hint: {'center_y': 0.5}
                    bold: True
                    size_hint_x: 0.6
                    font_size: "23sp"
                    md_bg_color: app.color_rojo
                    line_color: "black"
                    text: 'Cerrar Parte'

    MDScreen:
        name: 'screen_ajustes'
        MDFillRoundFlatButton:
            text: 'Volver Menu'
            pos_hint: {'top': 0.97, 'x': 0.03}
            on_release:
                app.root.current = 'screen_principal'
                app.root.transition = SlideTransition(direction='right')
        MDRectangleFlatIconButton:
            size_hint: 0.95,0.1
            pos_hint: {'top': 0.85, 'x': 0.03}
            icon: "file-cog-outline"
            bold: True
            font_style: "H6"
            md_bg_color: "#FF66F8"
            theme_text_color: "Custom"
            text_color: "black"
            line_color: "black"
            theme_icon_color: "Custom"
            icon_color: "black"
            text: "Reset Archivos"
            on_press:
                root.current = 'screen_json'
                app.root.transition = RiseInTransition()
        MDRectangleFlatIconButton:
            size_hint: 0.95,0.1
            pos_hint: {'top': 0.73, 'x': 0.03}
            icon: "refresh"
            bold: True
            font_style: "H6"
            md_bg_color: "#F3C561"
            theme_text_color: "Custom"
            text_color: "black"
            line_color: "black"
            theme_icon_color: "Custom"
            icon_color: "black"
            text: "Actualizar App"
            on_press:
                app.actu_app()
                root.current = 'screen_principal'
                app.root.transition = RiseInTransition()
        
        MDRectangleFlatIconButton:
            size_hint: 0.95,0.1
            pos_hint: {'top': 0.61, 'x': 0.03}
            icon: "exit-to-app"
            bold: True
            font_style: "H6"
            md_bg_color: app.color_rojo
            theme_text_color: "Custom"
            text_color: "white"
            line_color: "black"
            theme_icon_color: "Custom"
            icon_color: "white"
            text: "Salir"
            on_press:
                app.exit_app()
                root.current = 'screen_principal'
                app.root.transition = RiseInTransition()

        MDBoxLayout:
            orientation: 'vertical'
            size_hint: 0.95,0.3
            pos_hint: {"bottom": 1}
            margin_bottom: "2dp"
            spacing: "0.5dp"
            MDLabel:
                id: version_app
                text: "v.xx"
                font_size: "18sp"
                bold: True
                halign: "center"
            MDLabel:
                text: "Consultando Datos"
                bold: True
                font_size: "25sp"
                halign: "center"
            MDLabel:
                id: dia_act
                text: "Día: XX/XX/XXXX"
                font_size: "18sp"
                halign: "center"
            MDLabel:
                id: hora_act
                text: "Hora: XX:XX"
                font_size: "18sp"
                halign: "center"

    
    MDScreen:
        name: 'screen_json'
        MDBoxLayout:
            orientation: 'vertical'
            padding: 100
            spacing: 10
            MDLabel:
                size_hint_x: 1
                size_hint_y: 0.15
                text: "Password"
                bold: True
                font_style: "H6"
            TextInput:
                size_hint_x: 1
                size_hint_y: 0.3
                id: Borrar_psw
                font_size: '18dp'
                font_name: "data/fonts/Roboto-Bold.ttf"
                bold: True
                foreground_color: (0,0,0.6,1)
                disabled_foreground_color: (1,0,0,0.8)
                allow_copy: False
                password: True
                text: ''
                multiline: False
            MDRaisedButton:
                id: bt_Borrar_Json
                text: "Reset Archivos"
                size_hint: 1, None
                height: '60dp'
                font_size: '18dp'
                md_bg_color: "#FF66F8"
                theme_text_color: "Custom"
                text_color: "black"
                line_color: "black"
                theme_icon_color: "Custom"
                icon_color: "black"
                bold: True
                on_press:
                    app.borrar_json(root.ids.Borrar_psw.text)
            MDFillRoundFlatButton:
                text: 'Volver Menu'
                pos_hint: {'top': 0.97}
                on_release:
                    app.root.current = 'screen_ajustes'
                    app.root.transition = SlideTransition(direction='right')
            AnchorLayout:
                anchor_x: 'center'
                anchor_y: 'bottom'
    MDScreen:
        name: 'screen_partes'
        MDBottomNavigation:
            MDBottomNavigationItem:
                id: activos
                name: "partes_act"
                text: "Partes Activos"
                icon: "alpha-a-box"
                MDFillRoundFlatButton:
                    text: 'Volver'
                    pos_hint: {'top': 0.97, 'x': 0.04}
                    font_size: "20sp"
                    on_release:
                        app.root.current = 'screen_principal'
                        app.root.transition = SlideTransition(direction='right')
                MDFillRoundFlatButton:
                    text: 'Nuevo Parte'
                    pos_hint: {'top': 0.97, 'x': 0.64}
                    font_size: "20sp"
                    on_release:
                        app.show_open_dialog()
                        app.root.transition = SlideTransition(direction='right')
                MDBoxLayout:
                    size_hint: 0.95, 0.89
                    orientation: "vertical"
                    pos_hint: {'top': 0.90, "center_x": .5}
                    padding: ['10px', '0px','10dp', '0px']
                    spacing: 3
                    RecycleView:
                        id: recycle_view_act
                        data: []
                        viewclass: 'ParteView'
                        RecycleBoxLayout:
                            default_size_hint: 1, None
                            default_height: '55dp'
                            padding: ['0px', '0px','0px', '0px']
                            spacing: 5
                            orientation: 'vertical'
                            size_hint_y: None
                            height: self.minimum_height

            MDBottomNavigationItem:
                id: espera
                name: "partes_esp"
                text: "Partes Espera"
                icon: "alpha-e-box"
                MDFillRoundFlatButton:
                    text: 'Volver'
                    pos_hint: {'top': 0.97, 'x': 0.04}
                    font_size: "20sp"
                    on_release:
                        app.root.current = 'screen_principal'
                        app.root.transition = SlideTransition(direction='right')
                MDFillRoundFlatButton:
                    text: 'Nuevo Parte'
                    pos_hint: {'top': 0.97, 'x': 0.64}
                    font_size: "20sp"
                    on_release:
                        app.show_open_dialog()
                        app.root.transition = SlideTransition(direction='right')
                MDBoxLayout:
                    size_hint: 0.95, 0.89
                    orientation: "vertical"
                    pos_hint: {'top': 0.90, "center_x": .5}
                    padding: ['10px', '0px','10dp', '0px']
                    spacing: 3
                    RecycleView:
                        id: recycle_view_esp
                        data: []
                        viewclass: 'ParteView'
                        RecycleBoxLayout:
                            default_size_hint: 1, None
                            default_height: '55dp'
                            padding: ['0px', '0px','0px', '0px']
                            spacing: 5
                            orientation: 'vertical'
                            size_hint_y: None
                            height: self.minimum_height

            MDBottomNavigationItem:
                id: cerrados
                name: "partes_cerr"
                text: "Partes Cerrados"
                icon: "alpha-c-box"
                MDFillRoundFlatButton:
                    text: 'Volver'
                    pos_hint: {'top': 0.97, 'x': 0.04}
                    font_size: "20sp"
                    on_release:
                        app.root.current = 'screen_principal'
                        app.root.transition = SlideTransition(direction='right')
                MDFillRoundFlatButton:
                    text: 'Nuevo Parte'
                    pos_hint: {'top': 0.97, 'x': 0.64}
                    font_size: "20sp"
                    on_release:
                        app.show_open_dialog()
                        app.root.transition = SlideTransition(direction='right')
                MDBoxLayout:
                    size_hint: 0.95, 0.89
                    orientation: "vertical"
                    pos_hint: {'top': 0.90, "center_x": .5}
                    padding: ['10px', '0px','10dp', '0px']
                    spacing: 3
                    RecycleView:
                        id: recycle_view_cerr
                        data: []
                        viewclass: 'ParteView'
                        RecycleBoxLayout:
                            default_size_hint: 1, None
                            default_height: '55dp'
                            padding: ['0px', '0px','0px', '0px']
                            spacing: 5
                            orientation: 'vertical'
                            size_hint_y: None
                            height: self.minimum_height
<MySpinnerPopup>:
    title: 'Selecciona una opción'
    size_hint: None, None
    size: '250dp', '250dp'
    auto_dismiss: False
    MDBoxLayout:
        orientation: 'vertical'
        spacing: '10dp'
        padding: '10dp'
        MySpinnerButton:
            id: habitacion_btn
            text: 'Habitación'
            on_release:
                app.filtro_general('0','')
                app.filtro_general_entr('0','')
                root.dismiss()
        MySpinnerButton:
            id: hora_entrada_btn
            text: 'Hora Entrada'
            on_release:
                app.filtro_general('1','Entradas_ord')
                app.filtro_general_entr('1','Entradas_ord')
                root.dismiss()
        MySpinnerButton:
            id: hora_salida_btn
            text: 'Hora Salida'
            on_release:
                app.filtro_general('2','Salidas_ord')
                app.filtro_general_entr('2','Salidas_ord')
                root.dismiss()

<MySpinnerButton@Button>:
    size_hint_y: None
    height: '48dp'
'''

#----------------------------------------------------------------------------------------------------#
#                                                                                                    #
#                                      Variables Globales                                            #
#                                                                                                    #
#----------------------------------------------------------------------------------------------------#

version="1.23"
theme = ""
gl_tip_partes = ""
mensaje = ""
url_app = 'http://pms.hotelesglobales.com/app'
conf_info = ""
items = ""
items_partes = ""

#----------------------------------------------------------------------------------------------------#
#                                                                                                    #
#                                      Métodos Globales                                              #
#                                                                                                    #
#----------------------------------------------------------------------------------------------------#

def fully_qualified_path(filename):
    path = os.path.dirname(os.path.abspath(__file__))
    return os.path.join(path, filename)

# Entro en Modo Test o Producción
conf_info = JsonStore(fully_qualified_path("conf.json"))
if conf_info['modotest'] == 1:
	url_ghot = 'http://pms.hotelesglobales.com/ghot/api/api.php?modo=test&'
else:
	url_ghot = 'http://pms.hotelesglobales.com/ghot/api/api.php?modo=real&'

# Cargo Json's
if path.exists(fully_qualified_path("lista_habitaciones.json")):
    store_ListaHabs = JsonStore(fully_qualified_path("lista_habitaciones.json"))
    lista_Habitaciones = store_ListaHabs.get("HABITACIONES")
if path.exists(fully_qualified_path("partes.json")):
    temp_parte = JsonStore(fully_qualified_path("partes.json"))
    if 'IGNORAR' in temp_parte:
        gl_tip_partes = temp_parte.get('IGNORAR')['spin_tip_part']

# Miro si existe el archivo
if os.path.exists(fully_qualified_path("theme.json")):
    # Guardo el valor
    with open(fully_qualified_path("theme.json"), "r") as json_file:
        theme = json.load(json_file)
else:
    # Creo un valor
    theme = {"theme_value": 0}
    with open(fully_qualified_path("theme.json"), "w") as json_file:
        json.dump(theme, json_file)

def log_error(error):
    log_file_path = fully_qualified_path("log_errores.txt")
    max_file_size = 1024 * 1024

    if os.path.exists(log_file_path):
        # Verifica el tamaño del archivo
        file_size = os.path.getsize(log_file_path)
        
        if file_size > max_file_size:
            # Si el archivo supera el tamaño máximo, realiza la eliminación de líneas
            with open(log_file_path, "r") as file:
                lines = file.readlines()
            
            # Mantén solo las últimas líneas (puedes ajustar cuántas líneas deseas mantener)
            lines = lines[-500:]  # Por ejemplo, aquí mantenemos las últimas 500 líneas
            
            with open(log_file_path, "w") as file:
                file.writelines(lines)
        
        # Abre el archivo en modo "append" para agregar el nuevo error
        with open(log_file_path, "a") as error_file:
            error_file.write("\n\n" + str(datetime.now()) + "\t" + str(error))
    else:
        # Si el archivo no existe, créalo y agrega el error
        with open(log_file_path, "w") as error_file:
            error_file.write("\n\n" + str(datetime.now()) + "\t" + str(error))
    
def reiniciar_app():
    os.execv(sys.executable, ['python'] + sys.argv)

#----------------------------------------------------------------------------------------------------#
#                                                                                                    #
#                                      Clases Personalizadas                                         #
#                                                                                                    #
#----------------------------------------------------------------------------------------------------#

# Clase presonalizada de PopUp Filtros Habitaciones
class MySpinnerPopup(Popup):
    def __init__(self, my_spinner, **kwargs):
        super().__init__(**kwargs)
        self.my_spinner = my_spinner

    def set_filtro(self, instance):
        self.my_spinner.set_filtro(instance)

# Clase personalizada de RecycleView
class HabsView(RecycleDataViewBehavior, GridLayout):
    id_hab = StringProperty('')
    rango = StringProperty('')
    estado = StringProperty('')
    eos_val = StringProperty('')
    hora_val = StringProperty('')
    pax = StringProperty('')
    dias_vacia = StringProperty('')
    estado_libre = StringProperty('')

    # Monto los Botones + Labels con al información
    def refresh_view_attrs(self, rv, index, data):
        eos_val = list("---")
        hora_val = ""
        estado_libre = "0"
        self.id_hab = str(data['id'])
        self.rango = str(items.get(str(data['id']), {}).get('GGOB', ''))
        self.estado = str(items.get(str(data['id']), {}).get('ESTADO', ''))
        if items.get(str(data['id']), {}).get('ENT', '') == 1:
            eos_val[2] = "E"
            hora_val = str(items.get(str(data['id']), {}).get('HENT', ''))
        if items.get(str(data['id']), {}).get('SAL', '') > 0:
            eos_val[0] = "S"
        if items.get(str(data['id']), {}).get('OCU', '') > 0:
            eos_val[1] = "O"
        if str(items.get(str(data['id']), {}).get('HSAL', '')):
            hora_val = str(items.get(str(data['id']), {}).get('HSAL', '')) + " - " + hora_val
        if items.get(str(data['id']), {}).get('BLOQ', '') == 0:
            eos_val[0] = "B"
            eos_val[1] = "L"
            eos_val[2] = "O"
        # Si está libre muestro en zona VIP los días sin ocupar
        if items.get(str(data['id']), {}).get('DLIB', '') > 0:
            dias_vacia = items.get(str(data['id']), {}).get('DLIB', '') - 1
        else:
            dias_vacia = None
        # Si es salida y Tiene guarda, uso el la zona vip para indicarlo
        if items.get(str(data['id']), {}).get('SAL', '') != 0:
            if items.get(str(data['id']), {}).get('GUARDA', '') == 1:
                estado_libre = "GUARDA"

        # Si ya ha salido, uso el la zona vip para indicarlo
        if items.get(str(data['id']), {}).get('SAL', '') == 2:
            estado_libre = "OUT"

        # Si es MEDIA y no han salido las dos
        if items.get(str(data['id']), {}).get('SAL', '') == 3:
            estado_libre = "MEDIA"
        if items.get(str(data['id']), {}).get('ESTADO', '') == "Sucia":
            self.color = str(1)
        else:
            self.color = str(0)
        self.eos_val = str(''.join(eos_val))
        self.hora_val = str(hora_val)
        self.pax = str(items.get(str(data['id']), {}).get('PAX', ''))
        self.dias_vacia = str(dias_vacia)
        self.estado_libre = estado_libre
        return super().refresh_view_attrs(rv, index, data)
    
# Clase personalizada de RecycleView
class ParteView(RecycleDataViewBehavior, GridLayout):
    id = StringProperty('')
    hab = StringProperty('')
    zona = StringProperty('')
    apertura = StringProperty('')
    estado = StringProperty('')
    urgente = StringProperty('')
    critico = StringProperty('')
    hora = StringProperty('')
    asunto = StringProperty('')
    asignado = StringProperty('')

    # Monto los Botones + Labels con al información
    def refresh_view_attrs(self, rv, index, data):
        self.id = str(data['id'])
        self.hab = str(data['hab'])
        self.zona = str(data['zona'])
        self.hora = str(data['hora'])
        self.asunto = str(data['asunto'])
        self.apertura = str(data['apertura'])
        self.urgente = str(data['urgente'])
        self.critico = str(data['critico'])
        self.asignado = str(data['asignado'])
        if str(data['estado']) == 'A':
            self.color = str(1)
        elif str(data['estado']) == 'E':
            self.color = str(2)
        else:
            self.color = str(0)
        return super().refresh_view_attrs(rv, index, data)

#----------------------------------------------------------------------------------------------------#
#                                                                                                    #
#                                      Dialogos Personalizadas                                       #
#                                                                                                    #
#----------------------------------------------------------------------------------------------------#
    
class DialogoParteNuevoHab(MDBoxLayout):
    orientation = "vertical"
    def __init__(self, text_input, checkbox, **kwargs):
        super().__init__(**kwargs)
        self.text_input = text_input
        self.checkbox = checkbox
        self.spacing = "5px"
        self.pos_hint= {'center_y': .75}

        self.add_widget(MDLabel(text="¿Quién abre parte?",font_style= "H4"))
        self.add_widget(self.text_input)

        boxlayout = (MDBoxLayout(orientation= "horizontal"))
        boxlayout.add_widget(MDLabel(font_style= "H5",text="Recibir aviso al cerrar:",pos_hint= {'center_y': 0.5}))
        boxlayout.add_widget(self.checkbox)
        self.add_widget(boxlayout)

        self.size_hint_y = None
        self.height = dp(160)

class DialogoParteNuevo(MDBoxLayout):
    orientation = "vertical"
    def __init__(self, text_input, checkbox, **kwargs):
        super().__init__(**kwargs)
        self.text_input = text_input
        self.checkbox = checkbox
        self.spacing = "5px"
        self.pos_hint= {'center_y': .75}

        self.add_widget(MDLabel(text="¿Quién abre parte?",font_style= "H4"))
        self.add_widget(self.text_input)

        boxlayout = (MDBoxLayout(orientation= "horizontal"))
        boxlayout.add_widget(MDLabel(font_style= "H5",text="Recibir aviso al cerrar:",pos_hint= {'center_y': 0.5}))
        boxlayout.add_widget(self.checkbox)
        self.add_widget(boxlayout)

        self.size_hint_y = None
        self.height = dp(160)

# Clase personalizada de Dialogo
class DialogoParteCerrar(MDBoxLayout):
    orientation = "vertical"
    def __init__(self, text_input, checkbox, **kwargs):
        super().__init__(**kwargs)
        self.text_input = text_input
        self.checkbox = checkbox
        self.spacing = "3dp"
        self.pos_hint= {'center_y': 0.9}

        self.add_widget(MDLabel(text="¿Quién cierra/abre parte?"))
        self.add_widget(self.text_input)

        self.size_hint_y = None
        self.height = dp(80)

class DialogoParteChat(MDBoxLayout):
    orientation = "vertical"
    def __init__(self, text_input, text_input2, **kwargs):
        super().__init__(**kwargs)
        self.text_input = text_input
        self.text_input2 = text_input2
        self.spacing = "3dp"
        self.pos_hint= {'center_y': 0.7}

        self.add_widget(MDLabel(text=""))
        self.add_widget(self.text_input)
        self.add_widget(self.text_input2)

        self.size_hint_y = None
        self.height = dp(140)

#----------------------------------------------------------------------------------------------------#
#                                                                                                    #
#                                         Clase Principal                                            #
#                                                                                                    #
#----------------------------------------------------------------------------------------------------#

class Globales(MDApp):
    color_verde = get_color_from_hex("#72AE37")
    color_rojo = get_color_from_hex("#F12C36")
    color_light_naranja = get_color_from_hex("#fdbd39")
    color_naranja = get_color_from_hex("#f69833")
    color_turquesa = get_color_from_hex("#0dcfda")
    color_amarillo = get_color_from_hex("#fecf33")
    color_azul = (103/255,208/255,1)
    # Data RecycleView
    filtered_data = []
    filtered_data_entr = []
    filtered_data_sal = []
    filtered_data_ocu = []
    filtered_data_lib = []
    # Dialogs
    dialog = None
    dialog_parte_hab = None
    dialog_parte = None
    dialog_parte_hab_cerrar = None
    dialog_parte_chat = None
    # Theme
    activado_switch = False
    hab_instance = ObjectProperty('')
    parte_instance = ObjectProperty('')
    cargadoGober = False
    cargadoPartes = False
    # Habitacionas Act. ultima vez
    ignorar_data = ""
    partes_act_dia = ""
    partes_act_hora = ""

    # Processos en el Arranque
    def build(self):
         # Cogemos la hora de ahora
        self.now = datetime.now()
        # Cargamos Datos
        Clock.schedule_once(self.datos, 0)
        # Eviamos que con la tecla de retroceso nos salgamos del programa
        Window.bind(on_keyboard=self.key_input)
        # Miramos el tema de la app
        if theme["theme_value"] == 0:
            self.theme_cls.theme_style = "Dark"
            self.theme_cls.primary_palette = "Blue"
        else:
            self.theme_cls.theme_style = "Light"
            self.theme_cls.primary_palette = "Blue"
        root = Builder.load_string(KV)
        # Guardamos estado del switch
        self.activado_switch = root.ids.switch.active
        Window.size = (Window.width, Window.height)
        # Le asignamos un reloj y el método para actualizar la hora/fecha
        Clock.schedule_interval(self.update_clock_hora, 1)
        # Le asignamos un reloj y el método para actualizar la hora/fecha
        Clock.schedule_interval(self.tengo_wifi, 10)
        # Reloj que se encarga cada 5 segundos de contar los envíos
        Clock.schedule_interval(self.actualiza_contador_cola_Hab, 2)

        return root
    
####################################################################
################# Pantalla Principal Métodos #######################
####################################################################

    # Método para poner las url en cola
    def poner_en_cola_Sent(self, contenido):
        # Primero verifico si ya existe la Carpeta Sent
        if os.path.exists(fully_qualified_path('Sent')):
            pass
        else:
            # Creo carpeta Sent
            os.mkdir(fully_qualified_path('Sent'))
        # Generar archivo con nombre Random con el contenido
        nom = random.randint(1, 99999999999)
        # Monto senda
        path = 'Sent/' + str(nom)
        # Abro archivo
        f = open(fully_qualified_path(path), 'w')
        # Escribo la url
        f.write(str(contenido))
        # Cierro archivo
        f.close()

    # Método de envió
    def envio_cola(self):
        # Miro si existe la capeta Sent
        if os.path.exists(fully_qualified_path('Sent')):
            # La recorro
            for f in os.listdir(fully_qualified_path('Sent')):
                # Guardo la senda del archivo
                path = 'Sent/' + str(f)
                # Abro el archivo
                f = open(fully_qualified_path(path))
                # Leo la url que contiene y la guardo en una variable
                url = f.read()
                # Cierro archivo
                f.close()
                try:
                    # Envío la url
                    req = Request(url)
                    # Espero respuesta (Máximo 4 segundos)
                    response = urlopen(req, timeout=4)
                    # Si hay respuesta
                    if response:
                        # Borra el archivo
                        self.ok_envio(fully_qualified_path(path))
                    # No hay respuesta
                    else:
                        # No hace nada para probar a enviar la url más tarde
                        self.error_envio()

                # Excepciones
                except HTTPError as e:
                    log_error("Error enviando a Ghot")

                except URLError as e:
                    log_error("Error enviando a Ghot")

                except socket.timeout as e:
                    log_error("Error enviando a Ghot")

                except Exception as e:
                    log_error("Error enviando a Ghot")

    # Método para borrar los archivos enviados correctamente
    def ok_envio(self, path, *args):
        os.remove(path)

    # Método para mantener en bucle los envíos
    def error_envio(self, *args):
        pass
    
    # Método para cargar datos + conf
    def datos(self, *args):
        
        try:
            # Carga la configuración
            self.cargaConf()
            # Agregamos la versión al menu
            self.root.ids.version_app.text = "v." + version
            # Agregamos perfil al menu y la id de la tablet
            self.root.ids['perfil'].text = conf_info['perfil'] + " - " + conf_info['clave']
            # Agregamos el hotel y si es subgober
            self.root.ids['centro'].text = conf_info['nomEDF'] + "(" + conf_info['subgober'] + ")"
            # Ejecuta una sola vez "Cargar Lista Habitaciones"
            Clock.schedule_once(self.carga_lista_habitaciones, 0)
        # En caso de error
        except Exception as e:
            log_error("Error cargando Datos")

    def cargaDatosGober(self):
        self.cargadoGober
        if self.cargadoGober == False:
            # Reviso conexion
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(5)
            try:
                s.connect(("www.google.com", 80))
            except (socket.gaierror, socket.timeout):
                self.actualizar_rv_habs()
                pass
            else:
                
                # Ejecuta una sola vez "Recargar Datos Habitación" (Actualiza partes y habitaciónes)
                Clock.schedule_once(self.recargar_datos_hab, 0)
                # Ejecuta un reloj que cada 15 minutos Actualiza Partes y Habitaciónes
                Clock.schedule_interval(self.recargar_datos_gober_buton, 900)
                self.cargadoGober = True
                s.close()

    def cargaDatosParte(self):
        self.cargadoPartes
        if self.cargadoPartes == False:
            # Reviso conexion
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(5)
            try:
                s.connect(("www.google.com", 80))
            except (socket.gaierror, socket.timeout):
                self.actualizar_rv_partes()
                pass
            else:
                
                # Ejecuta una sola vez "Recargar Datos Habitación" (Actualiza partes y habitaciónes)
                Clock.schedule_once(self.recargar_datos_partes, 0)
                # Ejecuta un reloj que cada 15 minutos Actualiza Partes y Habitaciónes
                Clock.schedule_interval(self.recargar_datos_gober_buton, 900)
                self.cargadoPartes = True
                s.close()

    def cargaConf(self):
        try:
            # Si existe el directorio Imagenes
            if ((os.path.exists(fully_qualified_path('img')) and (os.listdir(fully_qualified_path('img')) != []))):
                pass
            else:
                if not os.path.exists(fully_qualified_path('img')):
                    os.mkdir(fully_qualified_path('img'))
                
                # Reviso conexion
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.settimeout(5)
                try:
                    s.connect(("www.google.com", 80))
                except (socket.gaierror, socket.timeout):
                    pass
                else:
                    
                    # Montamos Url de la imagen
                    url = url_app + '/GlobalesAppMD/img/actualizar.png'
                    # Traemos la imagen
                    urllib.request.urlretrieve(url, fully_qualified_path("img/actualizar.png"))
                    url = url_app + '/GlobalesAppMD/img/ajustes.png'
                    urllib.request.urlretrieve(url, fully_qualified_path("img/ajustes.png"))
                    url = url_app + '/GlobalesAppMD/img/globales.png'
                    urllib.request.urlretrieve(url, fully_qualified_path("img/globales.png"))
                    url = url_app + '/GlobalesAppMD/img/gobernanta.png'
                    urllib.request.urlretrieve(url, fully_qualified_path("img/gobernanta.png"))
                    url = url_app + '/GlobalesAppMD/img/partes.png'
                    urllib.request.urlretrieve(url, fully_qualified_path("img/partes.png"))
                    url = url_app + '/GlobalesAppMD/img/no-wifi.png'
                    urllib.request.urlretrieve(url, fully_qualified_path("img/no-wifi.png"))
                    s.close()

                reiniciar_app()
        # Excepciones
        except Exception as e:
            log_error("Error descargando Imagenes")
            
    # Cargo lista Habitaciones
    # Método para cargar Json de las habitaciónes del hotel
    def carga_lista_habitaciones(self, nap):
        global mensaje

        # Reviso conexion
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(5)
        try:
            s.connect(("www.google.com", 80))
        except (socket.gaierror, socket.timeout):
            pass
        else:
            
            # Sólo cargar Lista de Habitaciones si no tengo el json
            if os.path.exists(fully_qualified_path('lista_habitaciones.json')):
                pass
            else:
                # Variable global
                global lista_Habitaciones
                # Si el Config Json viene sin EDF damos error
                if conf_info['idEDF'] == 0:
                    return False
                # Montamos url
                url = url_ghot + 'vars=clave:' + str(conf_info['clave']) + '@acc:hab_list_get@edf:' + str(conf_info['idEDF']) + \
                    '@perfil:'+ conf_info['perfil']
                # Hacemos petición a la url
                req = Request(url)
                try:
                    # Esperamos respuesta
                    response = urlopen(req, timeout=4)
                # Excepciones
                except HTTPError as e:
                    log_error("Error descargando Lista Habitaciones de Ghot")

                except URLError as e:
                    log_error("Error descargando Lista Habitaciones de Ghot")

                except socket.timeout as e:
                    log_error("Error descargando Lista Habitaciones de Ghot")

                except ValueError as e:
                    log_error("Error descargando Lista Habitaciones de Ghot")
                else:
                    # Guardamos el Json que envía como respuesta
                    data = json.loads(response.read().decode("utf-8-sig"))
                    # Abrimos Json de Habitacines
                    fh = open(fully_qualified_path('lista_habitaciones.json'), 'w')
                    # Insertamos la información recibida
                    json.dump(data, fh)
                    # Cerramos Json
                    fh.close()
                s.close()
        if os.path.exists(fully_qualified_path('lista_habitaciones.json')):
            # Buscamos la ruta donde esta el Json de Habitaciónes
            store_ListaHabs = JsonStore(fully_qualified_path('lista_habitaciones.json'))
            # Cogemos las habitaciones y las guardamos en la Variable Global
            lista_Habitaciones = store_ListaHabs.get("HABITACIONES")

    # Método actualizar habitaciones
    def recargar_habitaciones(self):
        try:
            # Asignamos método a una variable
            retorno = self.search_habs()
            # Si devuelve True, se han actualizado las Habitaciones
            if retorno:
                pass
            # En caso contrario
            else:
                # Miramos si hay EDF
                if conf_info['idEDF'] == 0:
                    return
                # Si hay EDF Ponemos Error de Conexión
                else:
                    pass
            self.actualizar_rv_habs()
        # Excepciones
        except ValueError as e:
            log_error("Error Actualizando Habitaciones")

    # Método Principal para actualiar datos Habitacion
    def search_habs(self):
        global mensaje
        # Miro si hay EDF
        if conf_info['idEDF'] == 0:
            return False
        retorno = False
        # Monto url
        url = url_ghot + 'vars=clave:'+str(conf_info['clave'])+'@acc:hab_get@edf:' + str(conf_info['idEDF']) + \
                '@subgober:' + str(conf_info['subgober'])
        # Hago petición
        req = Request(url)
        try:
            # Espero Respuesta
            response = urlopen(req, timeout=4)
        except HTTPError as e:
            log_error("Error descargando Habitaciones de Ghot")
        except URLError as e:
            log_error("Error descargando Habitaciones de Ghot")
        except socket.timeout as e:
            log_error("Error descargando Habitaciones de Ghot")
        else:
            # Conexión correcta. guardo en json local
            data = json.loads(response.read().decode("utf-8-sig"))
            fh = open(fully_qualified_path('habitaciones.json'), 'w')
            json.dump(data, fh)
            fh.close()
            retorno = True
        return retorno
    
    # Método para recargar los datos de Gobernanta (Habitaciones)
    def recargar_datos_hab(self, nap):
        # Llamo método
        self.recargar_habitaciones()

    # Botón Método que recarga los datos una sola vez (Partes y Habitaciones)
    def recargar_datos_gober_buton(self,nap):
        # Reviso conexion
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(5)
        try:
            s.connect(("www.google.com", 80))
        except (socket.gaierror, socket.timeout):
            self.actualizar_rv_habs()
            self.actualizar_rv_partes()
            pass
        else:
            
            # Relojes de un solo loop
            Clock.schedule_once(self.recargar_datos_hab, nap)
            Clock.schedule_once(self.recargar_datos_partes, nap)
            s.close()

    def btn_Act_Datos(self,nap):
        self.cargadoGober = False
        self.cargadoPartes = False
    # Método para actualizar datos partes
    def recargar_datos_partes(self, nap):
        # Llamo método
        self.recargar_partes()

    def search_partes(self):
        # En esta petición enviamos la versión de la app para registrarla en GHOT
        global version
        global items_partes
        global gl_tip_partes
        if conf_info['idEDF'] == 0:
            return False
        retorno = False
        # Filtro Destino Partes
        dst_part = 'G'
        if str(conf_info['perfil']).startswith("S") or str(conf_info['perfil']).startswith("s"):
            dst_part = 'S'
        url = url_ghot + 'vars=clave:' + str(conf_info['clave']) + '@acc:partes_get@edf:' + str(conf_info['idEDF']) + \
                '@dst_part:' + dst_part + '@version:' + version
        req = Request(url)
        try:
            response = urlopen(req, timeout=4)
        except HTTPError as e:
            log_error("Error descargando Partes de Ghot")
        except URLError as e:
            log_error("Error descargando Partes de Ghot")
        except socket.timeout as e:
            log_error("Error descargando Partes de Ghot")
        else:
            data = json.loads(response.read())
            fh = open(fully_qualified_path('partes.json'), 'w')
            json.dump(data, fh)
            fh.close()
            retorno = True
        items_partes = JsonStore(fully_qualified_path("partes.json"))
        # Accedo a la llave específica
        if 'IGNORAR' in items_partes:
            gl_tip_partes = items_partes.get('IGNORAR')['spin_tip_part']
            self.partes_act_dia = items_partes.get('IGNORAR')['fecha']
            self.partes_act_hora = items_partes.get('IGNORAR')['hora']
        return retorno
    
    def recargar_partes(self):
        global gl_tip_partes
        global items_partes
        try:
            # Guardo método en variable
            retorno = self.search_partes()
            # Si devuelve True
            if retorno:
                pass
            # En caso contrario
            else:
                # Miro si hay EDF en conf
                if conf_info['idEDF'] == 0:
                    return
            # Cargamos del JSON guardado (puede ser actual o el anterior)
            items_partes = JsonStore(fully_qualified_path('partes.json'))
            items_partes = list((x[1] for x in sorted(items_partes.find(ES_ITEM='S'))))
            if 'IGNORAR' in items_partes:
                gl_tip_partes = items_partes.get('IGNORAR')['spin_tip_part']
            self.actualizar_rv_partes()
        # Excepciones
        except ValueError as e:
            log_error("Error Actualizando Partes de Ghot")

    # Cierra App y cambia estado de Tema
    def close_app(self, instance):
        global theme
        if theme['theme_value'] == 0:
            theme = {"theme_value": 1}
            with open(fully_qualified_path("theme.json"), "w") as json_file:
                json.dump(theme, json_file)
        else:
            theme = {"theme_value": 0}
            with open(fully_qualified_path("theme.json"), "w") as json_file:
                json.dump(theme, json_file)
        self.stop()

    # Método para comprobar cuantos archivos hay para envíar
    def actualiza_contador_cola_Hab(self, *args):
        # Miro si existe la carpeta Sent
        if os.path.exists(fully_qualified_path('Sent')):
            # Cuento cuantos archivos hay en la carpeta y lo guardo en una variable
            contadorcola = str(len(os.listdir(fully_qualified_path('Sent'))))
        else:
            # En caso de no haber carpeta Sent habrá 0 envíos
            contadorcola = "0"
        # Localizo el Label de Envíos y actualizo su numero
        self.root.ids['sent'].text = "Envios - " + str(contadorcola)
        try:
            # Ejecuto método de envío
            self.envio_cola()
        except:
            pass

    # Método para que no cierre la app con el botón de retroceso
    def key_input(self, window, key, scancode, codepoint, modifier):
        if key == 27:
            return True
        else:
            return False
        
    #Método para actualizar la hora/fecha
    def update_clock_hora(self, *args):
        self.now = self.now + timedelta(seconds=1)
        self.root.ids.hora.text = self.now.strftime(
        "%H:%M - %d/%m/%Y"
        )

    #Método para ver si tengo connexión
    def tengo_wifi(self, *args):
        # Reviso conexion
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(5)
        try:
            s.connect(("www.google.com", 80))
        except (socket.gaierror, socket.timeout):
            self.root.ids.wifi.text = "(Sin conexión)"
            self.root.ids.wifi_img.opacity = 1
            pass
        else:
            
            self.root.ids.wifi.text = ""
            self.root.ids.wifi_img.opacity = 0
            s.close()    

####################################################################
################# Pantalla Gobernanta Métodos ######################
####################################################################

    # Muestra PopUp Filtros Habitaciones
    def show_dropdown(self):
        popup = MySpinnerPopup(self)
        popup.open()
        self.popup = popup

    # Cierra PopUp Filtros Habitaciones
    def dismiss(self):
        self.popup.dismiss()

    # Aplica el Filtro elegido
    def set_filtro(self,texto):
        self.root.ids.filter_selected.text = texto
        self.root.ids.filter_selected_entr.text = texto

    # Importa los datos de la habitación seleccionada a los widgets
    def abrir_hab(self, id_hab, root):
        if conf_info["perfil"].startswith("G") or conf_info["perfil"].startswith("g"):
            info = items.get(id_hab, {})
            self.root.ids.hab_num.text = "Habitación : " + id_hab
            self.root.ids.rango_txt.text = str(info['GGOB'])
            if str(info['VIP']) != "":
                self.root.ids.tratamiento_txt.text = "Tratamiento: " + str(info['VIP'])
            extras = info['EXTRAS']
            lista_extras = ", ".join(extras)
            self.root.ids.tratamiento_info.text = str(lista_extras)
            self.root.ids.text_ObsGober.text = str(info['OBS'])
            if str(info["ESTADO"]) == "Sucia":
                self.root.ids.btn_Limpio_Sucio.text = "Marcar como LIMPIA"
                self.root.ids.btn_Limpio_Sucio.md_bg_color = self.color_verde
            else:
                self.root.ids.btn_Limpio_Sucio.text = "Marcar como SUCIA"
                self.root.ids.btn_Limpio_Sucio.md_bg_color = self.color_rojo
            if str(info["BLOQ"]) == '0':
                self.root.ids.btn_Limpio_Sucio.text = "BLOQUEADA"
                self.root.ids.btn_Limpio_Sucio.md_bg_color = self.color_turquesa
            self.data_temp = info
            self.hab_instance = root
            self.root.transition = RiseInTransition()
            self.root.current = "screen_habitacion"
        else:
            pass
    
    # Método para enviar las Observaciones a Ghot
    def Obs_Gober_enviar(self):
        # Vacío url
        url = ""
        info_habs = self.data_temp
        if info_habs["BLOQ"] != 0:
            # Guardo en una variable todo el texto de Observación
            unicObs = urllib.parse.quote(self.root.ids.text_ObsGober.text.replace('\n', ' ').encode('utf-8'))
            # Monto url
            url = url_ghot + 'vars=clave:' + str(conf_info['clave']) + '@acc:hab_obs_gober_mod@emp:' + str(info_habs['EMP']) + '@cnt:' + str(
            info_habs['CNT']) + '@id:' + \
            str(info_habs['ID']) + '@obs:' + unicObs
            # Si la url no esta vacía, guardo Observación en el Json y envío url a la cola de envío
            if (url != ""):
                info_habs["OBS"] = self.root.ids.text_ObsGober.text
                # Método de envío
                self.poner_en_cola_Sent(url)

    # Método para cambiar rango de una habitación
    def cambia_rango(self, rango):
        # Vacío url
        url = ""
        info_habs = self.data_temp
        if info_habs["BLOQ"] != 0:
            # Monto url
            url = url_ghot + 'vars=clave:' + str(conf_info['clave']) + '@acc:hab_rango_mod@emp:' + str(info_habs['EMP']) + '@cnt:' + str(
                info_habs['CNT']) + '@id:' + \
                str(info_habs['ID']) + '@ggob:' + rango
            # Si la url no esta vacía, guardo Observación en el Json y envío url a la cola de envío
            if (url != ""):
                info_habs["GGOB"] = rango
                self.hab_instance.rango = rango
                # Método de envío
                self.poner_en_cola_Sent(url)

    # Método Cambiar Estado Limpia/Sucia
    def act_limpia_sucia(self):
        # Vacío url
        url = ""
        info_habs = self.data_temp
        if info_habs["BLOQ"] != 0:
            # Si esta sucia, monto url con el Estado de LIMPIA (Cambia)
            if info_habs["ESTADO"] == "Sucia":
                url = url_ghot + 'vars=clave:' + str(conf_info['clave']) + '@acc:hab_estado_mod@emp:' + str(info_habs['EMP']) + '@cnt:' + str(info_habs['CNT']) + '@id:' + \
                str(info_habs['ID']) + '@estado:L'
                # Marco Json
                info_habs["ESTADO"] = "Limpia"
                # Si la url no esta vacía, envío la url
                if (url != ""):
                    self.poner_en_cola_Sent(url)
                    self.hab_instance.estado = str("Sucia")
                    self.hab_instance.color = "0"
            else:
                # Si esta Limpia, monto url con el Estado de Sucia (Cambia)
                url = url_ghot + 'vars=clave:' + str(conf_info['clave']) + '@acc:hab_estado_mod@emp:' + str(info_habs['EMP']) + '@cnt:' + str(info_habs['CNT']) + '@id:' + \
                str(info_habs['ID']) + '@estado:S'
                # Marco Json
                info_habs["ESTADO"] = "Sucia"
                # Si la url no esta vacía, envío la url
                if (url != ""):
                    self.poner_en_cola_Sent(url)
                    self.hab_instance.estado = str("Limpia")
                    self.hab_instance.color = "1"

    # Método para Filtrar Habitaciónes
    def get_filtered_data(self, filter_text, tipo):
        if tipo not in ["Habs", "Rango", "Entradas_ord", "Salidas_ord"]:
            return [
                {
                    'id': item,
                    'rango': str(items.get(str(item), {}).get('GGOB', '')),
                    'estado': str(items.get(str(item), {}).get('ESTADO', '')),
                    'ent': str(items.get(str(item), {}).get('ENT', '')),
                    'sal': str(items.get(str(item), {}).get('SAL', '')),
                    'ocu': str(items.get(str(item), {}).get('OCU', '')),
                    'dias_vacia': str(items.get(str(item), {}).get('DLIB', '')),
                }
                for item in items
            ]
        if tipo in ["Entradas_ord"]:
            items_with_hhmm = []
            items_without_hhmm = []
            for item in items:
                hhmm = str(items.get(str(item), {}).get('HENT', '')).strip().lower()
                if hhmm:
                    hhmm = datetime.strptime(hhmm, "%H:%M")
                    items_with_hhmm.append({
                        'id': item,
                        'rango': str(items.get(str(item), {}).get('GGOB', '')),
                        'estado': str(items.get(str(item), {}).get('ESTADO', '')),
                        'ent': str(items.get(str(item), {}).get('ENT', '')),
                        'sal': str(items.get(str(item), {}).get('SAL', '')),
                        'ocu': str(items.get(str(item), {}).get('OCU', '')),
                        'dias_vacia': str(items.get(str(item), {}).get('DLIB', '')),
                        'HHMM': hhmm  # Agrega 'HH:MM' a la entrada
                    })
                else:
                    items_without_hhmm.append({
                        'id': item,
                        'rango': str(items.get(str(item), {}).get('GGOB', '')),
                        'estado': str(items.get(str(item), {}).get('ESTADO', '')),
                        'ent': str(items.get(str(item), {}).get('ENT', '')),
                        'sal': str(items.get(str(item), {}).get('SAL', '')),
                        'ocu': str(items.get(str(item), {}).get('OCU', '')),
                        'dias_vacia': str(items.get(str(item), {}).get('DLIB', ''))
                    })

            # Ordenar la lista de elementos con 'HH:MM' por 'HH:MM' de más pronto a más tarde
            items_with_hhmm.sort(key=lambda x: x['HHMM'])
            # Concatenar las dos listas
            filtered_items = items_with_hhmm + items_without_hhmm

            return filtered_items
        if tipo in ["Salidas_ord"]:
            items_with_hhmm = []
            items_without_hhmm = []
            for item in items:
                hhmm = str(items.get(str(item), {}).get('HSAL', '')).strip().lower()
                if hhmm:
                    hhmm = datetime.strptime(hhmm, "%H:%M")
                    items_with_hhmm.append({
                        'id': item,
                        'rango': str(items.get(str(item), {}).get('GGOB', '')),
                        'estado': str(items.get(str(item), {}).get('ESTADO', '')),
                        'ent': str(items.get(str(item), {}).get('ENT', '')),
                        'sal': str(items.get(str(item), {}).get('SAL', '')),
                        'ocu': str(items.get(str(item), {}).get('OCU', '')),
                        'dias_vacia': str(items.get(str(item), {}).get('DLIB', '')),
                        'HHMM': hhmm  # Agrega 'HH:MM' a la salida
                    })
                else:
                    items_without_hhmm.append({
                        'id': item,
                        'rango': str(items.get(str(item), {}).get('GGOB', '')),
                        'estado': str(items.get(str(item), {}).get('ESTADO', '')),
                        'ent': str(items.get(str(item), {}).get('ENT', '')),
                        'sal': str(items.get(str(item), {}).get('SAL', '')),
                        'ocu': str(items.get(str(item), {}).get('OCU', '')),
                        'dias_vacia': str(items.get(str(item), {}).get('DLIB', ''))
                    })

            # Ordenar la lista de elementos con 'HH:MM' por 'HH:MM' de más pronto a más tarde
            items_with_hhmm.sort(key=lambda x: x['HHMM'])
            # Concatenar las dos listas
            filtered_items = items_with_hhmm + items_without_hhmm
            
            return filtered_items
        if tipo in ["Habs", "Rango"]:
            if self.root.ids.filter_selected.text == 'Ordenado por: Hora Entrada':
                items_with_hhmm = []
                items_without_hhmm = []
                for item in items:
                    hhmm = str(items.get(str(item), {}).get('HENT', '')).strip().lower()
                    if hhmm:
                        hhmm = datetime.strptime(hhmm, "%H:%M")
                        if (tipo == "Habs" and str(item).lower().startswith(filter_text.lower())) or \
                        (tipo == "Rango" and str(items.get(str(item), {}).get('GGOB', '')).lower().startswith(filter_text.lower())):
                            items_with_hhmm.append({
                                'id': item,
                                'rango': str(items.get(str(item), {}).get('GGOB', '')),
                                'estado': str(items.get(str(item), {}).get('ESTADO', '')),
                                'ent': str(items.get(str(item), {}).get('ENT', '')),
                                'sal': str(items.get(str(item), {}).get('SAL', '')),
                                'ocu': str(items.get(str(item), {}).get('OCU', '')),
                                'dias_vacia': str(items.get(str(item), {}).get('DLIB', '')),
                                'HHMM': hhmm  # Agrega 'HH:MM' a la entrada
                            })
                    else:
                        if (tipo == "Habs" and str(item).lower().startswith(filter_text.lower())) or \
                        (tipo == "Rango" and str(items.get(str(item), {}).get('GGOB', '')).lower().startswith(filter_text.lower())):
                            items_without_hhmm.append({
                                'id': item,
                                'rango': str(items.get(str(item), {}).get('GGOB', '')),
                                'estado': str(items.get(str(item), {}).get('ESTADO', '')),
                                'ent': str(items.get(str(item), {}).get('ENT', '')),
                                'sal': str(items.get(str(item), {}).get('SAL', '')),
                                'ocu': str(items.get(str(item), {}).get('OCU', '')),
                                'dias_vacia': str(items.get(str(item), {}).get('DLIB', ''))
                            })

                # Ordenar la lista de elementos con 'HH:MM' por 'HH:MM' de más pronto a más tarde
                items_with_hhmm.sort(key=lambda x: x['HHMM'])
                # Concatenar las dos listas
                filtered_items = items_with_hhmm + items_without_hhmm
            elif self.root.ids.filter_selected.text == 'Ordenado por: Hora Salida':
                items_with_hhmm = []
                items_without_hhmm = []
                for item in items:
                    hhmm = str(items.get(str(item), {}).get('HSAL', '')).strip().lower()
                    if hhmm:
                        hhmm = datetime.strptime(hhmm, "%H:%M")
                        if (tipo == "Habs" and str(item).lower().startswith(filter_text.lower())) or \
                        (tipo == "Rango" and str(items.get(str(item), {}).get('GGOB', '')).lower().startswith(filter_text.lower())):
                            items_with_hhmm.append({
                                'id': item,
                                'rango': str(items.get(str(item), {}).get('GGOB', '')),
                                'estado': str(items.get(str(item), {}).get('ESTADO', '')),
                                'ent': str(items.get(str(item), {}).get('ENT', '')),
                                'sal': str(items.get(str(item), {}).get('SAL', '')),
                                'ocu': str(items.get(str(item), {}).get('OCU', '')),
                                'dias_vacia': str(items.get(str(item), {}).get('DLIB', '')),
                                'HHMM': hhmm  # Agrega 'HH:MM' a la salida
                            })
                    else:
                        if (tipo == "Habs" and str(item).lower().startswith(filter_text.lower())) or \
                        (tipo == "Rango" and str(items.get(str(item), {}).get('GGOB', '')).lower().startswith(filter_text.lower())):
                            items_without_hhmm.append({
                                'id': item,
                                'rango': str(items.get(str(item), {}).get('GGOB', '')),
                                'estado': str(items.get(str(item), {}).get('ESTADO', '')),
                                'ent': str(items.get(str(item), {}).get('ENT', '')),
                                'sal': str(items.get(str(item), {}).get('SAL', '')),
                                'ocu': str(items.get(str(item), {}).get('OCU', '')),
                                'dias_vacia': str(items.get(str(item), {}).get('DLIB', ''))
                            })

                # Ordenar la lista de elementos con 'HH:MM' por 'HH:MM' de más pronto a más tarde
                items_with_hhmm.sort(key=lambda x: x['HHMM'])
                # Concatenar las dos listas
                filtered_items = items_with_hhmm + items_without_hhmm
            else:
                filtered_items = [
                    {
                        'id': item,
                        'rango': str(items.get(str(item), {}).get('GGOB', '')),
                        'estado': str(items.get(str(item), {}).get('ESTADO', '')),
                        'ent': str(items.get(str(item), {}).get('ENT', '')),
                        'sal': str(items.get(str(item), {}).get('SAL', '')),
                        'ocu': str(items.get(str(item), {}).get('OCU', '')),
                        'dias_vacia': str(items.get(str(item), {}).get('DLIB', ''))
                    }
                    for item in items
                    if (tipo == "Habs" and str(item).lower().startswith(filter_text.lower()))
                    or (tipo == "Rango" and str(items.get(str(item), {}).get('GGOB', '')).lower().startswith(filter_text.lower()))

                ]
            return filtered_items
    
    def actualizar_filtros(self, filtro):
        if filtro == "0":
            self.set_filtro('Ordenado por: Habitación')
        elif filtro == "1":
            self.set_filtro('Ordenado por: Hora Entrada')
        elif filtro == "2":
            self.set_filtro('Ordenado por: Hora Salida')

    def borrar_filtros(self, instance):
        self.root.ids.filtro_habs.text = ""
        self.root.ids.filtro_habs_entr.text = ""
        self.root.ids.filtro_habs_sal.text = ""
        self.root.ids.filtro_habs_ocu.text = ""
        self.root.ids.filtro_habs_lib.text = ""
        self.root.ids.filtro_rango.text = ""
        self.root.ids.filtro_rango_entr.text = ""
        self.root.ids.filtro_rango_sal.text = ""
        self.root.ids.filtro_rango_ocu.text = ""
        self.root.ids.filtro_rango_lib.text = ""

    def actualizar_rv_habs(self):
        global items

        if path.exists(fully_qualified_path("habitaciones.json")):
            # Cargamos del JSON guardado (puede ser actual o el anterior)
            with open(fully_qualified_path('habitaciones.json'), 'r') as json_file:
                data = json.load(json_file)
                if data != 0:
                    self.ignorar_data = {key: value for key, value in data.items() if key.startswith("IGNORAR")}
                    # Filtrar las claves que comienzan con "IGNORAR:"
                    data = {key: value for key, value in data.items() if not key.startswith("IGNORAR")}
                
                    items = data
                    self.filtered_data = self.get_filtered_data('','')
                    entradas = []
                    salidas = []
                    ocupadas = []
                    libres = []
                    count_entradas = 0
                    count_salidas = 0
                    count_ocupadas = 0
                    count_libres = 0
                    # Agregamos fecha y hora de datos consultados
                    self.root.ids.dia_act.text =  "Día: " + self.ignorar_data['IGNORAR']['fecha']
                    self.root.ids.hora_act.text =  "Hora: " + self.ignorar_data['IGNORAR']['hora']

                    for hab in self.filtered_data:
                        if int(hab['ent']) > 0:
                            entradas.append(hab)
                            count_entradas += 1
                        if int(hab['sal']) > 0:
                            salidas.append(hab)
                            count_salidas += 1
                        if int(hab['ocu']) > 0:
                            ocupadas.append(hab)
                            count_ocupadas += 1  
                        if (int(hab['dias_vacia'])) > 0:
                            libres.append(hab)
                            count_libres += 1   
                    # Agregamos Todas
                    self.root.ids.recycle_view.data = self.filtered_data
                    # Agregamos Entradas
                    self.root.ids.entradas.text = "Entradas (" + str(count_entradas) + ")"
                    self.root.ids.recycle_view_entr.data = entradas
                    # Agregamos Salidas
                    self.root.ids.salidas.text = "Salidas (" + str(count_salidas) + ")"
                    self.root.ids.recycle_view_sal.data = salidas
                    # Agregamos Ocupadas
                    self.root.ids.ocupadas.text = "Ocupadas (" + str(count_ocupadas) + ")"
                    self.root.ids.recycle_view_ocu.data = ocupadas
                    # Agregamos Libres
                    self.root.ids.libres.text = "Libres (" + str(count_libres) + ")"
                    self.root.ids.recycle_view_lib.data = libres

# ------------- Filtro Pantalla Todas -----------------
    def filtro_general(self, filter_text,tipo):
        self.filtered_data = self.get_filtered_data(filter_text,tipo)
        self.borrar_filtros("")
        self.actualizar_filtros(filter_text)
        self.root.ids.recycle_view.data = self.filtered_data

    def filtro_habs(self, filter_text,tipo):
        self.filtered_data = self.get_filtered_data(filter_text,tipo)
        self.root.ids.filtro_habs_entr.text = str(filter_text)
        self.root.ids.filtro_habs_sal.text = str(filter_text)
        self.root.ids.filtro_habs_ocu.text = str(filter_text)
        self.root.ids.filtro_habs_lib.text = str(filter_text)
        self.root.ids.recycle_view.data = self.filtered_data
        
    def filtro_rango(self, filter_text,tipo):
        self.filtered_data = self.get_filtered_data(filter_text,tipo)
        self.root.ids.recycle_view.data = self.filtered_data

# ------------- Filtro Pantalla Entradas -----------------

    def filtro_general_entr(self, filter_text,tipo):
        self.filtered_data_entr = self.get_filtered_data(filter_text,tipo)
        self.actualizar_filtros(filter_text)
        # Filtramos Entradas
        entradas = [item for item in self.filtered_data_entr if item['ent'] == '1']
        # Contamos numero entradas
        count_entradas = len(entradas)
        self.root.ids.entradas.text = "Entradas (" + str(count_entradas) + ")"
        # Agregamos Entradas
        self.root.ids.recycle_view_entr.data = entradas

    def filtro_habs_entr(self, filter_text,tipo):
        self.filtered_data_entr = self.get_filtered_data(filter_text,tipo)
        # Filtramos Entradas
        entradas = [item for item in self.filtered_data_entr if item['ent'] == '1']
        # Contamos numero entradas
        count_entradas = len(entradas)
        self.root.ids.entradas.text = "Entradas (" + str(count_entradas) + ")"
        # Agregamos Entradas
        self.root.ids.recycle_view_entr.data = entradas
        
    def filtro_rango_entr(self, filter_text,tipo):
        self.filtered_data_entr = self.get_filtered_data(filter_text,tipo)
        # Filtramos Entradas
        entradas = [item for item in self.filtered_data_entr if item['ent'] == '1']
        # Contamos numero entradas
        count_entradas = len(entradas)
        self.root.ids.entradas.text = "Entradas (" + str(count_entradas) + ")"
        # Agregamos Entradas
        self.root.ids.recycle_view_entr.data = entradas

# ------------- Filtro Pantalla Salidas -----------------
    def filtro_general_sal(self, filter_text,tipo):

        self.filtered_data_sal = self.get_filtered_data(filter_text,tipo)
        self.actualizar_filtros(filter_text)
        # Filtramos Salidas
        salidas = [item for item in self.filtered_data_sal if item['sal'] == '1']
        # Contamos numero salidas
        count_salidas = len(salidas)
        self.root.ids.salidas.text = "Salidas (" + str(count_salidas) + ")"
        # Agregamos Salidas
        self.root.ids.recycle_view_sal.data = salidas

    def filtro_habs_sal(self, filter_text,tipo):
        self.filtered_data_sal = self.get_filtered_data(filter_text,tipo)
        # Filtramos Salidas
        salidas = [item for item in self.filtered_data_sal if item['sal'] == '1']
        # Contamos numero salidas
        count_salidas = len(salidas)
        self.root.ids.salidas.text = "Salidas (" + str(count_salidas) + ")"
        # Agregamos Salidas
        self.root.ids.recycle_view_sal.data = salidas
        
    def filtro_rango_entr(self, filter_text,tipo):
        self.filtered_data_sal = self.get_filtered_data(filter_text,tipo)
        # Filtramos Salidas
        salidas = [item for item in self.filtered_data_sal if item['sal'] == '1']
        # Contamos numero salidas
        count_salidas = len(salidas)
        self.root.ids.salidas.text = "Salidas (" + str(count_salidas) + ")"
        # Agregamos Salidas
        self.root.ids.recycle_view_sal.data = salidas

# ------------- Filtro Pantalla Ocupadas -----------------

    def filtro_general_ocu(self, filter_text,tipo):
        self.filtered_data_ocu = self.get_filtered_data(filter_text,tipo)
        self.actualizar_filtros(filter_text)
        # Filtramos Ocupadas
        ocupadas = [item for item in self.filtered_data_ocu if item['ocu'] == '1']
        # Contamos numero ocupadas
        count_ocupadas = len(ocupadas)
        self.root.ids.ocupadas.text = "Ocupadas (" + str(count_ocupadas) + ")"
        # Agregamos Ocupadas
        self.root.ids.recycle_view_ocu.data = ocupadas

    def filtro_habs_ocu(self, filter_text,tipo):
        self.filtered_data_ocu = self.get_filtered_data(filter_text,tipo)
        # Filtramos Ocupadas
        ocupadas = [item for item in self.filtered_data_ocu if item['ocu'] == '1']
        # Contamos numero ocupadas
        count_ocupadas = len(ocupadas)
        self.root.ids.ocupadas.text = "Ocupadas (" + str(count_ocupadas) + ")"
        # Agregamos Ocupadas
        self.root.ids.recycle_view_ocu.data = ocupadas
        
    def filtro_rango_ocu(self, filter_text,tipo):
        self.filtered_data_ocu = self.get_filtered_data(filter_text,tipo)
        # Filtramos Ocupadas
        ocupadas = [item for item in self.filtered_data_ocu if item['ocu'] == '1']
        # Contamos numero ocupadas
        count_ocupadas = len(ocupadas)
        self.root.ids.ocupadas.text = "Ocupadas (" + str(count_ocupadas) + ")"
        # Agregamos Ocupadas
        self.root.ids.recycle_view_ocu.data = ocupadas

# ------------- Filtro Pantalla Libres -----------------

    def filtro_general_lib(self, filter_text,tipo):
        self.filtered_data_lib = self.get_filtered_data(filter_text,tipo)
        self.actualizar_filtros(filter_text)
        # Filtramos Ocupadas
        libres = [item for item in self.filtered_data_lib if item['dias_vacia'] > '0']
        # Contamos numero ocupadas
        count_libres = len(libres)
        self.root.ids.libres.text = "Libres (" + str(count_libres) + ")"
        # Agregamos Ocupadas
        self.root.ids.recycle_view_lib.data = libres

    def filtro_habs_lib(self, filter_text,tipo):
        self.filtered_data_lib = self.get_filtered_data(filter_text,tipo)
        # Filtramos Ocupadas
        libres = [item for item in self.filtered_data_lib if item['dias_vacia'] > '0']
        # Contamos numero ocupadas
        count_libres = len(libres)
        self.root.ids.libres.text = "Libres (" + str(count_libres) + ")"
        # Agregamos Ocupadas
        self.root.ids.recycle_view_lib.data = libres
        
    def filtro_rango_lib(self, filter_text,tipo):
        self.filtered_data_lib = self.get_filtered_data(filter_text,tipo)
        # Filtramos Ocupadas
        libres = [item for item in self.filtered_data_lib if item['dias_vacia'] > '0']
        # Contamos numero ocupadas
        count_libres = len(libres)
        self.root.ids.libres.text = "Libres (" + str(count_libres) + ")"
        # Agregamos Ocupadas
        self.root.ids.recycle_view_lib.data = libres

####################################################################
################# Pantalla Partes Métodos ######################
####################################################################

    def actualizar_rv_partes(self):
        global items_partes

        if not items_partes:
            # Cargamos del JSON guardado (puede ser actual o el anterior)
            items_partes = JsonStore(fully_qualified_path('partes.json'))
            items_partes = list((x[1] for x in sorted(items_partes.find(ES_ITEM='S'))))

        if path.exists(fully_qualified_path("partes.json")):

            # Agregamos fecha y hora de datos consultados
            self.root.ids.dia_act.text =  "Día: " + self.partes_act_dia
            self.root.ids.hora_act.text =  "Hora: " + self.partes_act_hora

            activo = []
            espera = []
            cerrado = []
            count_activos = 0
            count_espera = 0
            count_cerrados = 0
            data_partes= [{
                    'id': str(item['ID']),
                    'hab': str(item['HAB']),
                    'zona': str(item['ZON_COM']),
                    'apertura': str(item['FCH_APE']),
                    'estado': str(item['ESTADO']),
                    'urgente': str(item['URG']),
                    'critico': str(item['CRI']),
                    'hora': str(item['HOR_APE']),
                    'asunto': str(item['TIP_PART_NAME']),
                    'asignado': str(item['ASIGNADO_A']),
                }
                for item in items_partes]

            data_partes.sort(key=lambda x: x['hab'])

            for parte in data_partes:
                if parte['estado'] == 'A':
                    activo.append(parte)
                    count_activos += 1
                if parte['estado'] == 'E':
                    espera.append(parte)
                    count_espera += 1
                if parte['estado'] == 'C':
                    cerrado.append(parte)
                    count_cerrados += 1
            # Agregamos Activos
            self.root.ids.activos.text = "Activos (" + str(count_activos) + ")"
            self.root.ids.recycle_view_act.data = activo
            # Agregamos Entradas
            self.root.ids.espera.text = "En Espera (" + str(count_espera) + ")"
            self.root.ids.recycle_view_esp.data = espera
            # Agregamos Entradas
            self.root.ids.cerrados.text = "Cerrados (" + str(count_cerrados) + ")"
            self.root.ids.recycle_view_cerr.data = cerrado

    def separar_texto(self,text, max_chars_per_line):
        palabra = text[:max_chars_per_line]
        palabra2 = text[max_chars_per_line:]

        if not any(char.isdigit() for char in palabra) and not any(char.isdigit() for char in palabra2):
            return f"{palabra}\n{palabra2}"
        else:
            return text

    def asignarme_parte(self,id_parte):
        data = id_parte.split(" ")
        for elemento in items_partes:
            if elemento['ID'] == data[1]:
                elemento['ASIGNADO_A'] = conf_info['clave']
                self.parte_instance.asignado = conf_info['clave']
                url = url_ghot + 'vars=clave:'+str(conf_info['clave'])+'@acc:partes_asignar@id:'+str(data[1])+'@asignado_a:'+ conf_info['clave']
                self.poner_en_cola_Sent(url)

    def cerrar_abrir_parte(self,id_parte, nombre):
        if len(nombre) >= 3:
            self.dialog_parte_hab_cerrar.dismiss()
            self.dialog_parte_hab_cerrar = None
            for elemento in items_partes:
                if elemento['ID'] == id_parte:
                    elemento['MOT_ESP'] = self.root.ids.parte_espera_motivo.text
                    elemento['DIAS_ESP'] = self.root.ids.dias_espera.text
                    if (elemento['ESTADO'] == 'A') | (elemento['ESTADO'] == 'E'):
                        usuario = str(conf_info['clave']) + "-" + nombre
                        elemento['ESTADO'] = 'C'
                        self.parte_instance.estado = "C"
                        url = url_ghot + 'vars=clave:' + str(conf_info['clave']) + '@acc:partes_estado_mod@estado:C@id:' + str(id_parte) + '@usuario:' + urllib.parse.quote(usuario.replace('\n', ' ').encode('utf-8')) + '@motesp:' + urllib.parse.quote(self.root.ids.parte_espera_motivo.text.replace('\n', ' ').encode('utf-8')) + '@dias_esp:' + elemento['DIAS_ESP']
                    else:
                        usuario = str(conf_info['clave']) + "-" + nombre
                        elemento['ESTADO'] = 'A'
                        self.parte_instance.estado = "A"
                        url = url_ghot + 'vars=clave:' + str(conf_info['clave']) + '@acc:partes_estado_mod@estado:A@id:' + str(id_parte) + '@usuario:' + urllib.parse.quote(usuario.replace('\n', ' ').encode('utf-8')) + '@motesp:' + urllib.parse.quote(self.root.ids.parte_espera_motivo.text.replace('\n', ' ').encode('utf-8')) + '@dias_esp:' + elemento['DIAS_ESP']

                    self.poner_en_cola_Sent(url)
                    self.actualizar_rv_partes()
                    self.root.current = "screen_partes"
            else:
                pass

    def poner_en_espera(self,id_parte):
        data = id_parte.split(" ")
        for elemento in items_partes:
            if elemento['ID'] == data[1]:
                elemento['MOT_ESP'] = self.root.ids.parte_espera_motivo.text
                elemento['DIAS_ESP'] = self.root.ids.dias_espera.text
                elemento['ESTADO'] = "E"
                usuario = str(conf_info['clave'])
                self.parte_instance.estado = "E"
                url = url_ghot + 'vars=clave:' + str(conf_info['clave']) + '@acc:partes_estado_mod@estado:E@id:' + str(data[1]) + '@usuario:' + urllib.parse.quote(usuario.replace('\n', ' ').encode('utf-8')) + '@motesp:' + urllib.parse.quote(self.root.ids.parte_espera_motivo.text.replace('\n', ' ').encode('utf-8')) + '@dias_esp:' + elemento['DIAS_ESP']
                self.poner_en_cola_Sent(url)
                self.actualizar_rv_partes()

    def escribir_mensaje(self, id_parte, username_input, mensaje):
        if len(username_input) >= 3:
            self.dialog_parte_chat.dismiss()
            self.dialog_parte_chat = None
            for elemento in items_partes:
                if elemento['ID'] == id_parte:
                    usuario = str(conf_info['clave'])

                    now = datetime.now()
                    fecha_hora = now.strftime('%d/%m/%y %H:%M')
                    # Quito ceros del dia y mes
                    fecha_hora = fecha_hora.lstrip('0')
                    fecha_hora = fecha_hora.replace('/0', '/', 1)
                    mensaje_fecha = f"{fecha_hora} {usuario}-{username_input}: {mensaje}"
                    elemento['OBS'] = elemento['OBS']  + "\n" + mensaje_fecha
                    url = url_ghot + 'vars=clave:' + str(conf_info['clave']) + '@acc:chat@id:' + str(id_parte) + '@usuario:' + urllib.parse.quote(usuario.replace('\n', ' ').encode('utf-8')) + "-" + urllib.parse.quote(username_input.replace('\n', ' ').encode('utf-8')) + '@obs:' + urllib.parse.quote(mensaje.replace('\n', '#n#').encode('utf-8'))
                    self.poner_en_cola_Sent(url)
                    self.actualizar_rv_partes()
                    self.root.current = "screen_partes"

    # Importa los datos de la habitación seleccionada a los widgets
    def abrir_parte(self, id_parte, root):
        global gl_tip_partes 
        for elemento in items_partes:
            if elemento['ID'] == id_parte:
                self.parte_instance = root
                self.root.ids.parte_num.text = "Parte: " + elemento['ID']
                if elemento['ASIGNADO_A'] != '0':
                    self.root.ids.asignado_txt.text = "Asignado a: " + elemento['ASIGNADO_A']
                    self.root.ids.asignado_txt.color = self.color_naranja
                    self.root.ids.asignado_btn.opacity = 0
                    self.root.ids.asignado_txt.opacity = 1
                    self.root.ids.asignado_btn.disabled = True
                else:
                    self.root.ids.asignado_txt.opacity = 0
                    self.root.ids.asignado_btn.opacity = 1
                    self.root.ids.asignado_btn.disabled = False
                if elemento['ZON_COM'] == '':
                    self.root.ids.hab.text = elemento['HAB']
                else:
                    self.root.ids.zona.text = elemento['ZON_COM']
                self.root.ids.apertura.text = elemento['USU_APE'] + " - " + elemento['HOR_APE'] + " - " + elemento['FCH_APE']
                self.root.ids.parte_desc.text = elemento['DESC']
                self.root.ids.dias_espera.text = elemento['DIAS_ESP']
                self.root.ids.parte_espera_motivo.text = elemento['MOT_ESP']
                self.root.ids.parte_obs.text = elemento['OBS'].replace('#n#', "\n")
                if elemento['ESTADO'] == 'A':
                    self.root.ids.btn_parte_acc.text =  "Cerrar Parte"
                    self.root.ids.btn_parte_acc.md_bg_color =  self.color_rojo
                elif elemento['ESTADO'] == 'E':
                    self.root.ids.btn_parte_acc.text =  "Cerrar Parte"
                    self.root.ids.btn_parte_acc.md_bg_color =  self.color_turquesa
                else:
                    self.root.ids.btn_parte_acc.md_bg_color =  self.color_verde
                    self.root.ids.btn_parte_acc.text =  "Reabrir Parte"
                # Bloqueo todo
                self.root.ids.tipo.text = elemento['TIP_PART_NAME']
                self.root.ids.tipo.values = ""
                self.root.ids.zona.readonly = True
                self.root.ids.hab.readonly = True
                self.root.ids.parte_desc.readonly = True
                self.root.ids.parte_obs.readonly = True
                self.root.ids.dias_espera.readonly = False
                self.root.ids.parte_espera_motivo.readonly = False
                self.root.ids.btn_espera.disabled = True
                self.root.ids.atras_parte.on_release = lambda: self.cambiar_pantalla_parte()
                self.root.ids.btn_parte_acc.on_press = lambda: self.accion_parte("", self.root.ids.parte_num.text, "", "","")
                self.root.transition = RiseInTransition()
                self.root.current = "screen_parte"
                break

    def crear_parte(self,nombre,aviso,hab):
        if hab:
            # Guardamos Descripción
            unicDesc = urllib.parse.quote(self.root.ids.parte_desc.text.encode('utf-8'))
            # Guardamos Observación
            unicObs = urllib.parse.quote(self.root.ids.parte_obs.text.encode('utf-8'))
            # Guardamos Tipo
            unicTipo = urllib.parse.quote(self.root.ids.tipo.text.encode('utf-8'))
            # Guardamos Zona
            unicZona = urllib.parse.quote(self.root.ids.zona.text.encode('utf-8'))
            # Guardamos Num Habitación
            unicHab = str(self.root.ids.hab.text)
        else:
            # Guardamos Descripción
            unicDesc = urllib.parse.quote(self.root.ids.parte_desc_nuevo.text.encode('utf-8'))
            # Guardamos Observación
            unicObs = urllib.parse.quote(self.root.ids.parte_obs_nuevo.text.encode('utf-8'))
            # Guardamos Tipo
            unicTipo = urllib.parse.quote(self.root.ids.tipo_nuevo.text.encode('utf-8'))
            # Guardamos Zona
            unicZona = urllib.parse.quote(self.root.ids.zona_nuevo.text.encode('utf-8'))
            # Guardamos Num Habitación
            unicHab = str(self.root.ids.hab_nuevo.text)
        # Si el dispositivo es de gobernanta o SSTT
        if conf_info['perfil'].startswith("G") or conf_info['perfil'].startswith("g"):
            ori_part = "G"
        else:
            ori_part = "S"
        # Si esta activo el Check Box de avisar miramos si esta seleccionado
        if aviso == True:
            # Seleccionado
            es_avisar = 1
        else:
            # No Seleccionado
            es_avisar = 0
        # Monto url
        url = url_ghot + 'vars=clave:' + str(conf_info['clave']) + '@acc:parte_alta@estado:A@hab:' + unicHab + \
            '@zona:' + unicZona +'@usuario:' + urllib.parse.quote(nombre.replace('\n', ' ').encode('utf-8')) + '@motesp:' + ""  + '@obs:' + unicObs + \
            '@tipo:' + unicTipo + '@desc:' + unicDesc + '@edf:' + str(conf_info['idEDF']) + '@es_avisar:' + str(es_avisar) + \
            '@ori_part:' + ori_part + '@dias_esp:' + "0"
        self.poner_en_cola_Sent(url)
    
    def accion_parte(self,accion, parte_id,nombre,aviso,hab):

        if accion != "crear":
            self.show_cerrar_dialog(parte_id)
        else:
            error = False
            if path.exists(fully_qualified_path("lista_habitaciones.json")):
                if hab:
                    if ((str(self.root.ids.hab.text) in lista_Habitaciones) | ((str(self.root.ids.zona.text) != "") and len(str(self.root.ids.zona.text)) < 13)) and (self.root.ids.tipo.text != 'Selecciona un tipo'):
                        self.crear_parte(nombre,aviso,hab)
                        self.root.current = 'screen_gobernanta'
                        self.root.transition = SlideTransition(direction='right')
                    else:
                        error = True
                else:
                    if ((str(self.root.ids.hab_nuevo.text) in lista_Habitaciones) | ((str(self.root.ids.zona_nuevo.text) != "") and len(str(self.root.ids.zona_nuevo.text)) < 13)) and (self.root.ids.tipo_nuevo.text != 'Selecciona un tipo'):
                        self.crear_parte(nombre,aviso,False)
                        self.root.current = 'screen_partes'
                        self.root.transition = SlideTransition(direction='right')
                    else:
                        error = True
                if error == True:
                    PU_Error = Popup()
                    PU_Error.title = u'Error'
                    bl_content = MDBoxLayout()
                    bl_content.orientation = 'vertical'
                    bl_content.padding = [10,10,10,10]
                    lab = MDLabel(text='Posibles Errores:\n \n- No existe Nº Habitación\n- Selecciona "Tipo Parte"\n- Reduce el texto de Zona', markup= True )
                    lab.font_size = '35sp'
                    lab.color = "#FF0C00"
                    bl_content.add_widget(lab)
                    bl_content2 = MDBoxLayout()
                    bl_content2.md_bg_color = "#FBFF11"
                    bl_content2.size_hint =  None,None
                    bl_content2.height = "120dp"
                    bl_content2.width = "160dp"
                    icon = MDIconButton()
                    icon.bold = True
                    icon.icon = "exit-to-app"
                    icon.size_hint = 1,1
                    icon.type = "large"
                    icon.theme_icon_color = "Custom"
                    icon.line_color = "black"
                    icon.icon_color = "black"
                    bl_content2.add_widget(icon)
                    bl_content.add_widget(bl_content2)
                    icon.bind(on_press=PU_Error.dismiss)
                    PU_Error.content = bl_content
                    PU_Error.open()
                    if hab: 
                        self.root.current = 'screen_parte'
                    else:    
                        self.root.current = 'screen_parte_nuevo'

    def cambiar_pantalla_hab(self):
        self.root.transition = RiseInTransition()
        self.root.current = "screen_habitacion"
    
    def cambiar_pantalla_parte(self):
        self.root.transition = RiseInTransition()
        self.root.current = "screen_partes"
    
    def vaciar_campo_hab(self):
        if len(self.root.ids.zona.text) > 0:
            self.root.ids.hab.text = ""
        if len(self.root.ids.zona_nuevo.text) > 0:
            self.root.ids.hab_nuevo.text = ""

    def vaciar_campo_zona(self):
        if len(self.root.ids.hab.text) > 0:
            self.root.ids.zona.text = ""
        if len(self.root.ids.hab_nuevo.text) > 0:
            self.root.ids.zona_nuevo.text = ""
            
####################################################################
####################### Nuevo Parte ################################
####################################################################

    def nuevo_parte(self, nombre, aviso):
        global gl_tip_partes
        if len(nombre) >= 3:
            self.root.ids.hab_nuevo.text = ''
            self.root.ids.zona_nuevo.readonly = False
            self.root.ids.hab_nuevo.readonly = False
            self.root.ids.zona_nuevo.text = ''
            vengo_hab = False
            self.root.ids.atras_parte_nuevo.on_release = lambda: self.cambiar_pantalla_parte()
            self.root.ids.parte_num_nuevo.text = "Parte: Creando"
            self.root.ids.asignado_txt_nuevo.opacity = 0
            self.root.ids.asignado_btn_nuevo.opacity = 0
            self.root.ids.asignado_btn_nuevo.disabled = True
            self.root.ids.tipo_nuevo.text = 'Selecciona un tipo'
            self.root.ids.tipo_nuevo.values = gl_tip_partes
            self.now = self.now + timedelta(seconds=1)
            hora = self.now.strftime(
            "%H:%M - %d/%m/%Y"
            )
            self.root.ids.apertura_nuevo.text = nombre + " - " + hora
            self.root.ids.parte_desc_nuevo.text = ""
            self.root.ids.dias_espera_nuevo.text = "0"
            self.root.ids.parte_espera_motivo_nuevo.text = ""
            self.root.ids.parte_obs_nuevo.readonly = True
            self.root.ids.parte_obs_nuevo.text = ""
            self.root.ids.parte_desc_nuevo.readonly = False
            self.root.ids.dias_espera_nuevo.readonly = True
            self.root.ids.parte_espera_motivo_nuevo.readonly = True
            self.root.ids.btn_espera_nuevo.disabled = True
            self.root.ids.btn_parte_acc_nuevo.text =  "Crear Parte"
            self.root.ids.btn_parte_acc_nuevo.md_bg_color =  self.color_verde
            self.root.ids.btn_parte_acc_nuevo.on_press = lambda: self.accion_parte("crear", self.root.ids.parte_num.text, nombre, aviso,vengo_hab)
            self.root.transition = RiseInTransition()
            self.root.current = "screen_parte_nuevo"
            self.dialog_parte.dismiss()
            self.dialog_parte = None
        else:
            pass

####################################################################
##################### Nuevo Parte Hab ##############################
####################################################################

    def nuevo_parte_hab(self,habitacion, nombre, aviso):
        global gl_tip_partes
        if len(nombre) >= 3:
            num_hab = habitacion.split(" ")
            self.root.ids.hab.text = num_hab[2]
            self.root.ids.hab.readonly = True
            self.root.ids.zona.readonly = True
            self.root.ids.zona.text = ''
            vengo_hab = True
            self.root.ids.atras_parte.on_release = lambda: self.cambiar_pantalla_hab()
            self.root.ids.parte_num.text = "Parte: Creando"
            self.root.ids.asignado_txt.opacity = 0
            self.root.ids.asignado_btn.opacity = 0
            self.root.ids.asignado_btn.disabled = True
            self.root.ids.tipo.text = 'Selecciona un tipo'
            self.root.ids.tipo.values = gl_tip_partes
            self.now = self.now + timedelta(seconds=1)
            hora = self.now.strftime(
            "%H:%M - %d/%m/%Y"
            )
            self.root.ids.apertura.text = nombre + " - " + hora
            self.root.ids.parte_desc.text = ""
            self.root.ids.dias_espera.text = "0"
            self.root.ids.parte_espera_motivo.text = ""
            self.root.ids.parte_obs.readonly = False
            self.root.ids.parte_obs.text = ""
            self.root.ids.parte_desc.readonly = False
            self.root.ids.dias_espera.readonly = True
            self.root.ids.parte_espera_motivo.readonly = True
            self.root.ids.btn_espera.disabled = True
            self.root.ids.btn_parte_acc.text =  "Crear Parte"
            self.root.ids.btn_parte_acc.md_bg_color =  self.color_verde
            self.root.ids.btn_parte_acc.on_press = lambda: self.accion_parte("crear", self.root.ids.parte_num.text, nombre, aviso,vengo_hab)
            self.root.transition = RiseInTransition()
            self.root.current = "screen_parte"
            self.dialog_parte_hab.dismiss()
            self.dialog_parte_hab = None
        else:
            pass

####################################################################
########################### Dialogs ################################
####################################################################

    # Dialogo para cambiar de Tema de la app
    def show_change_dialog(self):
        if not self.dialog:
            self.dialog = MDDialog(
                text="¿Quieres cambiar el estilo? Se cerrará la aplicación!",
                buttons=[
                    MDFlatButton(
                        text="NO",
                        theme_text_color="Custom",
                        text_color=self.theme_cls.primary_color,
                        on_release=self.close_dialog,
                    ),
                    MDFlatButton(
                        text="SI",
                        theme_text_color="Custom",
                        text_color=self.theme_cls.primary_color,
                        on_release=self.close_app,
                    ),
                ],
            )
        self.dialog.open()

    # Método para cerrar app y mantener el switch en su estado principal
    def close_dialog(self, instance):
        self.root.ids.switch.active = self.activado_switch
        self.dialog.dismiss()

    # Dialogo para abrir parte
    def show_cerrar_dialog(self, id_parte):
        if not self.dialog_parte_hab_cerrar:
            data = id_parte.split(" ")
            self.text_input = MDTextField(hint_text = "Nombre (min. 3 letras)")
            self.checkbox = MDCheckbox(size_hint= [0.1,1],pos_hint= {'center_y': 0.5})
            self.dialog_parte_hab_cerrar = MDDialog(
                title=" ",
                type="custom",
                content_cls=DialogoParteCerrar(self.text_input, self.checkbox),
                buttons=[
                    MDFlatButton(
                        text="Cancelar",
                        md_bg_color = self.color_turquesa,
                        on_release=self.close_dialog_cerrar,
                    ),
                    MDFlatButton(
                        text="Cerrar/Abrir",
                        md_bg_color = self.color_turquesa,
                        on_release=lambda x: self.cerrar_abrir_parte(data[1], self.text_input.text),
                    ),
                ],
            )
        self.dialog_parte_hab_cerrar.open()

    def close_dialog_cerrar(self, instance):

        self.dialog_parte_hab_cerrar.dismiss()

    # Dialogo para chat en parte
    def show_chat_dialog(self, id_parte):
        if not self.dialog_parte_chat:
            data = id_parte.split(" ")
            self.text_input = MDTextField(hint_text = "Nombre (min. 3 letras)")
            self.text_input2 = MDTextField(hint_text = "Mensaje")
            self.dialog_parte_chat = MDDialog(
                title="Escribiendo Mensaje a Recepción",
                type="custom",
                content_cls=DialogoParteChat(self.text_input, self.text_input2),
                buttons=[
                    MDFlatButton(
                        text="Cancelar",
                        md_bg_color = self.color_turquesa,
                        on_release=self.close_dialog_chat,
                    ),
                    MDFlatButton(
                        text="Enviar",
                        md_bg_color = self.color_turquesa,
                        on_release=lambda x: self.escribir_mensaje(data[1], self.text_input.text, self.text_input2.text),
                    ),
                ],
            )
        self.dialog_parte_chat.open()

    def close_dialog_chat(self, instance):
        self.dialog_parte_chat.dismiss()

    # Dialogo para abrir parte
    def show_open_dialog(self):
        if not self.dialog_parte:
            self.text_input = MDTextField(hint_text = "Nombre (min. 3 letras)",font_size= "35sp")
            self.checkbox = MDCheckbox(size_hint= [0.2,None],pos_hint= {'center_y': 0.5}, height = dp(50))
            self.dialog_parte = MDDialog(
                title=" ",
                type="custom",
                content_cls=DialogoParteNuevo(self.text_input, self.checkbox),
                buttons=[
                    MDFlatButton(
                        text="Cancelar",
                        font_size="20sp",
                        md_bg_color = self.color_turquesa,
                        on_release=self.close_dialog_open,
                    ),
                    MDFlatButton(
                        text="Crear",
                        font_size="20sp",
                        md_bg_color = self.color_turquesa,
                        on_release=lambda x: self.nuevo_parte(self.text_input.text, self.checkbox.active),
                    ),
                ],
            )
        self.dialog_parte.open()

    # Método para cerrar app y mantener el switch en su estado principal
    def close_dialog_open(self, instance):
        self.dialog_parte.dismiss()
        self.dialog_parte = None

    # Dialogo para abrir parte desd habitación
    def show_open_dialog_hab(self, habitacion):
        if not self.dialog_parte_hab:
            self.text_input = MDTextField(hint_text = "Nombre (min. 3 letras)",font_size= "35sp")
            self.checkbox = MDCheckbox(size_hint= [0.2,None],pos_hint= {'center_y': 0.5}, height = dp(50))
            self.dialog_parte_hab = MDDialog(
                title=" ",
                type="custom",
                content_cls=DialogoParteNuevoHab(self.text_input, self.checkbox),
                buttons=[
                    MDFlatButton(
                        text="Cancelar",
                        font_size="20sp",
                        md_bg_color = self.color_turquesa,
                        on_release=self.close_dialog_open_hab,
                    ),
                    MDFlatButton(
                        text="Crear",
                        font_size="20sp",
                        md_bg_color = self.color_turquesa,
                        on_release=lambda x: self.nuevo_parte_hab(habitacion, self.text_input.text, self.checkbox.active),
                    ),
                ],
            )
        self.dialog_parte_hab.open()

    # Método para cerrar app y mantener el switch en su estado principal
    def close_dialog_open_hab(self, instance):
        self.dialog_parte_hab.dismiss()
        self.dialog_parte_hab = None

####################################################################
################# Pantalla Ajustes Métodos #########################
####################################################################
    
    def actu_app(self):
        try:
            url = url_app + '/GlobalesAppMD/main.py'
            urllib.request.urlretrieve(url, fully_qualified_path("main.py"))
            url = url_app + '/GlobalesAppMD/img/actualizar.png'
            urllib.request.urlretrieve(url, fully_qualified_path("img/actualizar.png"))
            url = url_app + '/GlobalesAppMD/img/ajustes.png'
            urllib.request.urlretrieve(url, fully_qualified_path("img/ajustes.png"))
            url = url_app + '/GlobalesAppMD/img/globales.png'
            urllib.request.urlretrieve(url, fully_qualified_path("img/globales.png"))
            url = url_app + '/GlobalesAppMD/img/gobernanta.png'
            urllib.request.urlretrieve(url, fully_qualified_path("img/gobernanta.png"))
            url = url_app + '/GlobalesAppMD/img/partes.png'
            urllib.request.urlretrieve(url, fully_qualified_path("img/partes.png"))
            url = url_app + '/GlobalesAppMD/img/no-wifi.png'
            urllib.request.urlretrieve(url, fully_qualified_path("img/no-wifi.png"))
            sys.exit(0)
        except Exception as e:
            log_error("Error Actualizando App a nueva versión")

    def exit_app(self):
        sys.exit(0)

    # Borra todos los json
    def borrar_json(self, password):
        if password == 'globales':
            if path.exists(fully_qualified_path("partes.json")):
                remove(fully_qualified_path("partes.json"))
            else:
                pass
            if path.exists(fully_qualified_path("lista_habitaciones.json")):
                remove(fully_qualified_path("lista_habitaciones.json"))
            else:
                pass
            if path.exists(fully_qualified_path("habitaciones.json")):
                remove(fully_qualified_path("habitaciones.json"))
            else:
                pass
            sys.exit(0)
        else:
            PU_Error = Popup()
            PU_Error.title = u'Error'
            bl_content = MDBoxLayout()
            bl_content.orientation = 'vertical'
            bl_content.padding = [10,10,10,10]
            lab = Label(text='Error Contraseña')
            lab.font_size = '35sp'
            lab.color = "#FF0C00"
            bl_content.add_widget(lab)
            bl_content2 = MDBoxLayout()
            bl_content2.md_bg_color = "#FBFF11"
            bl_content2.size_hint =  None,None
            bl_content2.height = "120dp"
            bl_content2.width = "160dp"
            icon = MDIconButton()
            icon.bold = True
            icon.icon = "exit-to-app"
            icon.size_hint = 1,1
            icon.type = "large"
            icon.theme_icon_color = "Custom"
            icon.line_color = "black"
            icon.icon_color = "black"
            bl_content2.add_widget(icon)
            bl_content.add_widget(bl_content2)
            icon.bind(on_press=PU_Error.dismiss)
            PU_Error.content = bl_content
            PU_Error.open()

Globales().run()