Search code examples
pythonkivykivy-language

How to keep users from getting past login screen of App before logging in Kivy


The first screen it goes to is the login screen but, I can just click any button on the Actionbar bypassing the login screen. I even thought of removing the Actionbar buttons then I could just put them back if login is successful but, I could not figure out how to call the id's of the Actionbar from the login screen class. What is the best way to keep a user from bypassing the login screen of the App?

Python code:

from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.image import Image
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.clock import mainthread
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView


Builder.load_file('main.kv')


class Menu(BoxLayout):
    manager = ObjectProperty(None)


class ScreenLogIn(Screen):




    @mainthread
    def verify_credentials(self):


        try:



           if self.ids.login.text == "[email protected]" and self.ids.passw.text == "password":
            self.manager.current = "match"
        else:

            popup = Popup(title='Try again',
                          content=Label(text='Wrong Email/Password'),
                          size_hint=(None, None), size=(400, 400),
                          auto_dismiss=True)
            popup.open()
    except Exception as e:
        pass


class ScreenNearUsers(Screen):

    @mainthread
    def on_enter(self):

    for i in xrange(101):
        button = Button(text="B_" + str(i))
        self.ids.grid.add_widget(button)


class ScreenMatch(Screen):
    pass


class ScreenChats(Screen):
    pass


class ScreenUserProfile(Screen):
    pass


class Manager(ScreenManager):
    screen_log_in = ObjectProperty(None)
    screen_near_user = ObjectProperty(None)
    screen_match = ObjectProperty(None)
    screen_chats = ObjectProperty(None)
    screen_user_profile = ObjectProperty(None)


class MenuApp(App):

    def build(self):
       return Menu()


if __name__ == '__main__':
       MenuApp().run()

Main kv:

<Menu>:
    manager: screen_manager
    orientation: "vertical"
    id: action
ActionBar:
    size_hint_y: 0.1
    background_color: 0, 0, 1000, 10
    background_normal: ""
    ActionView:
        ActionPrevious:
        ActionButton:
            id: near_users
            icon: 'icons/internet.png'
            on_press: root.manager.current = 'near_users'
        ActionButton:
            id: matching_bar
            text: "Matching"
            on_press: root.manager.current= 'match'
        ActionButton:
            id: chat
            text: "chat"
            on_press: root.manager.current = 'chats'
        ActionButton:
            id: profile
            text: "Profile"
            on_press: root.manager.current = 'profile'
Manager:
    id: screen_manager

<ScreenLogIn>:
     orientation: "vertical"
     id: login_screen
     BoxLayout:

     TextInput:
         id: login
     TextInput:
         id: passw
         password: True # hide password
     Button:
         text: "Log In"
         on_release: root.verify_credentials()

<ScreenNearUsers>:
    ScrollView:
        GridLayout:
            id: grid
            size_hint_y: None
            height: self.minimum_height
            cols: 2
            row_default_height: '20dp'
            row_force_default: True
            spacing: 0, 0
            padding: 0, 0

<ScreenMatch>:
    Button:
        text:

<ScreenChats>:
    Button:
        text: "stuff3"

<ScreenUserProfile>:
    Button:
        text: "stuff4"

<Manager>:
    id: screen_manager
    screen_log_in: screen_log_in
    screen_near_users: screen_near_users
    screen_match: screen_match
    screen_chats: screen_chats
    screen_user_profile: screen_user_profile

ScreenLogIn:
    id: screen_log_in
    name: 'login'
    manager: screen_manager
ScreenNearUsers:
    id: screen_near_users
    name: 'near_users'
    manager: screen_manager
ScreenMatch:
    id: screen_match
    name: 'match'
    manager: screen_manager
ScreenChats:
    id: screen_chats
    name: 'chats'
    manager: screen_manager
ScreenUserProfile:
    id: screen_user_profile
    name: 'profile'
    manger: screen_manager

Solution

  • Solution

    Use a BooleanProperty and ActionButton's disabled attribute (gray out ActionButtons) to prevent users from accessing the other screens.

    Python Code

    1. Add BooleanProperty to import statement, from kivy.properties import ObjectProperty, BooleanProperty
    2. Add BooleanProperty, access_denied = BooleanProperty(True) in class Menu()
    3. In verify_credentials() method, if password matched, set access_denied to False, else set it to True.

    Snippet

    from kivy.properties import ObjectProperty, BooleanProperty
    ...
    class Menu(BoxLayout):
        access_denied = BooleanProperty(True)
    
    
    class ScreenLogIn(Screen):
    
        def verify_credentials(self):
            try:
                if self.ids.login.text == "[email protected]" and self.ids.passw.text == "password":
                    App.get_running_app().root.access_denied = False
                    self.manager.current = "match"
                else:
                    App.get_running_app().root.access_denied = True
                    popup = Popup(title='Try again',
                                  content=Label(text='Wrong Email/Password'),
                                  size_hint=(None, None), size=(400, 400),
                                  auto_dismiss=True)
                    popup.open()
            except Exception as e:
                pass
    

    kv file

    1. Check BooleanProperty, access_denied in each ActionButton

    Snippet

            ActionButton:
                id: near_users
                icon: 'icons/internet.png'
                disabled: True if root.access_denied else False
                on_press: root.manager.current = 'near_users'
    
            ActionButton:
                id: matching_bar
                text: "Matching"
                disabled: True if root.access_denied else False
                on_press: root.manager.current= 'match'
    
            ActionButton:
                id: chat
                text: "chat"
                disabled: True if root.access_denied else False
                on_press: root.manager.current = 'chats'
    
            ActionButton:
                id: profile
                text: "Profile"
                disabled: True if root.access_denied else False
                on_press: root.manager.current = 'profile'
    

    Screen's default property manager

    Each screen has by default a property manager that gives you the instance of the ScreenManager used.

    Example

    main.py

    from kivy.app import App
    from kivy.uix.screenmanager import ScreenManager, Screen
    from kivy.properties import ObjectProperty, BooleanProperty
    from kivy.uix.boxlayout import BoxLayout
    from kivy.lang import Builder
    from kivy.uix.popup import Popup
    from kivy.uix.label import Label
    from kivy.uix.button import Button
    
    
    Builder.load_file('main.kv')
    
    
    class Menu(BoxLayout):
        access_denied = BooleanProperty(True)
    
    
    class ScreenLogIn(Screen):
    
        def verify_credentials(self):
            try:
                if self.ids.login.text == "[email protected]" and self.ids.passw.text == "password":
                    App.get_running_app().root.access_denied = False
                    self.manager.current = "match"
                else:
                    App.get_running_app().root.access_denied = True
                    popup = Popup(title='Try again',
                                  content=Label(text='Wrong Email/Password'),
                                  size_hint=(None, None), size=(400, 400),
                                  auto_dismiss=True)
                    popup.open()
            except Exception as e:
                pass
    
    
    class ScreenNearUsers(Screen):
    
        def on_enter(self):
            for i in range(101):
                button = Button(text="B_" + str(i))
                self.ids.grid.add_widget(button)
    
    
    class ScreenMatch(Screen):
        pass
    
    
    class ScreenChats(Screen):
        pass
    
    
    class ScreenUserProfile(Screen):
        pass
    
    
    class Manager(ScreenManager):
        screen_log_in = ObjectProperty(None)
        screen_near_user = ObjectProperty(None)
        screen_match = ObjectProperty(None)
        screen_chats = ObjectProperty(None)
        screen_user_profile = ObjectProperty(None)
    
    
    class MenuApp(App):
    
        def build(self):
            return Menu()
    
    
    if __name__ == '__main__':
        MenuApp().run()
    

    main.kv

    #:kivy 1.11.0
    
    <Menu>:
        manager: screen_manager
        orientation: "vertical"
        id: action
    
        ActionBar:
            size_hint_y: 0.1
            background_color: 0, 0, 1000, 10
            background_normal: ""
    
            ActionView:
                ActionPrevious:
    
                ActionButton:
                    id: near_users
                    icon: 'icons/internet.png'
                    disabled: True if root.access_denied else False
                    on_press: root.manager.current = 'near_users'
    
                ActionButton:
                    id: matching_bar
                    text: "Matching"
                    disabled: True if root.access_denied else False
                    on_press: root.manager.current= 'match'
    
                ActionButton:
                    id: chat
                    text: "chat"
                    disabled: True if root.access_denied else False
                    on_press: root.manager.current = 'chats'
    
                ActionButton:
                    id: profile
                    text: "Profile"
                    disabled: True if root.access_denied else False
                    on_press: root.manager.current = 'profile'
    
        Manager:
            id: screen_manager
    
    <ScreenLogIn>:
        orientation: "vertical"
        id: login_screen
        BoxLayout:
            TextInput:
                id: login
            TextInput:
                id: passw
                password: True # hide password
            Button:
                text: "Log In"
                on_release: root.verify_credentials()
    
    <ScreenNearUsers>:
        ScrollView:
            GridLayout:
                id: grid
                size_hint_y: None
                height: self.minimum_height
                cols: 2
                row_default_height: '20dp'
                row_force_default: True
                spacing: 0, 0
                padding: 0, 0
    
    <ScreenMatch>:
        Button:
            text:
    
    <ScreenChats>:
        Button:
            text: "stuff3"
    
    <ScreenUserProfile>:
        Button:
            text: "stuff4"
    
    <Manager>:
        screen_log_in: screen_log_in
        screen_near_users: screen_near_users
        screen_match: screen_match
        screen_chats: screen_chats
        screen_user_profile: screen_user_profile
    
        ScreenLogIn:
            id: screen_log_in
            name: 'login'
    
        ScreenNearUsers:
            id: screen_near_users
            name: 'near_users'
    
        ScreenMatch:
            id: screen_match
            name: 'match'
    
        ScreenChats:
            id: screen_chats
            name: 'chats'
    
        ScreenUserProfile:
            id: screen_user_profile
            name: 'profile'
    

    Output

    Img01 - ActionButton grayed out Img02 - clicked ActionButton near_users