/kivymd/snackbar.py

https://gitlab.com/nickyspag/KivyMD · Python · 115 lines · 102 code · 12 blank · 1 comment · 11 complexity · e601b8c4d6c6316dcb8a4cb2804ef372 MD5 · raw file

  1. # -*- coding: utf-8 -*-
  2. from collections import deque
  3. from kivy.animation import Animation
  4. from kivy.clock import Clock
  5. from kivy.core.window import Window
  6. from kivy.lang import Builder
  7. from kivy.metrics import dp
  8. from kivy.properties import ObjectProperty, StringProperty, NumericProperty
  9. from kivy.uix.relativelayout import RelativeLayout
  10. from kivymd.material_resources import DEVICE_TYPE
  11. Builder.load_string('''
  12. #:import Window kivy.core.window.Window
  13. #:import get_color_from_hex kivy.utils.get_color_from_hex
  14. #:import MDFlatButton kivymd.button.MDFlatButton
  15. #:import MDLabel kivymd.label.MDLabel
  16. #:import DEVICE_TYPE kivymd.material_resources.DEVICE_TYPE
  17. <_SnackbarWidget>
  18. canvas:
  19. Color:
  20. rgb: get_color_from_hex('323232')
  21. Rectangle:
  22. size: self.size
  23. size_hint_y: None
  24. size_hint_x: 1 if DEVICE_TYPE == 'mobile' else None
  25. height: dp(48) if _label.texture_size[1] < dp(30) else dp(80)
  26. width: dp(24) + _label.width + _spacer.width + root.padding_right if root.button_text == '' else dp(24) + \
  27. _label.width + _spacer.width + _button.width + root.padding_right
  28. top: 0
  29. x: 0 if DEVICE_TYPE == 'mobile' else Window.width/2 - self.width/2
  30. BoxLayout:
  31. width: Window.width - root.padding_right - _spacer.width - dp(24) if DEVICE_TYPE == 'mobile' and \
  32. root.button_text == '' else Window.width - root.padding_right - _button.width - _spacer.width - dp(24) \
  33. if DEVICE_TYPE == 'mobile' else _label.texture_size[0] if (dp(568) - root.padding_right - _button.width - \
  34. _spacer.width - _label.texture_size[0] - dp(24)) >= 0 else (dp(568) - root.padding_right - _button.width - \
  35. _spacer.width - dp(24))
  36. size_hint_x: None
  37. x: dp(24)
  38. MDLabel:
  39. id: _label
  40. text: root.text
  41. size: self.texture_size
  42. BoxLayout:
  43. id: _spacer
  44. size_hint_x: None
  45. x: _label.right
  46. width: 0
  47. MDFlatButton:
  48. id: _button
  49. text: root.button_text
  50. size_hint_x: None
  51. x: _spacer.right if root.button_text != '' else root.right
  52. center_y: root.height/2
  53. on_release: root.button_callback()
  54. ''')
  55. class _SnackbarWidget(RelativeLayout):
  56. text = StringProperty()
  57. button_text = StringProperty()
  58. button_callback = ObjectProperty()
  59. duration = NumericProperty()
  60. padding_right = NumericProperty(dp(24))
  61. def __init__(self, text, duration, button_text='', button_callback=None,
  62. **kwargs):
  63. super(_SnackbarWidget, self).__init__(**kwargs)
  64. self.text = text
  65. self.button_text = button_text
  66. self.button_callback = button_callback
  67. self.duration = duration
  68. self.ids['_label'].text_size = (None, None)
  69. def begin(self):
  70. if self.button_text == '':
  71. self.remove_widget(self.ids['_button'])
  72. else:
  73. self.ids['_spacer'].width = dp(16) if \
  74. DEVICE_TYPE == "mobile" else dp(40)
  75. self.padding_right = dp(16)
  76. Window.add_widget(self)
  77. anim = Animation(y=0, duration=.3, t='out_quad')
  78. anim.start(self)
  79. Clock.schedule_once(lambda dt: self.die(), self.duration)
  80. def die(self):
  81. anim = Animation(top=0, duration=.3, t='out_quad')
  82. anim.bind(on_complete=lambda *args: _play_next(self))
  83. anim.bind(on_complete=lambda *args: Window.remove_widget(self))
  84. anim.start(self)
  85. queue = deque()
  86. playing = False
  87. def make(text, button_text=None, button_callback=None, duration=3):
  88. if button_text is not None and button_callback is not None:
  89. queue.append(_SnackbarWidget(text=text,
  90. button_text=button_text,
  91. button_callback=button_callback,
  92. duration=duration))
  93. else:
  94. queue.append(_SnackbarWidget(text=text,
  95. duration=duration))
  96. _play_next()
  97. def _play_next(dying_widget=None):
  98. global playing
  99. if (dying_widget or not playing) and len(queue) > 0:
  100. playing = True
  101. queue.popleft().begin()
  102. elif len(queue) == 0:
  103. playing = False