Sideband/sbapp/kivymd/uix/snackbar/snackbar.py
2023-07-10 02:49:58 +02:00

550 lines
14 KiB
Python
Executable File

"""
Components/Snackbar
===================
.. seealso::
`Material Design spec, Snackbars <https://m3.material.io/components/snackbar/overview>`_
.. rubric:: Snackbars provide brief messages about app processes at the bottom
of the screen.
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/snackbar.png
:align: center
Usage
-----
.. code-block:: python
MDSnackbar(
MDLabel(
text="First string",
theme_text_color="Custom",
text_color="#393231",
),
).open()
Example
-------
.. code-block:: python
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.label import MDLabel
from kivymd.uix.snackbar import MDSnackbar
KV = '''
MDScreen:
MDRaisedButton:
text: "Create simple snackbar"
on_release: app.open_snackbar()
pos_hint: {"center_x": .5, "center_y": .5}
'''
class Example(MDApp):
def open_snackbar(self):
MDSnackbar(
MDLabel(
text="First string",
),
).open()
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Orange"
return Builder.load_string(KV)
Example().run()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/snackbar-simple.gif
:align: center
Control width and pos
---------------------
.. code-block:: python
MDSnackbar(
MDLabel(
text="First string",
),
pos=(dp(24), dp(56)),
size_hint_x=0.5,
).open()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/snackbar-widith-and-pos.gif
:align: center
On mobile, use up to two lines of text to communicate the snackbar message:
.. code-block:: python
MDSnackbar(
MDLabel(
text="First string",
theme_text_color="Custom",
text_color="#393231",
),
MDLabel(
text="Second string",
theme_text_color="Custom",
text_color="#393231",
),
y=dp(24),
pos_hint={"center_x": 0.5},
size_hint_x=0.5,
md_bg_color="#E8D8D7",
).open()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/snackbar-two-line.gif
:align: center
Usage action button
-------------------
A snackbar can contain a single action. "Dismiss" or "cancel" actions are
optional:
.. code-block:: python
MDSnackbar(
MDLabel(
text="First string",
theme_text_color="Custom",
text_color="#393231",
),
MDSnackbarActionButton(
text="Done",
theme_text_color="Custom",
text_color="#8E353C",
),
y=dp(24),
pos_hint={"center_x": 0.5},
size_hint_x=0.5,
md_bg_color="#E8D8D7",
).open()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/snackbar-action-button.gif
:align: center
Callback action button
----------------------
.. code-block:: python
def snackbar_action_button_callback(self, *args):
print("Snackbar callback action button")
def open_snackbar(self):
self.snackbar = MDSnackbar(
MDLabel(
text="First string",
theme_text_color="Custom",
text_color="#393231",
),
MDSnackbarActionButton(
text="Done",
theme_text_color="Custom",
text_color="#8E353C",
_no_ripple_effect=True,
on_release=self.snackbar_action_button_callback,
),
y=dp(24),
pos_hint={"center_x": 0.5},
size_hint_x=0.5,
md_bg_color="#E8D8D7",
)
self.snackbar.open()
If an action is long, it can be displayed on a third line:
.. code-block:: python
MDSnackbar(
MDLabel(
text="If an action is long, it can be displayed",
theme_text_color="Custom",
text_color="#393231",
),
MDLabel(
text="on a third line.",
theme_text_color="Custom",
text_color="#393231",
),
MDLabel(
text=" ",
),
MDSnackbarActionButton(
text="Action button",
theme_text_color="Custom",
text_color="#8E353C",
y=dp(8),
_no_ripple_effect=True,
),
y=dp(24),
pos_hint={"center_x": 0.5},
size_hint_x=0.5,
md_bg_color="#E8D8D7",
).open()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/snackbar-action-button-on-thrid-line.gif
:align: center
Icon (optional close affordance):
.. code-block:: python
def snackbar_close(self, *args):
self.snackbar.dismiss()
def open_snackbar(self):
self.snackbar = MDSnackbar(
MDLabel(
text="Icon (optional close affordance)",
theme_text_color="Custom",
text_color="#393231",
),
MDSnackbarActionButton(
text="Action button",
theme_text_color="Custom",
text_color="#8E353C",
_no_ripple_effect=True,
),
MDSnackbarCloseButton(
icon="close",
theme_text_color="Custom",
text_color="#8E353C",
_no_ripple_effect=True,
on_release=self.snackbar_close,
),
y=dp(24),
pos_hint={"center_x": 0.5},
size_hint_x=0.5,
md_bg_color="#E8D8D7",
)
self.snackbar.open()
.. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/snackbar-optional-close-affordance.gif
:align: center
API break
=========
1.1.1 version
-------------
.. code-block:: python
snackbar = Snackbar(
text="First string",
snackbar_x="10dp",
snackbar_y="24dp",
)
snackbar.size_hint_x = (
Window.width - (snackbar.snackbar_x * 2)
) / Window.width
snackbar.buttons = [
MDFlatButton(
text="Done",
theme_text_color="Custom",
text_color="#8E353C",
on_release=snackbar.dismiss,
),
]
snackbar.open()
1.2.0 version
-------------
.. code-block:: python
MDSnackbar(
MDLabel(
text="First string",
),
MDSnackbarActionButton(
text="Done",
theme_text_color="Custom",
text_color="#8E353C",
),
y=dp(24),
pos_hint={"center_x": 0.5},
size_hint_x=0.5,
md_bg_color="#E8D8D7",
).open()
"""
__all__ = (
"MDSnackbar",
"MDSnackbarActionButton",
"MDSnackbarCloseButton",
)
import os
from kivy import Logger
from kivy.animation import Animation
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.properties import (
BooleanProperty,
ColorProperty,
ListProperty,
NumericProperty,
OptionProperty,
StringProperty,
)
from kivymd import uix_path
from kivymd.uix.behaviors import MotionShackBehavior
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.button import MDFlatButton, MDIconButton
from kivymd.uix.card import MDCard
from kivymd.uix.label import MDLabel
from kivymd.uix.relativelayout import MDRelativeLayout
with open(
os.path.join(uix_path, "snackbar", "snackbar.kv"), encoding="utf-8"
) as kv_file:
Builder.load_string(kv_file.read())
class SnackbarLabelContainer(MDBoxLayout):
"""Container for placing snackbar text."""
class SnackbarActionButtonContainer(MDRelativeLayout):
"""Container for placing snackbar action button."""
class SnackbarCloseButtonContainer(MDRelativeLayout):
"""Container for placing snackbar close button."""
class MDSnackbarCloseButton(MDIconButton):
"""
Snackbar closed button class.
For more information, see in the
:class:`~kivymd.uix.button.MDIconButton` class documentation.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not self.y and not self.pos_hint:
self.pos_hint = {"center_y": 0.5}
class MDSnackbarActionButton(MDFlatButton):
"""
Snackbar action button class.
For more information, see in the
:class:`~kivymd.uix.button.MDFlatButton` class documentation.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not self.y and not self.pos_hint:
self.pos_hint = {"center_y": 0.5}
class MDSnackbar(MotionShackBehavior, MDCard):
"""
Snackbar class.
.. versionchanged:: 1.2.0
Rename `BaseSnackbar` to `MDSnackbar` class.
For more information, see in the
:class:`~kivymd.uix.card.MDCard` and
:class:`~kivymd.uix.behaviors.StencilBehavior`
class documentation.
:Events:
:attr:`on_open`
Called when a snackbar opened.
:attr:`on_dismiss`
Called when a snackbar closes.
"""
duration = NumericProperty(3)
"""
The amount of time that the snackbar will stay on screen for.
:attr:`duration` is a :class:`~kivy.properties.NumericProperty`
and defaults to `3`.
"""
auto_dismiss = BooleanProperty(True)
"""
Whether to use automatic closing of the snackbar or not.
:attr:`auto_dismiss` is a :class:`~kivy.properties.BooleanProperty`
and defaults to `True`.
"""
radius = ListProperty([5, 5, 5, 5])
"""
Snackbar radius.
:attr:`radius` is a :class:`~kivy.properties.ListProperty`
and defaults to `[5, 5, 5, 5]`
"""
bg_color = ColorProperty(None, deprecated=True)
"""
Snackbar background color in (r, g, b, a) or string format.
.. deprecated:: 1.2.0
Use 'md_bg_color` instead.
:attr:`bg_color` is a :class:`~kivy.properties.ColorProperty`
and defaults to `None`.
"""
buttons = ListProperty(deprecated=True)
"""
Snackbar buttons.
.. deprecated:: 1.2.0
:attr:`buttons` is a :class:`~kivy.properties.ListProperty`
and defaults to `[]`
"""
snackbar_animation_dir = OptionProperty(
"Bottom",
options=["Top", "Bottom", "Left", "Right"],
deprecated=True,
)
"""
Snackbar animation direction.
Available options are: `'Top'`, `'Bottom'`, `'Left'`, `'Right'`.
.. deprecated:: 1.2.0
:attr:`snackbar_animation_dir` is an :class:`~kivy.properties.OptionProperty`
and defaults to `'Bottom'`.
"""
snackbar_x = NumericProperty(0, deprecated=True)
"""
The snackbar x position in the screen
.. deprecated:: 1.2.0
:attr:`snackbar_x` is a :class:`~kivy.properties.NumericProperty`
and defaults to `0`.
"""
snackbar_y = NumericProperty(0, deprecated=True)
"""
The snackbar x position in the screen
.. deprecated:: 1.2.0
:attr:`snackbar_y` is a :class:`~kivy.properties.NumericProperty`
and defaults to `0`.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.register_event_type("on_open")
self.register_event_type("on_dismiss")
self.opacity = 0
def dismiss(self, *args) -> None:
"""Dismiss the snackbar."""
super().on_dismiss()
def open(self) -> None:
"""Show the snackbar."""
for widget in Window.parent.children:
if widget.__class__ is MDSnackbar:
return
Window.parent.add_widget(self)
super().on_open()
def add_widget(self, widget, *args, **kwargs):
def check_color(color):
if not widget.text_color:
widget.theme_text_color = "Custom"
widget.text_color = color
if isinstance(widget, MDSnackbarCloseButton):
widget.icon_size = "20sp"
check_color("white")
self.ids.close_container.add_widget(widget)
if len(self.ids.close_container.children) >= 2:
Logger.warning(
"KivyMD: "
"Do not use more than one button to close the snackbar. "
"This is contrary to the material design rules "
"of version 3"
)
if isinstance(widget, MDSnackbarActionButton):
self.ids.action_container.add_widget(widget)
check_color(self.theme_cls.primary_color)
if len(self.ids.action_container.children) >= 2:
Logger.warning(
"KivyMD: "
"Do not use more than one action button. "
"This is contrary to the material design rules "
"of version 3"
)
if isinstance(widget, MDLabel):
widget.adaptive_height = True
widget.pos_hint = {"center_y": 0.5}
check_color("white")
self.ids.label_container.add_widget(widget)
if len(self.ids.label_container.children) >= 4:
Logger.warning(
"KivyMD: "
"Do not use more than three lines in the snackbar. "
"This is contrary to the material design rules "
"of version 3"
)
elif isinstance(
widget,
(
SnackbarLabelContainer,
SnackbarActionButtonContainer,
SnackbarCloseButtonContainer,
),
):
return super().add_widget(widget)
def on_open(self, *args) -> None:
"""Called when a snackbar opened."""
def on_dismiss(self, *args) -> None:
"""Called when a snackbar closed."""
class Snackbar(MDSnackbar):
"""
.. deprecated:: 1.2.0
Use :class:`~kivymd.uix.snackbar.MDSnackbar`
class instead.
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Logger.warning(
"KivyMD: "
"The `Snackbar` class has been deprecated. "
"Use the `MDSnackbar` class instead."
)