├── kivymd ├── tools │ ├── __init__.py │ ├── release │ │ ├── __init__.py │ │ ├── git_commands.py │ │ ├── argument_parser.py │ │ └── update_icons.py │ ├── packaging │ │ ├── __init__.py │ │ ├── __pycache__ │ │ │ ├── __init__.cpython-38.pyc │ │ │ └── __init__.cpython-39.pyc │ │ └── pyinstaller │ │ │ ├── __pycache__ │ │ │ ├── __init__.cpython-38.pyc │ │ │ └── __init__.cpython-39.pyc │ │ │ ├── hook-kivymd.py │ │ │ └── __init__.py │ └── __pycache__ │ │ ├── __init__.cpython-38.pyc │ │ └── __init__.cpython-39.pyc ├── utils │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-38.pyc │ │ ├── __init__.cpython-39.pyc │ │ ├── fitimage.cpython-38.pyc │ │ ├── fitimage.cpython-39.pyc │ │ └── hot_reload_viewer.cpython-39.pyc │ ├── fpsmonitor.py │ ├── asynckivy.py │ ├── cropimage.py │ ├── fitimage.py │ └── hot_reload_viewer.py ├── toast │ ├── kivytoast │ │ ├── __init__.py │ │ ├── __pycache__ │ │ │ ├── __init__.cpython-38.pyc │ │ │ ├── __init__.cpython-39.pyc │ │ │ ├── kivytoast.cpython-38.pyc │ │ │ └── kivytoast.cpython-39.pyc │ │ └── kivytoast.py │ ├── __pycache__ │ │ ├── __init__.cpython-38.pyc │ │ └── __init__.cpython-39.pyc │ ├── __init__.py │ ├── androidtoast │ │ ├── __init__.py │ │ └── androidtoast.py │ ├── LICENSE │ └── README.md ├── images │ ├── folder.png │ ├── quad_shadow-0.png │ ├── quad_shadow-1.png │ ├── quad_shadow-2.png │ ├── rec_shadow-0.png │ ├── rec_shadow-1.png │ ├── transparent.png │ ├── rec_st_shadow-0.png │ ├── rec_st_shadow-1.png │ ├── rec_st_shadow-2.png │ ├── round_shadow-0.png │ ├── round_shadow-1.png │ ├── round_shadow-2.png │ ├── rec_shadow.atlas │ ├── quad_shadow.atlas │ ├── round_shadow.atlas │ └── rec_st_shadow.atlas ├── fonts │ ├── Roboto-Bold.ttf │ ├── Roboto-Thin.ttf │ ├── Roboto-Black.ttf │ ├── Roboto-Italic.ttf │ ├── Roboto-Light.ttf │ ├── Roboto-Medium.ttf │ ├── Roboto-Regular.ttf │ ├── Roboto-BlackItalic.ttf │ ├── Roboto-BoldItalic.ttf │ ├── Roboto-LightItalic.ttf │ ├── Roboto-MediumItalic.ttf │ ├── Roboto-ThinItalic.ttf │ └── materialdesignicons-webfont.ttf ├── __pycache__ │ ├── app.cpython-38.pyc │ ├── app.cpython-39.pyc │ ├── theming.cpython-38.pyc │ ├── theming.cpython-39.pyc │ ├── __init__.cpython-38.pyc │ ├── __init__.cpython-39.pyc │ ├── color_definitions.cpython-38.pyc │ ├── color_definitions.cpython-39.pyc │ ├── factory_registers.cpython-38.pyc │ ├── factory_registers.cpython-39.pyc │ ├── font_definitions.cpython-38.pyc │ ├── font_definitions.cpython-39.pyc │ ├── icon_definitions.cpython-38.pyc │ ├── icon_definitions.cpython-39.pyc │ ├── material_resources.cpython-38.pyc │ ├── material_resources.cpython-39.pyc │ ├── theming_dynamic_text.cpython-38.pyc │ └── theming_dynamic_text.cpython-39.pyc ├── uix │ ├── __pycache__ │ │ ├── card.cpython-38.pyc │ │ ├── card.cpython-39.pyc │ │ ├── chip.cpython-38.pyc │ │ ├── chip.cpython-39.pyc │ │ ├── label.cpython-38.pyc │ │ ├── label.cpython-39.pyc │ │ ├── list.cpython-38.pyc │ │ ├── list.cpython-39.pyc │ │ ├── menu.cpython-38.pyc │ │ ├── __init__.cpython-38.pyc │ │ ├── __init__.cpython-39.pyc │ │ ├── button.cpython-38.pyc │ │ ├── button.cpython-39.pyc │ │ ├── dialog.cpython-38.pyc │ │ ├── dialog.cpython-39.pyc │ │ ├── picker.cpython-38.pyc │ │ ├── picker.cpython-39.pyc │ │ ├── slider.cpython-39.pyc │ │ ├── toolbar.cpython-38.pyc │ │ ├── toolbar.cpython-39.pyc │ │ ├── tooltip.cpython-38.pyc │ │ ├── tooltip.cpython-39.pyc │ │ ├── boxlayout.cpython-38.pyc │ │ ├── boxlayout.cpython-39.pyc │ │ ├── gridlayout.cpython-38.pyc │ │ ├── gridlayout.cpython-39.pyc │ │ ├── textfield.cpython-38.pyc │ │ ├── textfield.cpython-39.pyc │ │ ├── floatlayout.cpython-38.pyc │ │ ├── floatlayout.cpython-39.pyc │ │ ├── stacklayout.cpython-38.pyc │ │ ├── stacklayout.cpython-39.pyc │ │ ├── circularlayout.cpython-38.pyc │ │ ├── circularlayout.cpython-39.pyc │ │ ├── relativelayout.cpython-38.pyc │ │ ├── relativelayout.cpython-39.pyc │ │ ├── selectioncontrol.cpython-38.pyc │ │ └── selectioncontrol.cpython-39.pyc │ ├── behaviors │ │ ├── __pycache__ │ │ │ ├── __init__.cpython-38.pyc │ │ │ ├── __init__.cpython-39.pyc │ │ │ ├── elevation.cpython-38.pyc │ │ │ ├── elevation.cpython-39.pyc │ │ │ ├── focus_behavior.cpython-38.pyc │ │ │ ├── focus_behavior.cpython-39.pyc │ │ │ ├── hover_behavior.cpython-38.pyc │ │ │ ├── hover_behavior.cpython-39.pyc │ │ │ ├── magic_behavior.cpython-38.pyc │ │ │ ├── magic_behavior.cpython-39.pyc │ │ │ ├── ripple_behavior.cpython-38.pyc │ │ │ ├── ripple_behavior.cpython-39.pyc │ │ │ ├── touch_behavior.cpython-38.pyc │ │ │ ├── touch_behavior.cpython-39.pyc │ │ │ ├── backgroundcolor_behavior.cpython-38.pyc │ │ │ └── backgroundcolor_behavior.cpython-39.pyc │ │ ├── __init__.py │ │ ├── touch_behavior.py │ │ ├── focus_behavior.py │ │ ├── magic_behavior.py │ │ ├── toggle_behavior.py │ │ └── backgroundcolor_behavior.py │ ├── screen.py │ ├── relativelayout.py │ ├── floatlayout.py │ ├── boxlayout.py │ ├── gridlayout.py │ ├── stacklayout.py │ ├── __init__.py │ ├── dropdownitem.py │ ├── circularlayout.py │ ├── refreshlayout.py │ └── carousel.py ├── tests │ ├── test_icon_definitions.py │ ├── test_font_definitions.py │ ├── test_app.py │ └── pyinstaller │ │ └── test_pyinstaller_packaging.py ├── stiffscroll │ ├── README.md │ └── LICENSE ├── material_resources.py ├── font_definitions.py ├── app.py ├── __init__.py ├── theming_dynamic_text.py └── factory_registers.py ├── .gitignore ├── icons.ttf ├── reminder.db ├── .gitattributes ├── Roboto-Black.ttf ├── other ├── icon.blend ├── icon.blend1 ├── color scheme.py ├── color scheme.kv ├── gesture pad.py ├── gesture_box.py └── my_gestures.py ├── remindyicon.png ├── Roboto-Medium.ttf ├── Roboto-Regular.ttf ├── reminder design.png ├── pics ├── design style.webp ├── Color inspiration.png ├── reminder design.png ├── reminder design style.png ├── todo_and_translator_4x.webp ├── Color Hunt Palette 117601.png ├── Color Hunt Palette 281694.png ├── Color Hunt Palette 282007.png ├── photo_2022-06-01_20-29-57.jpg ├── photo_2022-06-01_20-30-03.jpg ├── 31e41c5e6c832e94816a84b3c08bdf97.webp ├── Screenshot from 2021-03-10 22-46-21.png └── check.svg ├── __pycache__ ├── theming.cpython-38.pyc └── toolbar.cpython-38.pyc ├── suma.py ├── scr ├── ReminderMarkComp.java ├── FullScreenNotify.java ├── ReminderSnooze.java ├── ReminderAlarmReceiver.java └── ReminderRepeatingAlarmReceiver.java ├── README.md ├── theming.py └── reminderscheduler.py /kivymd/tools/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /kivymd/utils/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /kivymd/tools/release/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /kivymd/tools/packaging/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin/ 2 | .buildozer/ 3 | 4 | -------------------------------------------------------------------------------- /icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/icons.ttf -------------------------------------------------------------------------------- /reminder.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/reminder.db -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Roboto-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/Roboto-Black.ttf -------------------------------------------------------------------------------- /other/icon.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/other/icon.blend -------------------------------------------------------------------------------- /remindyicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/remindyicon.png -------------------------------------------------------------------------------- /Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/Roboto-Medium.ttf -------------------------------------------------------------------------------- /Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/Roboto-Regular.ttf -------------------------------------------------------------------------------- /kivymd/toast/kivytoast/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ("toast",) 2 | 3 | from .kivytoast import toast 4 | -------------------------------------------------------------------------------- /other/icon.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/other/icon.blend1 -------------------------------------------------------------------------------- /reminder design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/reminder design.png -------------------------------------------------------------------------------- /pics/design style.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/pics/design style.webp -------------------------------------------------------------------------------- /kivymd/images/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/images/folder.png -------------------------------------------------------------------------------- /pics/Color inspiration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/pics/Color inspiration.png -------------------------------------------------------------------------------- /pics/reminder design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/pics/reminder design.png -------------------------------------------------------------------------------- /kivymd/fonts/Roboto-Bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/fonts/Roboto-Bold.ttf -------------------------------------------------------------------------------- /kivymd/fonts/Roboto-Thin.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/fonts/Roboto-Thin.ttf -------------------------------------------------------------------------------- /kivymd/fonts/Roboto-Black.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/fonts/Roboto-Black.ttf -------------------------------------------------------------------------------- /kivymd/fonts/Roboto-Italic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/fonts/Roboto-Italic.ttf -------------------------------------------------------------------------------- /kivymd/fonts/Roboto-Light.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/fonts/Roboto-Light.ttf -------------------------------------------------------------------------------- /kivymd/fonts/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/fonts/Roboto-Medium.ttf -------------------------------------------------------------------------------- /kivymd/fonts/Roboto-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/fonts/Roboto-Regular.ttf -------------------------------------------------------------------------------- /kivymd/images/quad_shadow-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/images/quad_shadow-0.png -------------------------------------------------------------------------------- /kivymd/images/quad_shadow-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/images/quad_shadow-1.png -------------------------------------------------------------------------------- /kivymd/images/quad_shadow-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/images/quad_shadow-2.png -------------------------------------------------------------------------------- /kivymd/images/rec_shadow-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/images/rec_shadow-0.png -------------------------------------------------------------------------------- /kivymd/images/rec_shadow-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/images/rec_shadow-1.png -------------------------------------------------------------------------------- /kivymd/images/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/images/transparent.png -------------------------------------------------------------------------------- /pics/reminder design style.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/pics/reminder design style.png -------------------------------------------------------------------------------- /kivymd/images/rec_st_shadow-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/images/rec_st_shadow-0.png -------------------------------------------------------------------------------- /kivymd/images/rec_st_shadow-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/images/rec_st_shadow-1.png -------------------------------------------------------------------------------- /kivymd/images/rec_st_shadow-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/images/rec_st_shadow-2.png -------------------------------------------------------------------------------- /kivymd/images/round_shadow-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/images/round_shadow-0.png -------------------------------------------------------------------------------- /kivymd/images/round_shadow-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/images/round_shadow-1.png -------------------------------------------------------------------------------- /kivymd/images/round_shadow-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/images/round_shadow-2.png -------------------------------------------------------------------------------- /pics/todo_and_translator_4x.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/pics/todo_and_translator_4x.webp -------------------------------------------------------------------------------- /__pycache__/theming.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/__pycache__/theming.cpython-38.pyc -------------------------------------------------------------------------------- /__pycache__/toolbar.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/__pycache__/toolbar.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/fonts/Roboto-BlackItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/fonts/Roboto-BlackItalic.ttf -------------------------------------------------------------------------------- /kivymd/fonts/Roboto-BoldItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/fonts/Roboto-BoldItalic.ttf -------------------------------------------------------------------------------- /kivymd/fonts/Roboto-LightItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/fonts/Roboto-LightItalic.ttf -------------------------------------------------------------------------------- /kivymd/fonts/Roboto-MediumItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/fonts/Roboto-MediumItalic.ttf -------------------------------------------------------------------------------- /kivymd/fonts/Roboto-ThinItalic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/fonts/Roboto-ThinItalic.ttf -------------------------------------------------------------------------------- /pics/Color Hunt Palette 117601.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/pics/Color Hunt Palette 117601.png -------------------------------------------------------------------------------- /pics/Color Hunt Palette 281694.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/pics/Color Hunt Palette 281694.png -------------------------------------------------------------------------------- /pics/Color Hunt Palette 282007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/pics/Color Hunt Palette 282007.png -------------------------------------------------------------------------------- /pics/photo_2022-06-01_20-29-57.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/pics/photo_2022-06-01_20-29-57.jpg -------------------------------------------------------------------------------- /pics/photo_2022-06-01_20-30-03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/pics/photo_2022-06-01_20-30-03.jpg -------------------------------------------------------------------------------- /kivymd/__pycache__/app.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/app.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/app.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/app.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/theming.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/theming.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/theming.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/theming.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/card.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/card.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/card.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/card.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/chip.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/chip.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/chip.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/chip.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/label.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/label.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/label.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/label.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/list.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/list.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/list.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/list.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/menu.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/menu.cpython-38.pyc -------------------------------------------------------------------------------- /pics/31e41c5e6c832e94816a84b3c08bdf97.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/pics/31e41c5e6c832e94816a84b3c08bdf97.webp -------------------------------------------------------------------------------- /kivymd/fonts/materialdesignicons-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/fonts/materialdesignicons-webfont.ttf -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/button.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/button.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/button.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/button.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/dialog.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/dialog.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/dialog.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/dialog.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/picker.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/picker.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/picker.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/picker.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/slider.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/slider.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/toolbar.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/toolbar.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/toolbar.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/toolbar.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/tooltip.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/tooltip.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/tooltip.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/tooltip.cpython-39.pyc -------------------------------------------------------------------------------- /pics/Screenshot from 2021-03-10 22-46-21.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/pics/Screenshot from 2021-03-10 22-46-21.png -------------------------------------------------------------------------------- /kivymd/toast/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/toast/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/toast/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/toast/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/tools/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/tools/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/tools/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/tools/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/boxlayout.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/boxlayout.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/boxlayout.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/boxlayout.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/gridlayout.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/gridlayout.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/gridlayout.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/gridlayout.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/textfield.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/textfield.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/textfield.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/textfield.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/utils/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/utils/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/utils/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/utils/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/utils/__pycache__/fitimage.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/utils/__pycache__/fitimage.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/utils/__pycache__/fitimage.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/utils/__pycache__/fitimage.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/color_definitions.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/color_definitions.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/color_definitions.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/color_definitions.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/factory_registers.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/factory_registers.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/factory_registers.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/factory_registers.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/font_definitions.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/font_definitions.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/font_definitions.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/font_definitions.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/icon_definitions.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/icon_definitions.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/icon_definitions.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/icon_definitions.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/floatlayout.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/floatlayout.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/floatlayout.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/floatlayout.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/stacklayout.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/stacklayout.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/stacklayout.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/stacklayout.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/material_resources.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/material_resources.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/material_resources.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/material_resources.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/circularlayout.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/circularlayout.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/circularlayout.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/circularlayout.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/relativelayout.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/relativelayout.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/relativelayout.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/relativelayout.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/theming_dynamic_text.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/theming_dynamic_text.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/__pycache__/theming_dynamic_text.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/__pycache__/theming_dynamic_text.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/selectioncontrol.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/selectioncontrol.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/__pycache__/selectioncontrol.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/__pycache__/selectioncontrol.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/toast/kivytoast/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/toast/kivytoast/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/toast/kivytoast/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/toast/kivytoast/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/tools/packaging/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/tools/packaging/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/tools/packaging/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/tools/packaging/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/elevation.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/elevation.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/elevation.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/elevation.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/utils/__pycache__/hot_reload_viewer.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/utils/__pycache__/hot_reload_viewer.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/toast/kivytoast/__pycache__/kivytoast.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/toast/kivytoast/__pycache__/kivytoast.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/toast/kivytoast/__pycache__/kivytoast.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/toast/kivytoast/__pycache__/kivytoast.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/focus_behavior.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/focus_behavior.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/focus_behavior.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/focus_behavior.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/hover_behavior.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/hover_behavior.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/hover_behavior.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/hover_behavior.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/magic_behavior.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/magic_behavior.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/magic_behavior.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/magic_behavior.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/ripple_behavior.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/ripple_behavior.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/ripple_behavior.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/ripple_behavior.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/touch_behavior.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/touch_behavior.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/touch_behavior.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/touch_behavior.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/tools/packaging/pyinstaller/__pycache__/__init__.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/tools/packaging/pyinstaller/__pycache__/__init__.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/tools/packaging/pyinstaller/__pycache__/__init__.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/tools/packaging/pyinstaller/__pycache__/__init__.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/backgroundcolor_behavior.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/backgroundcolor_behavior.cpython-38.pyc -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__pycache__/backgroundcolor_behavior.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Guhan-SenSam/Reminder-App/HEAD/kivymd/uix/behaviors/__pycache__/backgroundcolor_behavior.cpython-39.pyc -------------------------------------------------------------------------------- /kivymd/toast/__init__.py: -------------------------------------------------------------------------------- 1 | __all__ = ("toast",) 2 | 3 | from kivy.utils import platform 4 | 5 | if platform == "android": 6 | try: 7 | from .androidtoast import toast 8 | except BaseException: 9 | from .kivytoast import toast 10 | else: 11 | from .kivytoast import toast 12 | -------------------------------------------------------------------------------- /kivymd/toast/androidtoast/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Toast for Android device 3 | ======================== 4 | 5 | .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/toast.png 6 | :align: center 7 | 8 | """ 9 | 10 | __all__ = ("toast",) 11 | 12 | from .androidtoast import toast 13 | -------------------------------------------------------------------------------- /kivymd/tests/test_icon_definitions.py: -------------------------------------------------------------------------------- 1 | def test_icons_have_size(): 2 | from kivy.core.text import Label 3 | 4 | from kivymd.icon_definitions import md_icons 5 | 6 | lbl = Label(font_name="Icons") 7 | for icon_name, icon_value in md_icons.items(): 8 | assert len(icon_value) == 1 9 | lbl.refresh() 10 | assert lbl.get_extents(icon_value) is not None 11 | -------------------------------------------------------------------------------- /other/color scheme.py: -------------------------------------------------------------------------------- 1 | from kivymd.app import MDApp 2 | from kivy.lang import Builder 3 | from kivy.uix.boxlayout import BoxLayout 4 | 5 | from kivymd.uix.card import MDCard 6 | 7 | class tempstuff(BoxLayout): 8 | pass 9 | 10 | class Mainapp(MDApp): 11 | 12 | def build(self): 13 | Builder.load_file('test.kv') 14 | return tempstuff() 15 | 16 | Mainapp().run() 17 | -------------------------------------------------------------------------------- /pics/check.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /kivymd/tests/test_font_definitions.py: -------------------------------------------------------------------------------- 1 | def test_fonts_registration(): 2 | # This should register fonts: 3 | from kivy.core.text import LabelBase 4 | 5 | import kivymd # NOQA 6 | 7 | fonts = [ 8 | "Roboto", 9 | "RobotoThin", 10 | "RobotoLight", 11 | "RobotoMedium", 12 | "RobotoBlack", 13 | "Icons", 14 | ] 15 | for font in fonts: 16 | assert font in LabelBase._fonts.keys() 17 | -------------------------------------------------------------------------------- /kivymd/tools/packaging/pyinstaller/hook-kivymd.py: -------------------------------------------------------------------------------- 1 | """ 2 | PyInstaller hook for KivyMD 3 | =========================== 4 | 5 | Adds fonts and images to package. 6 | 7 | All modules from uix directory are added by Kivy hook. 8 | """ 9 | 10 | from pathlib import Path 11 | 12 | import kivymd 13 | 14 | datas = [ 15 | ( 16 | kivymd.fonts_path, 17 | str(Path("kivymd").joinpath(Path(kivymd.fonts_path).name)), 18 | ), 19 | ( 20 | kivymd.images_path, 21 | str(Path("kivymd").joinpath(Path(kivymd.images_path).name)), 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /kivymd/tests/test_app.py: -------------------------------------------------------------------------------- 1 | from kivy import lang 2 | from kivy.clock import Clock 3 | from kivy.tests.common import GraphicUnitTest 4 | 5 | from kivymd.app import MDApp 6 | from kivymd.theming import ThemeManager 7 | 8 | 9 | class AppTest(GraphicUnitTest): 10 | def test_start_raw_app(self): 11 | lang._delayed_start = None 12 | a = MDApp() 13 | Clock.schedule_once(a.stop, 0.1) 14 | a.run() 15 | 16 | def test_theme_manager_existance(self): 17 | lang._delayed_start = None 18 | a = MDApp() 19 | Clock.schedule_once(a.stop, 0.1) 20 | a.run() 21 | assert isinstance(a.theme_cls, ThemeManager) 22 | -------------------------------------------------------------------------------- /kivymd/images/rec_shadow.atlas: -------------------------------------------------------------------------------- 1 | {"rec_shadow-1.png": {"20": [2, 266, 256, 128], "21": [260, 266, 256, 128], "22": [518, 266, 256, 128], "23": [776, 266, 256, 128], "3": [260, 136, 256, 128], "2": [2, 136, 256, 128], "5": [776, 136, 256, 128], "4": [518, 136, 256, 128], "7": [260, 6, 256, 128], "6": [2, 6, 256, 128], "9": [776, 6, 256, 128], "8": [518, 6, 256, 128]}, "rec_shadow-0.png": {"11": [518, 266, 256, 128], "10": [260, 266, 256, 128], "13": [2, 136, 256, 128], "12": [776, 266, 256, 128], "15": [518, 136, 256, 128], "14": [260, 136, 256, 128], "17": [2, 6, 256, 128], "16": [776, 136, 256, 128], "19": [518, 6, 256, 128], "18": [260, 6, 256, 128], "1": [776, 6, 256, 128], "0": [2, 266, 256, 128]}} -------------------------------------------------------------------------------- /kivymd/images/quad_shadow.atlas: -------------------------------------------------------------------------------- 1 | {"quad_shadow-1.png": {"20": [2, 136, 128, 128], "21": [132, 136, 128, 128], "22": [262, 136, 128, 128], "23": [2, 6, 128, 128], "19": [132, 266, 128, 128], "18": [2, 266, 128, 128], "1": [262, 266, 128, 128], "3": [262, 6, 128, 128], "2": [132, 6, 128, 128]}, "quad_shadow-0.png": {"11": [262, 266, 128, 128], "10": [132, 266, 128, 128], "13": [132, 136, 128, 128], "12": [2, 136, 128, 128], "15": [2, 6, 128, 128], "14": [262, 136, 128, 128], "17": [262, 6, 128, 128], "16": [132, 6, 128, 128], "0": [2, 266, 128, 128]}, "quad_shadow-2.png": {"5": [132, 266, 128, 128], "4": [2, 266, 128, 128], "7": [2, 136, 128, 128], "6": [262, 266, 128, 128], "9": [262, 136, 128, 128], "8": [132, 136, 128, 128]}} -------------------------------------------------------------------------------- /kivymd/images/round_shadow.atlas: -------------------------------------------------------------------------------- 1 | {"round_shadow-1.png": {"20": [2, 136, 128, 128], "21": [132, 136, 128, 128], "22": [262, 136, 128, 128], "23": [2, 6, 128, 128], "19": [132, 266, 128, 128], "18": [2, 266, 128, 128], "1": [262, 266, 128, 128], "3": [262, 6, 128, 128], "2": [132, 6, 128, 128]}, "round_shadow-0.png": {"11": [262, 266, 128, 128], "10": [132, 266, 128, 128], "13": [132, 136, 128, 128], "12": [2, 136, 128, 128], "15": [2, 6, 128, 128], "14": [262, 136, 128, 128], "17": [262, 6, 128, 128], "16": [132, 6, 128, 128], "0": [2, 266, 128, 128]}, "round_shadow-2.png": {"5": [132, 266, 128, 128], "4": [2, 266, 128, 128], "7": [2, 136, 128, 128], "6": [262, 266, 128, 128], "9": [262, 136, 128, 128], "8": [132, 136, 128, 128]}} -------------------------------------------------------------------------------- /kivymd/images/rec_st_shadow.atlas: -------------------------------------------------------------------------------- 1 | {"rec_st_shadow-0.png": {"11": [262, 138, 128, 256], "10": [132, 138, 128, 256], "13": [522, 138, 128, 256], "12": [392, 138, 128, 256], "15": [782, 138, 128, 256], "14": [652, 138, 128, 256], "16": [912, 138, 128, 256], "0": [2, 138, 128, 256]}, "rec_st_shadow-1.png": {"20": [522, 138, 128, 256], "21": [652, 138, 128, 256], "17": [2, 138, 128, 256], "23": [912, 138, 128, 256], "19": [262, 138, 128, 256], "18": [132, 138, 128, 256], "22": [782, 138, 128, 256], "1": [392, 138, 128, 256]}, "rec_st_shadow-2.png": {"3": [132, 138, 128, 256], "2": [2, 138, 128, 256], "5": [392, 138, 128, 256], "4": [262, 138, 128, 256], "7": [652, 138, 128, 256], "6": [522, 138, 128, 256], "9": [912, 138, 128, 256], "8": [782, 138, 128, 256]}} -------------------------------------------------------------------------------- /kivymd/uix/behaviors/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Behaviors 3 | ========= 4 | 5 | Modules and classes implementing various behaviors for buttons etc. 6 | """ 7 | 8 | # flake8: NOQA 9 | from .hover_behavior import HoverBehavior # isort:skip 10 | from .backgroundcolor_behavior import ( 11 | BackgroundColorBehavior, 12 | SpecificBackgroundColorBehavior, 13 | ) 14 | from .elevation import ( 15 | CircularElevationBehavior, 16 | CommonElevationBehavior, 17 | FakeCircularElevationBehavior, 18 | FakeRectangularElevationBehavior, 19 | ObservableShadow, 20 | RectangularElevationBehavior, 21 | RoundedRectangularElevationBehavior, 22 | ) 23 | from .focus_behavior import FocusBehavior 24 | from .magic_behavior import MagicBehavior 25 | from .ripple_behavior import CircularRippleBehavior, RectangularRippleBehavior 26 | from .touch_behavior import TouchBehavior 27 | -------------------------------------------------------------------------------- /kivymd/uix/screen.py: -------------------------------------------------------------------------------- 1 | """ 2 | Components/Screen 3 | ================= 4 | 5 | :class:`~kivy.uix.screenmanager.Screen` class equivalent. Simplifies working 6 | with some widget properties. For example: 7 | 8 | Screen 9 | ------ 10 | 11 | .. code-block:: 12 | 13 | Screen: 14 | canvas: 15 | Color: 16 | rgba: app.theme_cls.primary_color 17 | RoundedRectangle: 18 | pos: self.pos 19 | size: self.size 20 | radius: [25, 0, 0, 0] 21 | 22 | MDScreen 23 | -------- 24 | 25 | .. code-block:: 26 | 27 | MDScreen: 28 | radius: [25, 0, 0, 0] 29 | md_bg_color: app.theme_cls.primary_color 30 | """ 31 | 32 | from kivy.uix.screenmanager import Screen 33 | 34 | from kivymd.uix import MDAdaptiveWidget 35 | 36 | 37 | class MDScreen(Screen, MDAdaptiveWidget): 38 | pass 39 | -------------------------------------------------------------------------------- /other/color scheme.kv: -------------------------------------------------------------------------------- 1 | : 2 | MDCard: 3 | md_bg_color:44/250,62/250,80/250, 1 4 | 5 | Label: 6 | text:'44,62,80, 1 (Main Background Color)' 7 | bold: True 8 | 9 | MDCard: 10 | md_bg_color:50/255,49/255,61/255,1 11 | 12 | Label: 13 | text:'50,49,61,1 (Primary card color)' 14 | bold: True 15 | 16 | MDCard: 17 | md_bg_color:70/255,69/255,81/255,1 18 | 19 | Label: 20 | text:'70,69,81,1 (Secondary card color)' 21 | bold: True 22 | 23 | MDCard: 24 | md_bg_color:90/255,89/255,101/255,1 25 | 26 | Label: 27 | text:'90,89,101,1 (Tertiary card color)' 28 | bold: True 29 | 30 | MDCard: 31 | md_bg_color:218/255,68/255,83/255, 1 32 | 33 | Label: 34 | text:'218,68,83, 1 (Primary accent color)' 35 | bold: True 36 | -------------------------------------------------------------------------------- /kivymd/uix/relativelayout.py: -------------------------------------------------------------------------------- 1 | """ 2 | Components/Relative Layout 3 | ========================== 4 | 5 | :class:`~kivy.uix.relativelayout.RelativeLayout` class equivalent. Simplifies working 6 | with some widget properties. For example: 7 | 8 | RelativeLayout 9 | -------------- 10 | 11 | .. code-block:: 12 | 13 | RelativeLayout: 14 | canvas: 15 | Color: 16 | rgba: app.theme_cls.primary_color 17 | RoundedRectangle: 18 | pos: (0, 0) 19 | size: self.size 20 | radius: [25, ] 21 | 22 | MDRelativeLayout 23 | ---------------- 24 | 25 | .. code-block:: 26 | 27 | MDRelativeLayout: 28 | radius: [25, ] 29 | md_bg_color: app.theme_cls.primary_color 30 | """ 31 | 32 | from kivy.uix.relativelayout import RelativeLayout 33 | 34 | from kivymd.uix import MDAdaptiveWidget 35 | 36 | 37 | class MDRelativeLayout(RelativeLayout, MDAdaptiveWidget): 38 | pass 39 | -------------------------------------------------------------------------------- /suma.py: -------------------------------------------------------------------------------- 1 | """ 2 | Loading multiple instances of a widget over a period of time to prevent lag 3 | """ 4 | 5 | from kivy.app import App 6 | from kivy.lang import Builder 7 | from kivy.clock import Clock 8 | from kivy.uix.button import Button 9 | from kivy.animation import Animation 10 | 11 | 12 | KV = ''' 13 | GridLayout: 14 | id:container 15 | cols:5 16 | rows:20 17 | ''' 18 | 19 | 20 | class MessengerApp(App): 21 | 22 | counter = 0 23 | 24 | def build(self): 25 | self.kv = Builder.load_string(KV) 26 | return self.kv 27 | 28 | def on_start(self): 29 | Clock.schedule_interval(self.btn_create,0.3) 30 | 31 | def btn_create(self,time): 32 | if self.counter<50: 33 | btn = Button(text = str(self.counter)) 34 | btn.opacity = 0 # Set the opacity of the button to 0 35 | self.kv.add_widget(btn) # Add the button 36 | Animation(opacity = 1, duration = .25).start(btn) # Duration is < than clock duration 37 | self.counter +=1 38 | 39 | 40 | if __name__ == '__main__': 41 | MessengerApp().run() 42 | -------------------------------------------------------------------------------- /kivymd/stiffscroll/README.md: -------------------------------------------------------------------------------- 1 | stiffscroll 2 | =========== 3 | 4 | A ScrollEffect for use with a Kivy ScrollView. It makes scrolling more 5 | laborious as you reach the edge of the scrollable area. 6 | 7 | A ScrollView constructed with StiffScrollEffect, 8 | eg. ScrollView(effect_cls=StiffScrollEffect), will get harder to 9 | scroll as you get nearer to its edges. You can scroll all the way to 10 | the edge if you want to, but it will take more finger-movement than 11 | usual. 12 | 13 | Unlike DampedScrollEffect, it is impossible to overscroll with 14 | StiffScrollEffect. That means you cannot push the contents of the 15 | ScrollView far enough to see what's beneath them. This is appropriate 16 | if the ScrollView contains, eg., a background image, like a desktop 17 | wallpaper. Overscrolling may give the impression that there is some 18 | reason to overscroll, even if just to take a peek beneath, and that 19 | impression may be misleading. 20 | 21 | StiffScrollEffect was written by Zachary Spector. His other stuff is at: 22 | https://github.com/LogicalDash/ 23 | He can be reached, and possibly hired, at: 24 | zacharyspector@gmail.com -------------------------------------------------------------------------------- /kivymd/uix/floatlayout.py: -------------------------------------------------------------------------------- 1 | """ 2 | Components/Float Layout 3 | ======================= 4 | 5 | :class:`~kivy.uix.floatlayout.FloatLayout` class equivalent. Simplifies working 6 | with some widget properties. For example: 7 | 8 | FloatLayout 9 | ----------- 10 | 11 | .. code-block:: 12 | 13 | FloatLayout: 14 | canvas: 15 | Color: 16 | rgba: app.theme_cls.primary_color 17 | RoundedRectangle: 18 | pos: self.pos 19 | size: self.size 20 | radius: [25, 0, 0, 0] 21 | 22 | MDFloatLayout 23 | ------------- 24 | 25 | .. code-block:: 26 | 27 | MDFloatLayout: 28 | radius: [25, 0, 0, 0] 29 | md_bg_color: app.theme_cls.primary_color 30 | 31 | .. Warning:: For a :class:`~kivy.uix.floatlayout.FloatLayout`, the 32 | ``minimum_size`` attributes are always 0, so you cannot use 33 | ``adaptive_size`` and related options. 34 | """ 35 | 36 | from kivy.uix.floatlayout import FloatLayout 37 | 38 | from kivymd.uix import MDAdaptiveWidget 39 | 40 | 41 | class MDFloatLayout(FloatLayout, MDAdaptiveWidget): 42 | pass 43 | -------------------------------------------------------------------------------- /kivymd/utils/fpsmonitor.py: -------------------------------------------------------------------------------- 1 | """ 2 | Monitor module 3 | ============== 4 | 5 | The Monitor module is a toolbar that shows the activity of your current 6 | application : 7 | 8 | * FPS 9 | 10 | """ 11 | 12 | from kivy.clock import Clock 13 | from kivy.lang import Builder 14 | from kivy.properties import NumericProperty, StringProperty 15 | from kivy.uix.label import Label 16 | 17 | Builder.load_string( 18 | """ 19 | : 20 | size_hint_y: None 21 | height: self.texture_size[1] 22 | text: root._fsp_value 23 | pos_hint: {"top": 1} 24 | 25 | canvas.before: 26 | Color: 27 | rgba: app.theme_cls.primary_dark 28 | Rectangle: 29 | pos: self.pos 30 | size: self.size 31 | """ 32 | ) 33 | 34 | 35 | class FpsMonitor(Label): 36 | updated_interval = NumericProperty(0.5) 37 | """FPS refresh rate.""" 38 | 39 | _fsp_value = StringProperty() 40 | 41 | def start(self): 42 | Clock.schedule_interval(self.update_fps, self.updated_interval) 43 | 44 | def update_fps(self, *args): 45 | self._fsp_value = "FPS: %f" % Clock.get_fps() 46 | -------------------------------------------------------------------------------- /kivymd/stiffscroll/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 LogicalDash 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /kivymd/material_resources.py: -------------------------------------------------------------------------------- 1 | """ 2 | Material Resources 3 | ================== 4 | """ 5 | 6 | import os 7 | 8 | from kivy.core.window import Window 9 | from kivy.metrics import dp 10 | from kivy.utils import platform 11 | 12 | if "KIVY_DOC_INCLUDE" in os.environ: 13 | dp = lambda x: x # NOQA: F811 14 | 15 | # Feel free to override this const if you're designing for a device such as 16 | # a GNU/Linux tablet. 17 | DEVICE_IOS = platform == "ios" or platform == "macosx" 18 | if platform != "android" and platform != "ios": 19 | DEVICE_TYPE = "desktop" 20 | elif Window.width >= dp(600) and Window.height >= dp(600): 21 | DEVICE_TYPE = "tablet" 22 | else: 23 | DEVICE_TYPE = "mobile" 24 | 25 | if DEVICE_TYPE == "mobile": 26 | MAX_NAV_DRAWER_WIDTH = dp(300) 27 | HORIZ_MARGINS = dp(16) 28 | STANDARD_INCREMENT = dp(56) 29 | PORTRAIT_TOOLBAR_HEIGHT = STANDARD_INCREMENT 30 | LANDSCAPE_TOOLBAR_HEIGHT = STANDARD_INCREMENT - dp(8) 31 | else: 32 | MAX_NAV_DRAWER_WIDTH = dp(400) 33 | HORIZ_MARGINS = dp(24) 34 | STANDARD_INCREMENT = dp(64) 35 | PORTRAIT_TOOLBAR_HEIGHT = STANDARD_INCREMENT 36 | LANDSCAPE_TOOLBAR_HEIGHT = STANDARD_INCREMENT 37 | 38 | TOUCH_TARGET_HEIGHT = dp(48) 39 | -------------------------------------------------------------------------------- /kivymd/toast/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Brian - androidtoast library 4 | Copyright (c) 2019 Ivanov Yuri - kivytoast library 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | this software and associated documentation files (the "Software"), to deal in 8 | the Software without restriction, including without limitation the rights to 9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | the Software, and to permit persons to whom the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /kivymd/toast/README.md: -------------------------------------------------------------------------------- 1 | KivyToast 2 | ======== 3 | 4 | A package for working with messages like Toast on Android. It is intended for use in applications written using the Kivy framework. 5 | 6 | This package is an improved version of the package https://github.com/knappador/kivy-toaster in which human toasts are written, written on Kivy. 7 | 8 | 9 | 10 | The package modules are written using the framework for cross-platform development of . 11 | Information about the framework is available at http://kivy.org. 12 | 13 | An example of usage (note that with this import the native implementation of toasts will be used for the Android platform and implementation on Kivy for others: 14 | 15 | ```python 16 | from toast import toast 17 | 18 | ... 19 | 20 | # And then in the code, toasts are available 21 | # by calling the toast function: 22 | toast ('Your message') 23 | ``` 24 | 25 | To force the Kivy implementation on the Android platform, use the import of the form: 26 | 27 | ```python 28 | from toast.kivytoast import toast 29 | ``` 30 | 31 | PROGRAMMING LANGUAGE 32 | -------------------- 33 | Python 2.7 + 34 | 35 | DEPENDENCE 36 | ---------- 37 | The [Kivy] framework (http://kivy.org/docs/installation/installation.html) 38 | 39 | LICENSE 40 | ------- 41 | MIT -------------------------------------------------------------------------------- /scr/ReminderMarkComp.java: -------------------------------------------------------------------------------- 1 | package org.org.remindy; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Intent; 5 | import android.content.Context; 6 | 7 | import android.database.sqlite.SQLiteDatabase; 8 | import android.content.ContentValues; 9 | import androidx.core.app.NotificationManagerCompat; 10 | import android.widget.Toast; 11 | 12 | 13 | public class ReminderMarkComp extends BroadcastReceiver{ 14 | 15 | @Override 16 | public void onReceive(Context context, Intent intent) { 17 | SQLiteDatabase db = SQLiteDatabase.openDatabase("/data/data/org.remindy.remindy/files/app/reminder.db",null,SQLiteDatabase.OPEN_READWRITE); 18 | db.beginTransaction(); 19 | ContentValues cv = new ContentValues(); 20 | cv.put("state",1); 21 | String id = String.valueOf(intent.getShortExtra("IDENTIFICATION", (short) 0)); 22 | long result = db.update(intent.getExtras().getString("CURRENT_LIST"), cv, "rem_id ="+ id , null); 23 | db.setTransactionSuccessful(); 24 | db.endTransaction(); 25 | //Now remove the notification from panel 26 | NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); 27 | notificationManager.cancel(intent.getExtras().getInt("NOTIFICATION_ID")); 28 | //Show a toast to the user 29 | Toast toast = Toast.makeText(context, "Remider Marked Complete", Toast.LENGTH_SHORT); 30 | toast.show(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /scr/FullScreenNotify.java: -------------------------------------------------------------------------------- 1 | package org.org.remindy; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import org.remindy.remindy.R; 6 | import android.os.Build; 7 | import android.view.WindowManager; 8 | import android.content.Context; 9 | import android.app.KeyguardManager; 10 | 11 | public class FullScreenNotify extends Activity { 12 | 13 | public void onCreate(Bundle savedInstanceState) { 14 | //Set parameters to ensure device is woken up 15 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { 16 | setShowWhenLocked(true); 17 | setTurnScreenOn(true); 18 | this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 19 | KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE); 20 | keyguardManager.requestDismissKeyguard(this, null); 21 | 22 | 23 | } else { 24 | this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN | 25 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | 26 | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON, 27 | WindowManager.LayoutParams.FLAG_FULLSCREEN | 28 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | 29 | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | 30 | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); 31 | 32 | }; 33 | super.onCreate(savedInstanceState); 34 | // Load xml file 35 | setContentView(R.layout.fullscreenalarm); 36 | 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /kivymd/uix/boxlayout.py: -------------------------------------------------------------------------------- 1 | """ 2 | Components/Box Layout 3 | ===================== 4 | 5 | :class:`~kivy.uix.boxlayout.BoxLayout` class equivalent. Simplifies working 6 | with some widget properties. For example: 7 | 8 | BoxLayout 9 | --------- 10 | 11 | .. code-block:: 12 | 13 | BoxLayout: 14 | size_hint_y: None 15 | height: self.minimum_height 16 | 17 | canvas: 18 | Color: 19 | rgba: app.theme_cls.primary_color 20 | Rectangle: 21 | pos: self.pos 22 | size: self.size 23 | 24 | MDBoxLayout 25 | ----------- 26 | 27 | .. code-block:: 28 | 29 | MDBoxLayout: 30 | adaptive_height: True 31 | md_bg_color: app.theme_cls.primary_color 32 | 33 | Available options are: 34 | ---------------------- 35 | 36 | - adaptive_height_ 37 | - adaptive_width_ 38 | - adaptive_size_ 39 | 40 | .. adaptive_height: 41 | adaptive_height 42 | --------------- 43 | 44 | .. code-block:: kv 45 | 46 | adaptive_height: True 47 | 48 | Equivalent 49 | 50 | .. code-block:: kv 51 | 52 | size_hint_y: None 53 | height: self.minimum_height 54 | 55 | .. adaptive_width: 56 | adaptive_width 57 | -------------- 58 | 59 | .. code-block:: kv 60 | 61 | adaptive_width: True 62 | 63 | Equivalent 64 | 65 | .. code-block:: kv 66 | 67 | size_hint_x: None 68 | height: self.minimum_width 69 | 70 | .. adaptive_size: 71 | adaptive_size 72 | ------------- 73 | 74 | .. code-block:: kv 75 | 76 | adaptive_size: True 77 | 78 | Equivalent 79 | 80 | .. code-block:: kv 81 | 82 | size_hint: None, None 83 | size: self.minimum_size 84 | """ 85 | 86 | from kivy.uix.boxlayout import BoxLayout 87 | 88 | from kivymd.uix import MDAdaptiveWidget 89 | 90 | 91 | class MDBoxLayout(BoxLayout, MDAdaptiveWidget): 92 | pass 93 | -------------------------------------------------------------------------------- /kivymd/tools/packaging/pyinstaller/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | PyInstaller hooks 3 | ================= 4 | 5 | Add ``hookspath=[kivymd.hooks_path]`` to your .spec file. 6 | 7 | Example of .spec file 8 | ===================== 9 | 10 | .. code-block:: python 11 | 12 | # -*- mode: python ; coding: utf-8 -*- 13 | 14 | import sys 15 | import os 16 | 17 | from kivy_deps import sdl2, glew 18 | 19 | from kivymd import hooks_path as kivymd_hooks_path 20 | 21 | path = os.path.abspath(".") 22 | 23 | a = Analysis( 24 | ["main.py"], 25 | pathex=[path], 26 | hookspath=[kivymd_hooks_path], 27 | win_no_prefer_redirects=False, 28 | win_private_assemblies=False, 29 | cipher=None, 30 | noarchive=False, 31 | ) 32 | pyz = PYZ(a.pure, a.zipped_data, cipher=None) 33 | 34 | exe = EXE( 35 | pyz, 36 | a.scripts, 37 | a.binaries, 38 | a.zipfiles, 39 | a.datas, 40 | *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)], 41 | debug=False, 42 | strip=False, 43 | upx=True, 44 | name="app_name", 45 | console=True, 46 | ) 47 | """ 48 | 49 | __all__ = ("hooks_path", "get_hook_dirs", "get_pyinstaller_tests") 50 | 51 | import os 52 | from pathlib import Path 53 | 54 | import kivymd 55 | 56 | hooks_path = str(Path(__file__).absolute().parent) 57 | """Path to hook directory to use with PyInstaller. 58 | See :mod:`kivymd.tools.packaging.pyinstaller` for more information.""" 59 | 60 | 61 | def get_hook_dirs(): 62 | return [hooks_path] 63 | 64 | 65 | def get_pyinstaller_tests(): 66 | return [os.path.join(kivymd.path, "tests", "pyinstaller")] 67 | 68 | 69 | if __name__ == "__main__": 70 | print(hooks_path) 71 | print(get_hook_dirs()) 72 | print(get_pyinstaller_tests()) 73 | -------------------------------------------------------------------------------- /kivymd/uix/gridlayout.py: -------------------------------------------------------------------------------- 1 | """ 2 | Components/Grid Layout 3 | ====================== 4 | 5 | :class:`~kivy.uix.gridlayout.GridLayout` class equivalent. Simplifies working 6 | with some widget properties. For example: 7 | 8 | GridLayout 9 | ---------- 10 | 11 | .. code-block:: 12 | 13 | GridLayout: 14 | size_hint_y: None 15 | height: self.minimum_height 16 | 17 | canvas: 18 | Color: 19 | rgba: app.theme_cls.primary_color 20 | Rectangle: 21 | pos: self.pos 22 | size: self.size 23 | 24 | MDGridLayout 25 | ------------ 26 | 27 | .. code-block:: 28 | 29 | MDGridLayout: 30 | adaptive_height: True 31 | md_bg_color: app.theme_cls.primary_color 32 | 33 | Available options are: 34 | ---------------------- 35 | 36 | - adaptive_height_ 37 | - adaptive_width_ 38 | - adaptive_size_ 39 | 40 | .. adaptive_height: 41 | adaptive_height 42 | --------------- 43 | 44 | .. code-block:: kv 45 | 46 | adaptive_height: True 47 | 48 | Equivalent 49 | 50 | .. code-block:: kv 51 | 52 | size_hint_y: None 53 | height: self.minimum_height 54 | 55 | .. adaptive_width: 56 | adaptive_width 57 | -------------- 58 | 59 | .. code-block:: kv 60 | 61 | adaptive_width: True 62 | 63 | Equivalent 64 | 65 | .. code-block:: kv 66 | 67 | size_hint_x: None 68 | height: self.minimum_width 69 | 70 | .. adaptive_size: 71 | adaptive_size 72 | ------------- 73 | 74 | .. code-block:: kv 75 | 76 | adaptive_size: True 77 | 78 | Equivalent 79 | 80 | .. code-block:: kv 81 | 82 | size_hint: None, None 83 | size: self.minimum_size 84 | """ 85 | 86 | from kivy.uix.gridlayout import GridLayout 87 | 88 | from kivymd.uix import MDAdaptiveWidget 89 | 90 | 91 | class MDGridLayout(GridLayout, MDAdaptiveWidget): 92 | pass 93 | -------------------------------------------------------------------------------- /kivymd/uix/stacklayout.py: -------------------------------------------------------------------------------- 1 | """ 2 | Components/StackLayout 3 | ====================== 4 | 5 | :class:`~kivy.uix.stacklayout.StackLayout` class equivalent. Simplifies working 6 | with some widget properties. For example: 7 | 8 | StackLayout 9 | ----------- 10 | 11 | .. code-block:: 12 | 13 | StackLayout: 14 | size_hint_y: None 15 | height: self.minimum_height 16 | 17 | canvas: 18 | Color: 19 | rgba: app.theme_cls.primary_color 20 | Rectangle: 21 | pos: self.pos 22 | size: self.size 23 | 24 | MDStackLayout 25 | ------------- 26 | 27 | .. code-block:: 28 | 29 | MDStackLayout: 30 | adaptive_height: True 31 | md_bg_color: app.theme_cls.primary_color 32 | 33 | Available options are: 34 | ---------------------- 35 | 36 | - adaptive_height_ 37 | - adaptive_width_ 38 | - adaptive_size_ 39 | 40 | .. adaptive_height: 41 | adaptive_height 42 | --------------- 43 | 44 | .. code-block:: kv 45 | 46 | adaptive_height: True 47 | 48 | Equivalent 49 | 50 | .. code-block:: kv 51 | 52 | size_hint_y: None 53 | height: self.minimum_height 54 | 55 | .. adaptive_width: 56 | adaptive_width 57 | -------------- 58 | 59 | .. code-block:: kv 60 | 61 | adaptive_width: True 62 | 63 | Equivalent 64 | 65 | .. code-block:: kv 66 | 67 | size_hint_x: None 68 | width: self.minimum_width 69 | 70 | .. adaptive_size: 71 | adaptive_size 72 | ------------- 73 | 74 | .. code-block:: kv 75 | 76 | adaptive_size: True 77 | 78 | Equivalent 79 | 80 | .. code-block:: kv 81 | 82 | size_hint: None, None 83 | size: self.minimum_size 84 | """ 85 | 86 | from kivy.uix.stacklayout import StackLayout 87 | 88 | from kivymd.uix import MDAdaptiveWidget 89 | 90 | 91 | class MDStackLayout(StackLayout, MDAdaptiveWidget): 92 | pass 93 | -------------------------------------------------------------------------------- /kivymd/utils/asynckivy.py: -------------------------------------------------------------------------------- 1 | """ 2 | asynckivy 3 | ========= 4 | 5 | Copyright (c) 2019 Nattōsai Mitō 6 | 7 | GitHub - 8 | https://github.com/gottadiveintopython 9 | GitHub Gist - 10 | https://gist.github.com/gottadiveintopython/5f4a775849f9277081c396de65dc57c1 11 | 12 | """ 13 | 14 | __all__ = ("start", "sleep", "event") 15 | 16 | import types 17 | from collections import namedtuple 18 | from functools import partial 19 | 20 | from kivy.clock import Clock 21 | 22 | CallbackParameter = namedtuple("CallbackParameter", ("args", "kwargs")) 23 | 24 | 25 | def start(coro): 26 | def step(*args, **kwargs): 27 | try: 28 | coro.send(CallbackParameter(args, kwargs))(step) 29 | except StopIteration: 30 | pass 31 | 32 | try: 33 | coro.send(None)(step) 34 | except StopIteration: 35 | pass 36 | 37 | 38 | @types.coroutine 39 | def sleep(duration): 40 | # The partial() here looks meaningless. But this is needed in order 41 | # to avoid weak reference. 42 | param = yield lambda step_coro: Clock.schedule_once( 43 | partial(step_coro), duration 44 | ) 45 | return param.args[0] 46 | 47 | 48 | class event: 49 | def __init__(self, ed, name): 50 | self.bind_id = None 51 | self.ed = ed 52 | self.name = name 53 | 54 | def bind(self, step_coro): 55 | self.bind_id = bind_id = self.ed.fbind(self.name, self.callback) 56 | assert bind_id > 0 # check if binding succeeded 57 | self.step_coro = step_coro 58 | 59 | def callback(self, *args, **kwargs): 60 | self.parameter = CallbackParameter(args, kwargs) 61 | ed = self.ed 62 | ed.unbind_uid(self.name, self.bind_id) 63 | self.step_coro() 64 | 65 | def __await__(self): 66 | yield self.bind 67 | return self.parameter 68 | -------------------------------------------------------------------------------- /kivymd/font_definitions.py: -------------------------------------------------------------------------------- 1 | """ 2 | Themes/Font Definitions 3 | ======================= 4 | 5 | .. seealso:: 6 | 7 | `Material Design spec, The type system `_ 8 | """ 9 | 10 | from kivy.core.text import LabelBase 11 | 12 | from kivymd import fonts_path 13 | 14 | fonts = [ 15 | { 16 | "name": "Roboto", 17 | "fn_regular": fonts_path + "Roboto-Regular.ttf", 18 | "fn_bold": fonts_path + "Roboto-Bold.ttf", 19 | "fn_italic": fonts_path + "Roboto-Italic.ttf", 20 | "fn_bolditalic": fonts_path + "Roboto-BoldItalic.ttf", 21 | }, 22 | { 23 | "name": "RobotoThin", 24 | "fn_regular": fonts_path + "Roboto-Thin.ttf", 25 | "fn_italic": fonts_path + "Roboto-ThinItalic.ttf", 26 | }, 27 | { 28 | "name": "RobotoLight", 29 | "fn_regular": fonts_path + "Roboto-Light.ttf", 30 | "fn_italic": fonts_path + "Roboto-LightItalic.ttf", 31 | }, 32 | { 33 | "name": "RobotoMedium", 34 | "fn_regular": fonts_path + "Roboto-Medium.ttf", 35 | "fn_italic": fonts_path + "Roboto-MediumItalic.ttf", 36 | }, 37 | { 38 | "name": "RobotoBlack", 39 | "fn_regular": fonts_path + "Roboto-Black.ttf", 40 | "fn_italic": fonts_path + "Roboto-BlackItalic.ttf", 41 | }, 42 | { 43 | "name": "Icons", 44 | "fn_regular": fonts_path + "materialdesignicons-webfont.ttf", 45 | }, 46 | ] 47 | 48 | for font in fonts: 49 | LabelBase.register(**font) 50 | 51 | theme_font_styles = [ 52 | "H1", 53 | "H2", 54 | "H3", 55 | "H4", 56 | "H5", 57 | "H6", 58 | "Subtitle1", 59 | "Subtitle2", 60 | "Body1", 61 | "Body2", 62 | "Button", 63 | "Caption", 64 | "Overline", 65 | "Icon", 66 | ] 67 | """ 68 | .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/font-styles-2.png 69 | """ 70 | -------------------------------------------------------------------------------- /scr/ReminderSnooze.java: -------------------------------------------------------------------------------- 1 | package org.org.remindy; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Intent; 5 | import android.content.Context; 6 | import android.app.PendingIntent; 7 | import java.util.Calendar; 8 | import android.app.AlarmManager; 9 | import androidx.core.app.NotificationManagerCompat; 10 | import android.widget.Toast; 11 | 12 | public class ReminderSnooze extends BroadcastReceiver{ 13 | 14 | @Override 15 | public void onReceive(Context context, Intent intent) { 16 | 17 | Intent snoozedrem = new Intent(context,ReminderAlarmReceiver.class); 18 | snoozedrem.putExtra("TITLE", intent.getExtras().getString("TITLE")); 19 | snoozedrem.putExtra("DESCRIPTION", intent.getExtras().getString("DESCRIPTION")); 20 | snoozedrem.putExtra("IDENTIFICATION", intent.getExtras().getShort("IDENTIFICATION")); 21 | snoozedrem.putExtra("CURRENT_LIST", intent.getExtras().getString("CURRENT_LIST")); 22 | snoozedrem.putExtra("INTENT_ID", intent.getExtras().getShort("INTENT_ID")); 23 | PendingIntent pendingsnoozedrem = PendingIntent.getBroadcast(context, intent.getExtras().getShort("INTENT_ID"), snoozedrem, PendingIntent.FLAG_CANCEL_CURRENT); 24 | Calendar calendar = Calendar.getInstance(); 25 | Long timetoring = calendar.getTimeInMillis() + 10*60*60*1000; 26 | AlarmManager alarmManager=(AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 27 | alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,timetoring, pendingsnoozedrem); 28 | 29 | //Now clear the notification from the bar 30 | 31 | NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); 32 | notificationManager.cancel(intent.getExtras().getInt("NOTIFICATION_ID")); 33 | 34 | //Give a toast to the user 35 | Toast toast = Toast.makeText(context, "Snoozed for 10 mins", Toast.LENGTH_SHORT); 36 | toast.show(); 37 | 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /kivymd/tests/pyinstaller/test_pyinstaller_packaging.py: -------------------------------------------------------------------------------- 1 | """ 2 | PyInstaller freezing test 3 | ========================= 4 | 5 | PyInstaller must package KivyMD apps correctly. 6 | """ 7 | 8 | import subprocess 9 | 10 | from PyInstaller import __main__ as pyi_main 11 | 12 | 13 | def test_datas(tmp_path): 14 | """Test fonts and images.""" 15 | app_name = "userapp" 16 | workpath = tmp_path / "build" 17 | distpath = tmp_path / "dist" 18 | app = tmp_path / (app_name + ".py") 19 | app.write_text( 20 | """ 21 | import os 22 | import kivymd 23 | from kivy.core.text import LabelBase 24 | 25 | fonts = os.listdir(kivymd.fonts_path) 26 | print(fonts) 27 | assert "Roboto-Regular.ttf" in fonts 28 | assert "materialdesignicons-webfont.ttf" in fonts 29 | print(LabelBase._fonts.keys()) 30 | assert "Roboto" in LabelBase._fonts.keys() # NOQA 31 | assert "Icons" in LabelBase._fonts.keys() # NOQA 32 | 33 | images = os.listdir(kivymd.images_path) 34 | print(images) 35 | assert "folder.png" in images 36 | assert "rec_shadow.atlas" in images 37 | """ 38 | ) 39 | pyi_main.run( 40 | [ 41 | "--workpath", 42 | str(workpath), 43 | "--distpath", 44 | str(distpath), 45 | "--specpath", 46 | str(tmp_path), 47 | str(app), 48 | ] 49 | ) 50 | subprocess.run([str(distpath / app_name / app_name)], check=True) 51 | 52 | 53 | def test_widgets(tmp_path): 54 | """Test that all widgets are accesible.""" 55 | app_name = "userapp" 56 | workpath = tmp_path / "build" 57 | distpath = tmp_path / "dist" 58 | app = tmp_path / (app_name + ".py") 59 | app.write_text( 60 | """ 61 | import os 62 | import kivymd # NOQA 63 | __import__("kivymd.uix.label") 64 | __import__("kivymd.uix.button") 65 | __import__("kivymd.uix.list") 66 | __import__("kivymd.uix.navigationdrawer") 67 | 68 | print(os.listdir(os.path.dirname(kivymd.uix.__path__[0]))) 69 | """ 70 | ) 71 | pyi_main.run( 72 | [ 73 | "--workpath", 74 | str(workpath), 75 | "--distpath", 76 | str(distpath), 77 | "--specpath", 78 | str(tmp_path), 79 | str(app), 80 | ] 81 | ) 82 | subprocess.run([str(distpath / app_name / app_name)], check=True) 83 | -------------------------------------------------------------------------------- /kivymd/app.py: -------------------------------------------------------------------------------- 1 | """ 2 | Themes/Material App 3 | =================== 4 | 5 | This module contains :class:`MDApp` class that is inherited from 6 | :class:`~kivy.app.App`. :class:`MDApp` has some properties needed for ``KivyMD`` 7 | library (like :attr:`~MDApp.theme_cls`). 8 | 9 | You can turn on the monitor displaying the current ``FPS`` value in your application: 10 | 11 | .. code-block:: python 12 | 13 | KV = ''' 14 | Screen: 15 | 16 | MDLabel: 17 | text: "Hello, World!" 18 | halign: "center" 19 | ''' 20 | 21 | from kivy.lang import Builder 22 | 23 | from kivymd.app import MDApp 24 | 25 | 26 | class MainApp(MDApp): 27 | def build(self): 28 | return Builder.load_string(KV) 29 | 30 | def on_start(self): 31 | self.fps_monitor_start() 32 | 33 | 34 | MainApp().run() 35 | 36 | .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fps-monitor.png 37 | :width: 350 px 38 | :align: center 39 | 40 | """ 41 | 42 | __all__ = ("MDApp",) 43 | 44 | from kivy.app import App 45 | from kivy.properties import ObjectProperty 46 | 47 | from kivymd.theming import ThemeManager 48 | 49 | 50 | class FpsMonitoring: 51 | """Adds a monitor to display the current FPS in the toolbar.""" 52 | 53 | def fps_monitor_start(self): 54 | from kivy.core.window import Window 55 | 56 | from kivymd.utils.fpsmonitor import FpsMonitor 57 | 58 | monitor = FpsMonitor() 59 | monitor.start() 60 | Window.add_widget(monitor) 61 | 62 | 63 | class MDApp(App, FpsMonitoring): 64 | theme_cls = ObjectProperty() 65 | """ 66 | Instance of :class:`~ThemeManager` class. 67 | 68 | .. Warning:: The :attr:`~theme_cls` attribute is already available 69 | in a class that is inherited from the :class:`~MDApp` class. 70 | The following code will result in an error! 71 | 72 | .. code-block:: python 73 | 74 | class MainApp(MDApp): 75 | theme_cls = ThemeManager() 76 | theme_cls.primary_palette = "Teal" 77 | 78 | .. Note:: Correctly do as shown below! 79 | 80 | .. code-block:: python 81 | 82 | class MainApp(MDApp): 83 | def build(self): 84 | self.theme_cls.primary_palette = "Teal" 85 | 86 | :attr:`theme_cls` is an :class:`~kivy.properties.ObjectProperty`. 87 | """ 88 | 89 | def __init__(self, **kwargs): 90 | super().__init__(**kwargs) 91 | self.theme_cls = ThemeManager() 92 | -------------------------------------------------------------------------------- /kivymd/toast/androidtoast/androidtoast.py: -------------------------------------------------------------------------------- 1 | """ 2 | AndroidToast 3 | ============ 4 | 5 | .. rubric:: Native implementation of toast for Android devices. 6 | 7 | .. code-block:: python 8 | 9 | # Will be automatically used native implementation of the toast 10 | # if your application is running on an Android device. 11 | # Otherwise, will be used toast implementation 12 | # from the kivymd/toast/kivytoast package. 13 | 14 | from kivy.lang import Builder 15 | from kivy.uix.screenmanager import ScreenManager 16 | 17 | from kivymd.toast import toast 18 | from kivymd.app import MDApp 19 | 20 | KV = ''' 21 | MDScreen: 22 | 23 | MDFlatButton: 24 | text: "My Toast" 25 | pos_hint:{"center_x": .5, "center_y": .5} 26 | on_press: app.show_toast() 27 | ''' 28 | 29 | 30 | class Test(MDApp): 31 | def build(self): 32 | return Builder.load_string(KV) 33 | 34 | def show_toast(self): 35 | toast("Hello World", True, 80, 200, 0) 36 | 37 | 38 | Test().run() 39 | """ 40 | __all__ = ("toast",) 41 | 42 | from android.runnable import run_on_ui_thread 43 | from jnius import autoclass 44 | 45 | activity = autoclass("org.kivy.android.PythonActivity").mActivity 46 | Toast = autoclass("android.widget.Toast") 47 | String = autoclass("java.lang.String") 48 | 49 | 50 | @run_on_ui_thread 51 | def toast(text, length_long=False, gravity=0, y=0, x=0): 52 | """ 53 | Displays a toast. 54 | 55 | :param length_long: the amount of time (in seconds) that the toast is 56 | visible on the screen. 57 | :param text: text to be displayed in the toast; 58 | :param short_duration: duration of the toast, if `True` the toast 59 | will last 2.3s but if it is `False` the toast will last 3.9s; 60 | :param gravity: refers to the toast position, if it is 80the toast will 61 | be shown below, if it is 40 the toast will be displayed above; 62 | :param y: refers to the vertical position of the toast; 63 | :param x: refers to the horizontal position of the toast; 64 | 65 | Important: if only the text value is specified and the value of 66 | the `gravity`, `y`, `x` parameters is not specified, their values ​​will 67 | be 0 which means that the toast will be shown in the center. 68 | """ 69 | 70 | duration = Toast.LENGTH_SHORT if length_long else Toast.LENGTH_LONG 71 | t = Toast.makeText(activity, String(text), duration) 72 | t.setGravity(gravity, x, y) 73 | t.show() 74 | -------------------------------------------------------------------------------- /kivymd/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | KivyMD 3 | ====== 4 | 5 | .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/previous.png 6 | 7 | Is a collection of Material Design compliant widgets for use with, 8 | `Kivy cross-platform graphical framework `_ 9 | a framework for cross-platform, touch-enabled graphical applications. 10 | The project's goal is to approximate Google's `Material Design spec 11 | `_ as close as possible without 12 | sacrificing ease of use or application performance. 13 | 14 | This library is a fork of the `KivyMD project 15 | `_ the author of which stopped supporting 16 | this project three years ago. We found the strength and brought this project 17 | to a new level. Currently we're in **beta** status, so things are changing 18 | all the time and we cannot promise any kind of API stability. 19 | However it is safe to vendor now and make use of what's currently available. 20 | 21 | Join the project! Just fork the project, branch out and submit a pull request 22 | when your patch is ready. If any changes are necessary, we'll guide you 23 | through the steps that need to be done via PR comments or access to your for 24 | may be requested to outright submit them. If you wish to become a project 25 | developer (permission to create branches on the project without forking for 26 | easier collaboration), have at least one PR approved and ask for it. 27 | If you contribute regularly to the project the role may be offered to you 28 | without asking too. 29 | """ 30 | 31 | import os 32 | 33 | import kivy 34 | from kivy.logger import Logger 35 | 36 | __version__ = "0.104.2.dev0" 37 | """KivyMD version.""" 38 | 39 | release = False 40 | kivy.require("2.0.0") 41 | 42 | try: 43 | from kivymd._version import __date__, __hash__, __short_hash__ 44 | except ImportError: 45 | __hash__ = __short_hash__ = __date__ = "" 46 | 47 | path = os.path.dirname(__file__) 48 | """Path to KivyMD package directory.""" 49 | 50 | fonts_path = os.path.join(path, f"fonts{os.sep}") 51 | """Path to fonts directory.""" 52 | 53 | images_path = os.path.join(path, f"images{os.sep}") 54 | """Path to images directory.""" 55 | 56 | _log_message = ( 57 | "KivyMD:" 58 | + (" Release" if release else "") 59 | + f" {__version__}" 60 | + (f", git-{__short_hash__}" if __short_hash__ else "") 61 | + (f", {__date__}" if __date__ else "") 62 | + f' (installed at "{__file__}")' 63 | ) 64 | Logger.info(_log_message) 65 | 66 | import kivymd.factory_registers # NOQA 67 | import kivymd.font_definitions # NOQA 68 | from kivymd.tools.packaging.pyinstaller import hooks_path # NOQA 69 | -------------------------------------------------------------------------------- /kivymd/tools/release/git_commands.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2020 Artem Bulgakov 2 | # 3 | # This file is distributed under the terms of the same license, 4 | # as the Kivy framework. 5 | 6 | import subprocess 7 | 8 | 9 | def command(cmd: list, capture_output: bool = False) -> str: 10 | """Run system command.""" 11 | print(f"Command: {subprocess.list2cmdline(cmd)}") 12 | if capture_output: 13 | out = subprocess.check_output(cmd) 14 | out = out.decode("utf-8") 15 | print(out.strip()) 16 | return out 17 | else: 18 | subprocess.check_call(cmd) 19 | return "" 20 | 21 | 22 | def get_previous_version() -> str: 23 | """Returns latest tag in git.""" 24 | command(["git", "checkout", "master"]) 25 | old_version = command( 26 | ["git", "describe", "--abbrev=0", "--tags"], capture_output=True 27 | ) 28 | old_version = old_version[:-1] # Remove \n 29 | return old_version 30 | 31 | 32 | def git_clean(ask: bool = True): 33 | """Clean git repository from untracked and changed files.""" 34 | # Check what files will be removed 35 | files_to_clean = command( 36 | ["git", "clean", "-dx", "--force", "--dry-run"], capture_output=True 37 | ).strip() 38 | # Ask before removing 39 | if ask and files_to_clean: 40 | while True: 41 | ans = input("Do you want to remove these files? (yes/no)").lower() 42 | if ans == "y" or ans == "yes": 43 | break 44 | elif ans == "n" or ans == "no": 45 | print("git clean is required. Exit") 46 | exit(0) 47 | 48 | # Remove all untracked files 49 | command(["git", "clean", "-dx", "--force"]) 50 | command(["git", "reset", "--hard"]) 51 | 52 | 53 | def git_commit(message: str, allow_error: bool = False, add_files: list = None): 54 | """Make commit.""" 55 | add_files = add_files if add_files else ["-A"] 56 | command(["git", "add", *add_files]) 57 | try: 58 | command(["git", "commit", "--all", "-m", message]) 59 | except subprocess.CalledProcessError as e: 60 | if not allow_error: 61 | raise e 62 | 63 | 64 | def git_tag(name: str): 65 | """Create tag.""" 66 | command(["git", "tag", name]) 67 | 68 | 69 | def git_push(branches_to_push: list, ask: bool = True, push: bool = False): 70 | """Push all changes.""" 71 | if ask: 72 | push = input("Do you want to push changes? (y)") in ( 73 | "", 74 | "y", 75 | "yes", 76 | ) 77 | 78 | cmd = ["git", "push", "--tags", "origin", "master", *branches_to_push] 79 | if push: 80 | command(cmd) 81 | else: 82 | print( 83 | f"Changes are not pushed. Command for manual pushing: {subprocess.list2cmdline(cmd)}" 84 | ) 85 | 86 | 87 | if __name__ == "__main__": 88 | git_clean(ask=True) 89 | -------------------------------------------------------------------------------- /kivymd/uix/__init__.py: -------------------------------------------------------------------------------- 1 | from kivy.properties import BooleanProperty 2 | from kivy.uix.floatlayout import FloatLayout 3 | from kivy.uix.label import Label 4 | from kivy.uix.screenmanager import Screen 5 | 6 | from kivymd.uix.behaviors import SpecificBackgroundColorBehavior 7 | 8 | 9 | class MDAdaptiveWidget(SpecificBackgroundColorBehavior): 10 | adaptive_height = BooleanProperty(False) 11 | """ 12 | If `True`, the following properties will be applied to the widget: 13 | 14 | .. code-block:: kv 15 | 16 | size_hint_y: None 17 | height: self.minimum_height 18 | 19 | :attr:`adaptive_height` is an :class:`~kivy.properties.BooleanProperty` 20 | and defaults to `False`. 21 | """ 22 | 23 | adaptive_width = BooleanProperty(False) 24 | """ 25 | If `True`, the following properties will be applied to the widget: 26 | 27 | .. code-block:: kv 28 | 29 | size_hint_x: None 30 | width: self.minimum_width 31 | 32 | :attr:`adaptive_width` is an :class:`~kivy.properties.BooleanProperty` 33 | and defaults to `False`. 34 | """ 35 | 36 | adaptive_size = BooleanProperty(False) 37 | """ 38 | If `True`, the following properties will be applied to the widget: 39 | 40 | .. code-block:: kv 41 | 42 | size_hint: None, None 43 | size: self.minimum_size 44 | 45 | :attr:`adaptive_size` is an :class:`~kivy.properties.BooleanProperty` 46 | and defaults to `False`. 47 | """ 48 | 49 | def on_adaptive_height(self, instance, value): 50 | self.size_hint_y = None 51 | if issubclass(self.__class__, Label): 52 | self.bind( 53 | texture_size=lambda *x: self.setter("height")( 54 | self, self.texture_size[1] 55 | ) 56 | ) 57 | else: 58 | if not isinstance(self, (FloatLayout, Screen)): 59 | self.bind(minimum_height=self.setter("height")) 60 | 61 | def on_adaptive_width(self, instance, value): 62 | self.size_hint_x = None 63 | if issubclass(self.__class__, Label): 64 | self.bind( 65 | texture_size=lambda *x: self.setter("width")( 66 | self, self.texture_size[0] 67 | ) 68 | ) 69 | else: 70 | if not isinstance(self, (FloatLayout, Screen)): 71 | self.bind(minimum_width=self.setter("width")) 72 | 73 | def on_adaptive_size(self, instance, value): 74 | self.size_hint = (None, None) 75 | if issubclass(self.__class__, Label): 76 | self.text_size = (None, None) 77 | self.bind( 78 | texture_size=lambda *x: self.setter("size")( 79 | self, self.texture_size 80 | ) 81 | ) 82 | else: 83 | if not isinstance(self, (FloatLayout, Screen)): 84 | self.bind(minimum_size=self.setter("size")) 85 | -------------------------------------------------------------------------------- /kivymd/uix/behaviors/touch_behavior.py: -------------------------------------------------------------------------------- 1 | """ 2 | Behaviors/Touch 3 | =============== 4 | 5 | .. rubric:: Provides easy access to events. 6 | 7 | The following events are available: 8 | 9 | - on_long_touch 10 | - on_double_tap 11 | - on_triple_tap 12 | 13 | Usage 14 | ----- 15 | 16 | .. code-block:: python 17 | 18 | from kivy.lang import Builder 19 | 20 | from kivymd.app import MDApp 21 | from kivymd.uix.behaviors import TouchBehavior 22 | from kivymd.uix.button import MDRaisedButton 23 | 24 | KV = ''' 25 | Screen: 26 | 27 | MyButton: 28 | text: "PRESS ME" 29 | pos_hint: {"center_x": .5, "center_y": .5} 30 | ''' 31 | 32 | 33 | class MyButton(MDRaisedButton, TouchBehavior): 34 | def on_long_touch(self, *args): 35 | print(" event") 36 | 37 | def on_double_tap(self, *args): 38 | print(" event") 39 | 40 | def on_triple_tap(self, *args): 41 | print(" event") 42 | 43 | 44 | class MainApp(MDApp): 45 | def build(self): 46 | return Builder.load_string(KV) 47 | 48 | 49 | MainApp().run() 50 | """ 51 | 52 | __all__ = ("TouchBehavior",) 53 | 54 | from functools import partial 55 | 56 | from kivy.clock import Clock 57 | from kivy.properties import NumericProperty 58 | 59 | 60 | class TouchBehavior: 61 | duration_long_touch = NumericProperty(0.4) 62 | """ 63 | Time for a long touch. 64 | 65 | :attr:`duration_long_touch` is an :class:`~kivy.properties.NumericProperty` 66 | and defaults to `0.4`. 67 | """ 68 | 69 | def __init__(self, **kwargs): 70 | super().__init__(**kwargs) 71 | self.bind( 72 | on_touch_down=self.create_clock, on_touch_up=self.delete_clock 73 | ) 74 | 75 | def create_clock(self, widget, touch, *args): 76 | if self.collide_point(touch.x, touch.y): 77 | callback = partial(self.on_long_touch, touch) 78 | Clock.schedule_once(callback, self.duration_long_touch) 79 | touch.ud["event"] = callback 80 | 81 | def delete_clock(self, widget, touch, *args): 82 | if self.collide_point(touch.x, touch.y): 83 | try: 84 | Clock.unschedule(touch.ud["event"]) 85 | except KeyError: 86 | pass 87 | 88 | if touch.is_double_tap: 89 | self.on_double_tap(touch, *args) 90 | if touch.is_triple_tap: 91 | self.on_triple_tap(touch, *args) 92 | 93 | def on_long_touch(self, touch, *args): 94 | """Called when the widget is pressed for a long time.""" 95 | 96 | def on_double_tap(self, touch, *args): 97 | """Called by double clicking on the widget.""" 98 | 99 | def on_triple_tap(self, touch, *args): 100 | """Called by triple clicking on the widget.""" 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Reminder-App 2 | An android app for creating reminders made using the kivy and kivyMD framework for python. 3 | 4 | ![](https://github.com/Guhan-SenSam/Reminder-App/blob/main/pics/photo_2022-06-01_20-29-57.jpg) 5 | ![](https://github.com/Guhan-SenSam/Reminder-App/blob/main/pics/photo_2022-06-01_20-30-03.jpg) 6 | ![](https://github.com/Guhan-SenSam/Reminder-App/blob/main/reminder%20design.png) 7 | 8 | ## Features 9 | This reminder app organizes your reminders into lists. You can create multiple lists that contains reminders inside them. Each reminder can be set to notify you through notifications on a particular day or date at a specific time. 10 | * Create and delete named lists that can store reminders inside them. 11 | * Create reminderes that have a title and description. A reminder can be set to not notify you, to notify you on particular days(such as Monday, Tuesday, Wednesday etc.) or upto 5 specific dates. You can also set a time at which you want the reminder to ring. 12 | * Reminders appear as notifications. Clicking on the notification takes you directly to the reminder. 13 | * Snooze reminders for a certain amount of time directly from the notification 14 | * Mark reminders as complete direclty from the notification. 15 | * Internal themeing support. 16 | 17 | 18 | ## History 19 | 20 | > This App currently stands as an abandoned project 21 | 22 | 23 | This project was initially started for commercial purposes and to prove a point that commercial scale apps could be made using python and still be performant. It was originally named as Remindy, but unfortunately other apps already exist under that name so as to prevent copyright violations, the name of this repository has been changed. 24 | 25 | The app went through numerous iterations before it reached the stage it is at now and still needs much more to become a full fledged reminder app. Unfortunetly none of those updates or changes will be coming anytime soon. 26 | 27 | ### Why was it abandoned? 28 | 29 | The app's fundamental concept was based on sorting reminders into lists and displaying them as if they are a stack of cards. The App's entire UI was based on this fundamental concept. This presented a really interesting UX interaction with the user but deliverd a lack luster UI experience. Unfortunately I realized this too far into the development of the project that I was forced to scrap the entire idea and hence why the project is now considered as abandoned. 30 | 31 | 32 | ### Did the fact that it was coded in Python affect my Idea to abandon it? 33 | 34 | Not at all. In fact it was python that encouraged me to continue the project even after I knew that the UI was not good. The Kivy library really allows for rapid development of user interfaces. 35 | The performance impact that python had on the app where signifcant and the app incorporates numerous optimization techniques in order to reduce the performance impacts. You are welcome to use the logic I implemented in your own apps to reduce performance issues. 36 | 37 | ## Will the project ever continue again? 38 | 39 | Probably not. The concept of the reminder app may live on in another form but as of now I am focusing on learning more langaiges rather than sticking with just python. 40 | -------------------------------------------------------------------------------- /other/gesture pad.py: -------------------------------------------------------------------------------- 1 | from kivy.app import App 2 | 3 | from kivy.uix.floatlayout import FloatLayout 4 | from kivy.graphics import Color, Ellipse, Line 5 | from kivy.gesture import Gesture, GestureDatabase 6 | 7 | from my_gestures import cross, circle, check, square 8 | 9 | 10 | 11 | def simplegesture(name, point_list): 12 | """ 13 | A simple helper function 14 | """ 15 | g = Gesture() 16 | g.add_stroke(point_list) 17 | g.normalize() 18 | g.name = name 19 | return g 20 | 21 | 22 | class GestureBoard(FloatLayout): 23 | """ 24 | Our application main widget, derived from touchtracer example, use data 25 | constructed from touches to match symboles loaded from my_gestures. 26 | """ 27 | def __init__(self, *args, **kwargs): 28 | super(GestureBoard, self).__init__() 29 | self.gdb = GestureDatabase() 30 | 31 | # add pre-recorded gestures to database 32 | self.gdb.add_gesture(cross) 33 | self.gdb.add_gesture(check) 34 | self.gdb.add_gesture(circle) 35 | self.gdb.add_gesture(square) 36 | 37 | def on_touch_down(self, touch): 38 | # start collecting points in touch.ud 39 | # create a line to display the points 40 | userdata = touch.ud 41 | with self.canvas: 42 | Color(1, 1, 0) 43 | d = 30. 44 | Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d)) 45 | userdata['line'] = Line(points=(touch.x, touch.y)) 46 | return True 47 | 48 | def on_touch_move(self, touch): 49 | # store points of the touch movement 50 | try: 51 | touch.ud['line'].points += [touch.x, touch.y] 52 | return True 53 | except (KeyError) as e: 54 | pass 55 | 56 | def on_touch_up(self, touch): 57 | # touch is over, display informations, and check if it matches some 58 | # known gesture. 59 | g = simplegesture('', list(zip(touch.ud['line'].points[::2], 60 | touch.ud['line'].points[1::2]))) 61 | # gestures to my_gestures.py 62 | print("gesture representation:", self.gdb.gesture_to_str(g)) 63 | 64 | # print match scores between all known gestures 65 | print("cross:", g.get_score(cross)) 66 | print("check:", g.get_score(check)) 67 | print("circle:", g.get_score(circle)) 68 | print("square:", g.get_score(square)) 69 | 70 | # use database to find the more alike gesture, if any 71 | g2 = self.gdb.find(g, minscore=0.60) 72 | 73 | print(g2) 74 | if g2: 75 | if g2[1] == circle: 76 | print("circle") 77 | if g2[1] == square: 78 | print("square") 79 | if g2[1] == check: 80 | print("check") 81 | if g2[1] == cross: 82 | print("cross") 83 | 84 | # erase the lines on the screen, this is a bit quick&dirty, since we 85 | # can have another touch event on the way... 86 | self.canvas.clear() 87 | 88 | 89 | class DemoGesture(App): 90 | def build(self): 91 | return GestureBoard() 92 | 93 | 94 | if __name__ == '__main__': 95 | DemoGesture().run() 96 | -------------------------------------------------------------------------------- /kivymd/theming_dynamic_text.py: -------------------------------------------------------------------------------- 1 | """ 2 | Theming Dynamic Text 3 | ==================== 4 | 5 | Two implementations. The first is based on color brightness obtained from- 6 | https://www.w3.org/TR/AERT#color-contrast 7 | The second is based on relative luminance calculation for sRGB obtained from- 8 | https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef 9 | and contrast ratio calculation obtained from- 10 | https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef 11 | 12 | Preliminary testing suggests color brightness more closely matches the 13 | `Material Design spec` suggested text colors, but the alternative implementation 14 | is both newer and the current 'correct' recommendation, so is included here 15 | as an option. 16 | """ 17 | 18 | 19 | def _color_brightness(color): 20 | # Implementation of color brightness method 21 | brightness = color[0] * 299 + color[1] * 587 + color[2] * 114 22 | brightness = brightness 23 | return brightness 24 | 25 | 26 | def _black_or_white_by_color_brightness(color): 27 | if _color_brightness(color) >= 500: 28 | return "black" 29 | else: 30 | return "white" 31 | 32 | 33 | def _normalized_channel(color): 34 | # Implementation of contrast ratio and relative luminance method 35 | if color <= 0.03928: 36 | return color / 12.92 37 | else: 38 | return ((color + 0.055) / 1.055) ** 2.4 39 | 40 | 41 | def _luminance(color): 42 | rg = _normalized_channel(color[0]) 43 | gg = _normalized_channel(color[1]) 44 | bg = _normalized_channel(color[2]) 45 | return 0.2126 * rg + 0.7152 * gg + 0.0722 * bg 46 | 47 | 48 | def _black_or_white_by_contrast_ratio(color): 49 | l_color = _luminance(color) 50 | l_black = 0.0 51 | l_white = 1.0 52 | b_contrast = (l_color + 0.05) / (l_black + 0.05) 53 | w_contrast = (l_white + 0.05) / (l_color + 0.05) 54 | return "white" if w_contrast >= b_contrast else "black" 55 | 56 | 57 | def get_contrast_text_color(color, use_color_brightness=True): 58 | if use_color_brightness: 59 | contrast_color = _black_or_white_by_color_brightness(color) 60 | else: 61 | contrast_color = _black_or_white_by_contrast_ratio(color) 62 | if contrast_color == "white": 63 | return 1, 1, 1, 1 64 | else: 65 | return 0, 0, 0, 1 66 | 67 | 68 | if __name__ == "__main__": 69 | from kivy.utils import get_color_from_hex 70 | 71 | from kivymd.color_definitions import colors, text_colors 72 | 73 | for c in colors.items(): 74 | if c[0] in ["Light", "Dark"]: 75 | continue 76 | color = c[0] 77 | print(f"For the {color} color palette:") 78 | for name, hex_color in c[1].items(): 79 | if hex_color: 80 | col = get_color_from_hex(hex_color) 81 | col_bri = get_contrast_text_color(col) 82 | con_rat = get_contrast_text_color( 83 | col, use_color_brightness=False 84 | ) 85 | text_color = text_colors[c[0]][name] 86 | print( 87 | f" The {name} hue gives {col_bri} using color " 88 | f"brightness, {con_rat} using contrast ratio, and " 89 | f"{text_color} from the MD spec" 90 | ) 91 | -------------------------------------------------------------------------------- /other/gesture_box.py: -------------------------------------------------------------------------------- 1 | from kivy.gesture import GestureDatabase 2 | from kivy.uix.boxlayout import BoxLayout 3 | from kivy.gesture import Gesture 4 | 5 | gesture_strings = {'swipe_down':'eNp1ln1ME2cYwA9FsBtO2Fwk6Dbix8SJiEvmjGTjothWs4QKQ5hKoB8H11Hb0l5pmSs9R1ZJdlOjpwMkyh/qnMYAf2DEKK0YlbEt8ZMwIYFpsjG/cNlm2HTr2pe73r173/f+edvf73nued7nLm+OTzzgeJECl5BSY62rz6lm3JzHxYhCsk76tV9culP0i1nCDK/VwrGijs6WMpJYxlrNclHyWdMUmS2lVzhdDovHHFOaVeK2wmyvkOzmXI4axi2WiywlzJLuXgygUiPJ6bDauVhQVjQqRYoyxKASlOATdflNkWrjH4fDQkJ99M+9367k/WId8pjYtKkYdo4uv668f+OyHop9VZd/d32wtMlZRPQ/fbvynOWQn+jHHi4NHuz4iOhHF7fUbBjpI/qRfxJ/vfpSFdEPLyne0eVrJfohruXHH56eIPrBwbd8p4bvEv3t+RlpqdPbiP6m/2THo/E7sPdrNeOHMoC/fqlVX5S6l+i/u3i/t+rmCNEPJN/ZPPCMnH854NBev3eL6Pu65hzmjm4j+nNfre3eSk8Sfbc1rWHX2XSiP/60qmTP6v/lf/6Fdt/5x3TMtz5Of9f2ZifJhxpsocZpz8JEf2yiILeglyXVD3XVVrSdHNCTnk+oZ9U39vG5AuztD2aV+jqAD3fnnQ4ur4V8qCRlsleXA/zl945fCKxfCXv3Kxdtzt3A93ddFc78Cfcfqn8+/YXRCeC/F22e220W2POuBR9+fQL4a66B89vbviT6G9nDizTcIOwbf163cLQsHPO3Xl/e3NyfBftdW8y/z9WA+Q1q+zLmHWz0mBghxW12MYxdOSd0tC8XnD7RY6gZ/AhGjx1fpsx8CkuVmR7DUuPM+0RiO9sxrAzD0lHGD2EY5n68E8P0GIbpL9CJsoYxDMPU8F/DsDcisQtin9Jo3I5CNO4TAxpXXxlbE8CcKYn5KpXZy8zrRFldJprraUfjOAMa5+bROBcmt/YJmlubi8Y5A/H9xpmDV3Lld82uzC/ObBUoqzmCso9HUWYNozWsFMrYTLTnagyrwsyewbyTFsw7ZFG9B2MSMyt7izOTMhdvWGJGSsntlFhFWGHtEitXnpt3r8S2grhpENuiuh8vsTIeZaW00ovMSkDL/wLmlJky0zgrVtWVWRGNxm1SzUVmhny0RiFYZ0Dsg4ASVymxjaDRRIjpVXuTmY5CmZZSepZZAY+ydaDuc5hhctdSaC90BO2ZVs1PZu+DdSbE8kDu3xBbg9nHarAmQewdkPsXYAaJvQ3YJMRWADYBsWWqujLLUtWQ2SKwvgyx+WDNhNjUUfyamoEnHokcDYqMx2QUNJzDxriMdjMT/TrtaYldrUKi3bg9+mVNiR5Tzn9685bk' 6 | } 7 | 8 | #This database can compare gestures the user makes to its stored gestures 9 | #and tell us if the user input matches any of them. 10 | gestures = GestureDatabase() 11 | for name, gesture_string in gesture_strings.items(): 12 | gesture = gestures.str_to_gesture(gesture_string) 13 | gesture.name = name 14 | gestures.add_gesture(gesture) 15 | 16 | class GestureBox(BoxLayout): 17 | 18 | def __init__(self, **kwargs): 19 | self.register_event_type('on_swipe_down') 20 | super(GestureBox, self).__init__(**kwargs) 21 | 22 | def on_swipe_down(self): 23 | pass 24 | 25 | 26 | #To recognize a gesture, you’ll need to start recording each individual event in the 27 | #touch_down handler, add the data points for each call to touch_move , and then do the 28 | #gesture calculations when all data points have been received in the touch_up handler. 29 | 30 | def on_touch_down(self, touch): 31 | #create an user defined variable and add the touch coordinates 32 | touch.ud['gesture_path'] = [(touch.x, touch.y)] 33 | super(GestureBox, self).on_touch_down(touch) 34 | 35 | def on_touch_move(self, touch): 36 | touch.ud['gesture_path'].append((touch.x, touch.y)) 37 | super(GestureBox, self).on_touch_move(touch) 38 | 39 | def on_touch_up(self, touch): 40 | if 'gesture_path' in touch.ud: 41 | #create a gesture object 42 | gesture = Gesture() 43 | #add the movement coordinates 44 | gesture.add_stroke(touch.ud['gesture_path']) 45 | #normalize so thwu willtolerate size variations 46 | gesture.normalize() 47 | #minscore to be attained for a match to be true 48 | match = gestures.find(gesture, minscore=0.4) 49 | if match: 50 | print("{} happened".format(match[1].name)) 51 | self.dispatch('on_{}'.format(match[1].name)) 52 | super(GestureBox, self).on_touch_up(touch) 53 | -------------------------------------------------------------------------------- /kivymd/tools/release/argument_parser.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2020 Artem Bulgakov 2 | # 3 | # This file is distributed under the terms of the same license, 4 | # as the Kivy framework. 5 | 6 | import argparse 7 | import sys 8 | 9 | 10 | class ArgumentParserWithHelp(argparse.ArgumentParser): 11 | def parse_args(self, args=None, namespace=None): 12 | # Add help when no arguments specified 13 | if not args and not len(sys.argv) > 1: 14 | self.print_help() 15 | self.exit(1) 16 | return super().parse_args(args, namespace) 17 | 18 | def error(self, message): 19 | # Add full help on error 20 | self.print_help() 21 | self.exit(2, f"\nError: {message}\n") 22 | 23 | def format_help(self): 24 | # Add subparsers usage and help to full help text 25 | formatter = self._get_formatter() 26 | 27 | # Get subparsers 28 | subparsers_actions = [ 29 | action 30 | for action in self._actions 31 | if isinstance(action, argparse._SubParsersAction) 32 | ] 33 | 34 | # Description 35 | formatter.add_text(self.description) 36 | 37 | # Usage 38 | formatter.add_usage( 39 | self.usage, 40 | self._actions, 41 | self._mutually_exclusive_groups, 42 | prefix="Usage:\n", 43 | ) 44 | 45 | # Subparsers usage 46 | for subparsers_action in subparsers_actions: 47 | for choice, subparser in subparsers_action.choices.items(): 48 | formatter.add_usage( 49 | subparser.usage, 50 | subparser._actions, 51 | subparser._mutually_exclusive_groups, 52 | prefix="", 53 | ) 54 | 55 | # Positionals, optionals and user-defined groups 56 | for action_group in self._action_groups: 57 | if not any( 58 | [ 59 | action in subparsers_actions 60 | for action in action_group._group_actions 61 | ] 62 | ): 63 | formatter.start_section(action_group.title) 64 | formatter.add_text(action_group.description) 65 | formatter.add_arguments(action_group._group_actions) 66 | formatter.end_section() 67 | else: 68 | # Process subparsers differently 69 | # Just show list of choices 70 | formatter.start_section(action_group.title) 71 | # formatter.add_text(action_group.description) 72 | for action in action_group._group_actions: 73 | for choice in action.choices: 74 | formatter.add_text(choice) 75 | formatter.end_section() 76 | 77 | # Subparsers help 78 | for subparsers_action in subparsers_actions: 79 | for choice, subparser in subparsers_action.choices.items(): 80 | formatter.start_section(choice) 81 | for action_group in subparser._action_groups: 82 | formatter.start_section(action_group.title) 83 | formatter.add_text(action_group.description) 84 | formatter.add_arguments(action_group._group_actions) 85 | formatter.end_section() 86 | formatter.end_section() 87 | 88 | # Epilog 89 | formatter.add_text(self.epilog) 90 | 91 | # Determine help from format above 92 | return formatter.format_help() 93 | -------------------------------------------------------------------------------- /kivymd/utils/cropimage.py: -------------------------------------------------------------------------------- 1 | """ 2 | Crop Image 3 | ========== 4 | """ 5 | 6 | 7 | def crop_image( 8 | cutting_size, 9 | path_to_image, 10 | path_to_save_crop_image, 11 | corner=0, 12 | blur=0, 13 | corner_mode="all", 14 | ): 15 | """Call functions of cropping/blurring/rounding image. 16 | 17 | cutting_size: size to which the image will be cropped; 18 | path_to_image: path to origin image; 19 | path_to_save_crop_image: path to new image; 20 | corner: value of rounding corners; 21 | blur: blur value; 22 | corner_mode: 'all'/'top'/'bottom' - indicates which corners to round out; 23 | 24 | """ 25 | 26 | im = _crop_image(cutting_size, path_to_image, path_to_save_crop_image) 27 | if corner: 28 | im = add_corners(im, corner, corner_mode) 29 | if blur: 30 | im = add_blur(im, blur) 31 | try: 32 | im.save(path_to_save_crop_image) 33 | except IOError: 34 | im.save(path_to_save_crop_image, "JPEG") 35 | 36 | 37 | def add_blur(im, mode): 38 | from PIL import ImageFilter 39 | 40 | im = im.filter(ImageFilter.GaussianBlur(mode)) 41 | 42 | return im 43 | 44 | 45 | def _crop_image(cutting_size, path_to_image, path_to_save_crop_image): 46 | from PIL import Image, ImageOps 47 | 48 | image = Image.open(path_to_image) 49 | image = ImageOps.fit(image, cutting_size) 50 | image.save(path_to_save_crop_image) 51 | 52 | return image 53 | 54 | 55 | def add_corners(im, corner, corner_mode): 56 | def add_top_corners(): 57 | alpha.paste(circle.crop((0, 0, corner, corner)), (0, 0)) 58 | alpha.paste( 59 | circle.crop((corner, 0, corner * 2, corner)), (w - corner, 0) 60 | ) 61 | 62 | def add_bottom_corners(): 63 | alpha.paste( 64 | circle.crop((0, corner, corner, corner * 2)), (0, h - corner) 65 | ) 66 | alpha.paste( 67 | circle.crop((corner, corner, corner * 2, corner * 2)), 68 | (w - corner, h - corner), 69 | ) 70 | 71 | from PIL import Image, ImageDraw 72 | 73 | circle = Image.new("L", (corner * 2, corner * 2), 0) 74 | draw = ImageDraw.Draw(circle) 75 | draw.ellipse((0, 0, corner * 2, corner * 2), fill=255) 76 | alpha = Image.new("L", im.size, 255) 77 | w, h = im.size 78 | 79 | if corner_mode == "all": 80 | add_top_corners() 81 | add_bottom_corners() 82 | elif corner_mode == "top": 83 | add_top_corners() 84 | if corner_mode == "bottom": 85 | add_bottom_corners() 86 | im.putalpha(alpha) 87 | 88 | return im 89 | 90 | 91 | def prepare_mask(size, antialias=2): 92 | from PIL import Image, ImageDraw 93 | 94 | mask = Image.new("L", (size[0] * antialias, size[1] * antialias), 0) 95 | ImageDraw.Draw(mask).ellipse((0, 0) + mask.size, fill=255) 96 | return mask.resize(size, Image.ANTIALIAS) 97 | 98 | 99 | def _crop_round_image(im, s): 100 | from PIL import Image 101 | 102 | w, h = im.size 103 | k = w // s[0] - h // s[1] 104 | if k > 0: 105 | im = im.crop(((w - h) // 2, 0, (w + h) // 2, h)) 106 | elif k < 0: 107 | im = im.crop((0, (h - w) // 2, w, (h + w) // 2)) 108 | return im.resize(s, Image.ANTIALIAS) 109 | 110 | 111 | def crop_round_image(cutting_size, path_to_image, path_to_new_image): 112 | from PIL import Image 113 | 114 | im = Image.open(path_to_image) 115 | im = _crop_round_image(im, cutting_size) 116 | im.putalpha(prepare_mask(cutting_size, 4)) 117 | im.save(path_to_new_image) 118 | -------------------------------------------------------------------------------- /theming.py: -------------------------------------------------------------------------------- 1 | from kivy.properties import AliasProperty, ColorProperty 2 | 3 | class ThemeManager(): 4 | 5 | background_color =ColorProperty() 6 | 7 | primary_color = ColorProperty() 8 | 9 | secondary_color = ColorProperty() 10 | 11 | tertiary_color = ColorProperty() 12 | 13 | accent_color = ColorProperty() 14 | 15 | text_color = ColorProperty() 16 | 17 | secondary_text_color = ColorProperty() 18 | 19 | def __init__(self, **kwargs): 20 | super().__init__(**kwargs) 21 | self.background_color = [44/255,62/255,80/255, 1] 22 | self.primary_color = [50/255,49/255,61/255,1] 23 | self.secondary_color = [70/255,69/255,81/255,1] 24 | self.tertiary_color = [90/255,89/255,101/255,1] 25 | self.accent_color = [218/255,68/255,83/255, 1] 26 | self.text_color = [1,1,1,1] 27 | self.secondary_text_color = [1,1,1,.5] 28 | 29 | 30 | 31 | def set_theme(self, name): 32 | if name == 'Slate': 33 | self.background_color = [44/255,62/255,80/255, 1] 34 | self.primary_color = [50/255,49/255,61/255,1] 35 | self.secondary_color = [70/255,69/255,81/255,1] 36 | self.tertiary_color = [90/255,89/255,101/255,1] 37 | self.accent_color = [218/255,68/255,83/255, 1] 38 | self.text_color = [1,1,1,1] 39 | self.secondary_text_color = [0,0,0,.5] 40 | 41 | elif name == 'DeadWood': 42 | self.background_color = [34/255,40/255,49/255, 1] 43 | self.primary_color = [48/255,71/255,94/255,1] 44 | self.secondary_color = [68/255,91/255,114/255,1] 45 | self.tertiary_color = [88/255,121/255,134/255,1] 46 | self.accent_color = [242/255,163/255,101/255,1] 47 | self.text_color = [1,1,1,1] 48 | self.secondary_text_color = [1,1,1,.5] 49 | 50 | elif name == 'SnowWhite': 51 | self.background_color = [34/255,40/255,49/255, 1] 52 | self.primary_color = [0.9,0.9,0.9,1] 53 | self.secondary_color = [0.7,0.7,0.7,1] 54 | self.tertiary_color = [0.5,0.5,0.5,1] 55 | self.accent_color = [17/255,153/255,158/255,1] 56 | self.text_color = [0,0,0.1,1] 57 | self.secondary_text_color = [0,0,0.1,.5] 58 | 59 | elif name == 'Candy': 60 | self.background_color = [255/255,182/255,185/255,1] 61 | self.primary_color = [250/255,227/255,217/255,1] 62 | self.secondary_color = [230/255,207/255,197/255,1] 63 | self.tertiary_color = [210/255,197/255,187/255,1] 64 | self.accent_color = [97/255,192/255,191/255,1] 65 | self.text_color = [0,0,0.1,1] 66 | self.secondary_text_color = [0,0,0.1,.5] 67 | 68 | elif name == 'PureWhite': 69 | self.background_color = [0.9,0.9,0.9,1] 70 | self.primary_color = [0.9,0.9,0.9,1] 71 | self.secondary_color = [0.7,0.7,0.7,1] 72 | self.tertiary_color = [0.5,0.5,0.5,1] 73 | self.accent_color = [218/255,68/255,83/255, 1] 74 | self.text_color = [0,0,0.1,1] 75 | self.secondary_text_color = [0,0,0.1,.5] 76 | 77 | elif name == 'PureBlack': 78 | self.background_color = [0,0,0,1] 79 | self.primary_color = [0.1,0.1,0.1,1] 80 | self.secondary_color = [0.2,0.2,0.2,1] 81 | self.tertiary_color = [0.3,0.3,0.3,1] 82 | self.accent_color = [218/255,68/255,83/255, 1] 83 | self.text_color = [1,1,1,1] 84 | self.secondary_text_color = [1,1,1,.5] 85 | def rgb2hex(self,list): 86 | return '#%02x%02x%02x' % (int(list[0]*255),int(list[1]*255),int(list[2]*255)) 87 | -------------------------------------------------------------------------------- /kivymd/uix/dropdownitem.py: -------------------------------------------------------------------------------- 1 | """ 2 | Components/Dropdown Item 3 | ======================== 4 | 5 | .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/dropdown-item.png 6 | :align: center 7 | 8 | Usage 9 | ----- 10 | 11 | .. code-block:: python 12 | 13 | from kivy.lang import Builder 14 | 15 | from kivymd.app import MDApp 16 | 17 | KV = ''' 18 | Screen 19 | 20 | MDDropDownItem: 21 | id: drop_item 22 | pos_hint: {'center_x': .5, 'center_y': .5} 23 | text: 'Item' 24 | on_release: self.set_item("New Item") 25 | ''' 26 | 27 | 28 | class Test(MDApp): 29 | def __init__(self, **kwargs): 30 | super().__init__(**kwargs) 31 | self.screen = Builder.load_string(KV) 32 | 33 | def build(self): 34 | return self.screen 35 | 36 | 37 | Test().run() 38 | 39 | .. seealso:: 40 | 41 | `Work with the class MDDropdownMenu see here `_ 42 | """ 43 | 44 | __all__ = ("MDDropDownItem",) 45 | 46 | from kivy.lang import Builder 47 | from kivy.properties import NumericProperty, StringProperty 48 | from kivy.uix.behaviors import ButtonBehavior 49 | from kivy.uix.widget import Widget 50 | 51 | from kivymd.theming import ThemableBehavior 52 | from kivymd.uix.behaviors import FakeRectangularElevationBehavior 53 | from kivymd.uix.boxlayout import MDBoxLayout 54 | 55 | Builder.load_string( 56 | """ 57 | <_Triangle>: 58 | canvas: 59 | Color: 60 | rgba: root.theme_cls.text_color 61 | Triangle: 62 | points: 63 | [ \ 64 | self.right-dp(14), self.y+dp(7), \ 65 | self.right-dp(7), self.y+dp(7), \ 66 | self.right-dp(7), self.y+dp(14) \ 67 | ] 68 | 69 | 70 | 71 | orientation: "vertical" 72 | adaptive_size: True 73 | spacing: "5dp" 74 | padding: "5dp", "5dp", "5dp", 0 75 | 76 | MDBoxLayout: 77 | adaptive_size: True 78 | spacing: "10dp" 79 | 80 | Label: 81 | id: label_item 82 | size_hint: None, None 83 | size: self.texture_size 84 | color: root.theme_cls.text_color 85 | font_size: root.font_size 86 | 87 | 88 | _Triangle: 89 | size_hint: None, None 90 | size: "20dp", "20dp" 91 | 92 | MDSeparator: 93 | """ 94 | ) 95 | 96 | 97 | class _Triangle(ThemableBehavior, Widget): 98 | pass 99 | 100 | 101 | class MDDropDownItem( 102 | ThemableBehavior, 103 | FakeRectangularElevationBehavior, 104 | ButtonBehavior, 105 | MDBoxLayout, 106 | ): 107 | text = StringProperty() 108 | """ 109 | Text item. 110 | 111 | :attr:`text` is a :class:`~kivy.properties.StringProperty` 112 | and defaults to `''`. 113 | """ 114 | 115 | current_item = StringProperty() 116 | """ 117 | Current name item. 118 | 119 | :attr:`current_item` is a :class:`~kivy.properties.StringProperty` 120 | and defaults to `''`. 121 | """ 122 | 123 | font_size = NumericProperty("16sp") 124 | """ 125 | Item font size. 126 | 127 | :attr:`font_size` is a :class:`~kivy.properties.NumericProperty` 128 | and defaults to `'16sp'`. 129 | """ 130 | 131 | def on_text(self, instance, value): 132 | self.ids.label_item.text = value 133 | 134 | def set_item(self, name_item): 135 | """Sets new text for an item.""" 136 | 137 | self.ids.label_item.text = name_item 138 | self.current_item = name_item 139 | -------------------------------------------------------------------------------- /kivymd/uix/behaviors/focus_behavior.py: -------------------------------------------------------------------------------- 1 | """ 2 | Behaviors/Focus 3 | =============== 4 | 5 | .. rubric:: Changing the background color when the mouse is on the widget. 6 | 7 | To apply focus behavior, you must create a new class that is inherited from the 8 | widget to which you apply the behavior and from the :class:`FocusBehavior` class. 9 | 10 | Usage 11 | ----- 12 | 13 | .. code-block:: python 14 | 15 | from kivy.lang import Builder 16 | 17 | from kivymd.app import MDApp 18 | from kivymd.uix.behaviors import RectangularElevationBehavior, FocusBehavior 19 | from kivymd.uix.boxlayout import MDBoxLayout 20 | 21 | KV = ''' 22 | MDScreen: 23 | md_bg_color: 1, 1, 1, 1 24 | 25 | FocusWidget: 26 | size_hint: .5, .3 27 | pos_hint: {"center_x": .5, "center_y": .5} 28 | md_bg_color: app.theme_cls.bg_light 29 | 30 | MDLabel: 31 | text: "Label" 32 | theme_text_color: "Primary" 33 | pos_hint: {"center_y": .5} 34 | halign: "center" 35 | ''' 36 | 37 | 38 | class FocusWidget(MDBoxLayout, RectangularElevationBehavior, FocusBehavior): 39 | pass 40 | 41 | 42 | class Test(MDApp): 43 | def build(self): 44 | self.theme_cls.theme_style = "Dark" 45 | return Builder.load_string(KV) 46 | 47 | 48 | Test().run() 49 | 50 | .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/focus-widget.gif 51 | :align: center 52 | 53 | Color change at focus/defocus 54 | 55 | .. code-block:: kv 56 | 57 | FocusWidget: 58 | focus_color: 1, 0, 1, 1 59 | unfocus_color: 0, 0, 1, 1 60 | 61 | .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/focus-defocus-color.gif 62 | :align: center 63 | """ 64 | 65 | __all__ = ("FocusBehavior",) 66 | 67 | from kivy.app import App 68 | from kivy.properties import BooleanProperty, ColorProperty 69 | from kivy.uix.behaviors import ButtonBehavior 70 | 71 | from kivymd.uix.behaviors import HoverBehavior 72 | 73 | 74 | class FocusBehavior(HoverBehavior, ButtonBehavior): 75 | 76 | focus_behavior = BooleanProperty(True) 77 | """ 78 | Using focus when hovering over a widget. 79 | 80 | :attr:`focus_behavior` is a :class:`~kivy.properties.BooleanProperty` 81 | and defaults to `False`. 82 | """ 83 | 84 | focus_color = ColorProperty(None) 85 | """ 86 | The color of the widget when the mouse enters the bbox of the widget. 87 | 88 | :attr:`focus_color` is a :class:`~kivy.properties.ColorProperty` 89 | and defaults to `None`. 90 | """ 91 | 92 | unfocus_color = ColorProperty(None) 93 | """ 94 | The color of the widget when the mouse exits the bbox widget. 95 | 96 | :attr:`unfocus_color` is a :class:`~kivy.properties.ColorProperty` 97 | and defaults to `None`. 98 | """ 99 | 100 | def on_enter(self): 101 | """Called when mouse enter the bbox of the widget.""" 102 | 103 | if hasattr(self, "md_bg_color") and self.focus_behavior: 104 | if hasattr(self, "theme_cls") and not self.focus_color: 105 | self.md_bg_color = self.theme_cls.bg_normal 106 | else: 107 | if not self.focus_color: 108 | self.md_bg_color = App.get_running_app().theme_cls.bg_normal 109 | else: 110 | self.md_bg_color = self.focus_color 111 | 112 | def on_leave(self): 113 | """Called when the mouse exit the widget.""" 114 | 115 | if hasattr(self, "md_bg_color") and self.focus_behavior: 116 | if hasattr(self, "theme_cls") and not self.unfocus_color: 117 | self.md_bg_color = self.theme_cls.bg_light 118 | else: 119 | if not self.unfocus_color: 120 | self.md_bg_color = App.get_running_app().theme_cls.bg_light 121 | else: 122 | self.md_bg_color = self.unfocus_color 123 | -------------------------------------------------------------------------------- /kivymd/toast/kivytoast/kivytoast.py: -------------------------------------------------------------------------------- 1 | """ 2 | KivyToast 3 | ========= 4 | 5 | .. rubric:: Implementation of toasts for desktop. 6 | 7 | .. code-block:: python 8 | 9 | from kivy.lang import Builder 10 | 11 | from kivymd.app import MDApp 12 | from kivymd.toast import toast 13 | 14 | KV = ''' 15 | MDScreen: 16 | 17 | MDToolbar: 18 | title: 'Test Toast' 19 | pos_hint: {'top': 1} 20 | left_action_items: [['menu', lambda x: x]] 21 | 22 | MDRaisedButton: 23 | text: 'TEST KIVY TOAST' 24 | pos_hint: {'center_x': .5, 'center_y': .5} 25 | on_release: app.show_toast() 26 | ''' 27 | 28 | 29 | class Test(MDApp): 30 | def show_toast(self): 31 | '''Displays a toast on the screen.''' 32 | 33 | toast('Test Kivy Toast') 34 | 35 | def build(self): 36 | return Builder.load_string(KV) 37 | 38 | Test().run() 39 | """ 40 | 41 | from kivy.animation import Animation 42 | from kivy.clock import Clock 43 | from kivy.core.window import Window 44 | from kivy.lang import Builder 45 | from kivy.metrics import dp 46 | from kivy.properties import ListProperty, NumericProperty 47 | from kivy.uix.label import Label 48 | 49 | from kivymd.uix.dialog import BaseDialog 50 | 51 | Builder.load_string( 52 | """ 53 | : 54 | size_hint: (None, None) 55 | pos_hint: {"center_x": 0.5, "center_y": 0.1} 56 | opacity: 0 57 | auto_dismiss: True 58 | overlay_color: [0, 0, 0, 0] 59 | canvas: 60 | Color: 61 | rgba: root._md_bg_color 62 | RoundedRectangle: 63 | pos: self.pos 64 | size: self.size 65 | radius: root.radius 66 | """ 67 | ) 68 | 69 | 70 | class Toast(BaseDialog): 71 | duration = NumericProperty(2.5) 72 | """ 73 | The amount of time (in seconds) that the toast is visible on the screen. 74 | 75 | :attr:`duration` is an :class:`~kivy.properties.NumericProperty` 76 | and defaults to `2.5`. 77 | """ 78 | 79 | _md_bg_color = ListProperty() 80 | 81 | def __init__(self, **kwargs): 82 | super().__init__(**kwargs) 83 | self.label_toast = Label(size_hint=(None, None), opacity=0) 84 | self.label_toast.bind(texture_size=self.label_check_texture_size) 85 | self.add_widget(self.label_toast) 86 | 87 | def label_check_texture_size(self, instance, texture_size): 88 | texture_width, texture_height = texture_size 89 | if texture_width > Window.width: 90 | instance.text_size = (Window.width - dp(10), None) 91 | instance.texture_update() 92 | texture_width, texture_height = instance.texture_size 93 | self.size = (texture_width + 25, texture_height + 25) 94 | 95 | def toast(self, text_toast): 96 | self.label_toast.text = text_toast 97 | self.open() 98 | 99 | def on_open(self): 100 | self.fade_in() 101 | Clock.schedule_once(self.fade_out, self.duration) 102 | 103 | def fade_in(self): 104 | anim = Animation(opacity=1, duration=0.4) 105 | anim.start(self.label_toast) 106 | anim.start(self) 107 | 108 | def fade_out(self, *args): 109 | anim = Animation(opacity=0, duration=0.4) 110 | anim.bind(on_complete=lambda *x: self.dismiss()) 111 | anim.start(self.label_toast) 112 | anim.start(self) 113 | 114 | def on_touch_down(self, touch): 115 | if not self.collide_point(*touch.pos): 116 | if self.auto_dismiss: 117 | self.fade_out() 118 | return False 119 | super().on_touch_down(touch) 120 | return True 121 | 122 | 123 | def toast(text="", background=[0.2, 0.2, 0.2, 1], duration=2.5): 124 | """Displays a toast. 125 | 126 | :attr duration: the amount of time (in seconds) that the toast is visible on the screen 127 | :type duration: float 128 | 129 | :attr background: color ``rgba`` in Kivy format 130 | :type background: list 131 | """ 132 | 133 | Toast(duration=duration, _md_bg_color=background).toast(text) 134 | -------------------------------------------------------------------------------- /kivymd/factory_registers.py: -------------------------------------------------------------------------------- 1 | """ 2 | Register KivyMD widgets to use without import 3 | """ 4 | 5 | from kivy.factory import Factory 6 | 7 | r = Factory.register 8 | r("MDNavigationRail", module="kivymd.uix.navigationrail") 9 | r("MDSwiper", module="kivymd.uix.swiper") 10 | r("MDCarousel", module="kivymd.uix.carousel") 11 | r("MDFloatLayout", module="kivymd.uix.floatlayout") 12 | r("MDScreen", module="kivymd.uix.screen") 13 | r("MDBoxLayout", module="kivymd.uix.boxlayout") 14 | r("MDRelativeLayout", module="kivymd.uix.relativelayout") 15 | r("MDGridLayout", module="kivymd.uix.gridlayout") 16 | r("MDStackLayout", module="kivymd.uix.stacklayout") 17 | r("MDExpansionPanel", module="kivymd.uix.expansionpanel") 18 | r("MDExpansionPanelOneLine", module="kivymd.uix.expansionpanel") 19 | r("MDExpansionPanelTwoLine", module="kivymd.uix.expansionpanel") 20 | r("MDExpansionPanelThreeLine", module="kivymd.uix.expansionpanel") 21 | r("FitImage", module="kivymd.utils.fitimage") 22 | r("MDBackdrop", module="kivymd.uix.backdrop") 23 | r("MDBanner", module="kivymd.uix.banner") 24 | r("MDTooltip", module="kivymd.uix.tooltip") 25 | r("MDBottomNavigation", module="kivymd.uix.bottomnavigation") 26 | r("MDBottomNavigationItem", module="kivymd.uix.bottomnavigation") 27 | r("MDToggleButton", module="kivymd.uix.behaviors.toggle_behavior") 28 | r("MDFloatingActionButtonSpeedDial", module="kivymd.uix.button") 29 | r("MDIconButton", module="kivymd.uix.button") 30 | r("MDRoundImageButton", module="kivymd.uix.button") 31 | r("MDFlatButton", module="kivymd.uix.button") 32 | r("MDRaisedButton", module="kivymd.uix.button") 33 | r("MDFloatingActionButton", module="kivymd.uix.button") 34 | r("MDRectangleFlatButton", module="kivymd.uix.button") 35 | r("MDTextButton", module="kivymd.uix.button") 36 | r("MDCustomRoundIconButton", module="kivymd.uix.button") 37 | r("MDRoundFlatButton", module="kivymd.uix.button") 38 | r("MDFillRoundFlatButton", module="kivymd.uix.button") 39 | r("MDRectangleFlatIconButton", module="kivymd.uix.button") 40 | r("MDRoundFlatIconButton", module="kivymd.uix.button") 41 | r("MDFillRoundFlatIconButton", module="kivymd.uix.button") 42 | r("MDCard", module="kivymd.uix.card") 43 | r("MDSeparator", module="kivymd.uix.card") 44 | r("MDSelectionList", module="kivymd.uix.selection") 45 | r("MDChip", module="kivymd.uix.chip") 46 | r("MDChipContainer", module="kivymd.uix.chip") 47 | r("SmartTile", module="kivymd.uix.imagelist") 48 | r("SmartTileWithLabel", module="kivymd.uix.imagelist") 49 | r("SmartTileWithStar", module="kivymd.uix.imagelist") 50 | r("MDLabel", module="kivymd.uix.label") 51 | r("MDIcon", module="kivymd.uix.label") 52 | r("MDList", module="kivymd.uix.list") 53 | r("ILeftBody", module="kivymd.uix.list") 54 | r("ILeftBodyTouch", module="kivymd.uix.list") 55 | r("IRightBody", module="kivymd.uix.list") 56 | r("IRightBodyTouch", module="kivymd.uix.list") 57 | r("ContainerSupport", module="kivymd.uix.list") 58 | r("OneLineListItem", module="kivymd.uix.list") 59 | r("TwoLineListItem", module="kivymd.uix.list") 60 | r("ThreeLineListItem", module="kivymd.uix.list") 61 | r("OneLineAvatarListItem", module="kivymd.uix.list") 62 | r("TwoLineAvatarListItem", module="kivymd.uix.list") 63 | r("ThreeLineAvatarListItem", module="kivymd.uix.list") 64 | r("OneLineIconListItem", module="kivymd.uix.list") 65 | r("TwoLineIconListItem", module="kivymd.uix.list") 66 | r("ThreeLineIconListItem", module="kivymd.uix.list") 67 | r("OneLineRightIconListItem", module="kivymd.uix.list") 68 | r("TwoLineRightIconListItem", module="kivymd.uix.list") 69 | r("ThreeLineRightIconListItem", module="kivymd.uix.list") 70 | r("OneLineAvatarIconListItem", module="kivymd.uix.list") 71 | r("TwoLineAvatarIconListItem", module="kivymd.uix.list") 72 | r("ThreeLineAvatarIconListItem", module="kivymd.uix.list") 73 | r("HoverBehavior", module="kivymd.uix.behaviors.hover_behavior") 74 | r("FocusBehavior", module="kivymd.uix.behaviors.focus_behavior") 75 | r("MagicBehavior", module="kivymd.uix.behaviors.magic_behavior") 76 | r("MDNavigationDrawer", module="kivymd.uix.navigationdrawer") 77 | r("MDNavigationLayout", module="kivymd.uix.navigationdrawer") 78 | r("MDProgressBar", module="kivymd.uix.progressbar") 79 | r("MDScrollViewRefreshLayout", module="kivymd.uix.refreshlayout") 80 | r("MDCheckbox", module="kivymd.uix.selectioncontrol") 81 | r("MDSwitch", module="kivymd.uix.selectioncontrol") 82 | r("MDSlider", module="kivymd.uix.slider") 83 | r("MDSpinner", module="kivymd.uix.spinner") 84 | r("MDTabs", module="kivymd.uix.tab") 85 | r("MDTextField", module="kivymd.uix.textfield") 86 | r("MDTextFieldRound", module="kivymd.uix.textfield") 87 | r("MDTextFieldRect", module="kivymd.uix.textfield") 88 | r("MDToolbar", module="kivymd.uix.toolbar") 89 | r("MDBottomAppBar", module="kivymd.uix.toolbar") 90 | r("MDDropDownItem", module="kivymd.uix.dropdownitem") 91 | r("MDCircularLayout", module="kivymd.uix.circularlayout") 92 | -------------------------------------------------------------------------------- /kivymd/utils/fitimage.py: -------------------------------------------------------------------------------- 1 | """ 2 | Fit Image 3 | ========= 4 | 5 | Feature to automatically crop a `Kivy` image to fit your layout 6 | Write by Benedikt Zwölfer 7 | 8 | Referene - https://gist.github.com/benni12er/95a45eb168fc33a4fcd2d545af692dad 9 | 10 | 11 | Example: 12 | ======== 13 | 14 | .. code-block:: kv 15 | 16 | BoxLayout: 17 | size_hint_y: None 18 | height: "200dp" 19 | orientation: 'vertical' 20 | 21 | FitImage: 22 | size_hint_y: 3 23 | source: 'images/img1.jpg' 24 | 25 | FitImage: 26 | size_hint_y: 1 27 | source: 'images/img2.jpg' 28 | 29 | Example with round corners: 30 | =========================== 31 | 32 | .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/fitimage-round-corners.png 33 | :align: center 34 | 35 | .. code-block:: python 36 | 37 | from kivy.uix.modalview import ModalView 38 | from kivy.lang import Builder 39 | 40 | from kivymd import images_path 41 | from kivymd.app import MDApp 42 | from kivymd.uix.card import MDCard 43 | 44 | Builder.load_string( 45 | ''' 46 | : 47 | elevation: 10 48 | radius: [36, ] 49 | 50 | FitImage: 51 | id: bg_image 52 | source: "images/bg.png" 53 | size_hint_y: .35 54 | pos_hint: {"top": 1} 55 | radius: [36, 36, 0, 0, ] 56 | ''') 57 | 58 | 59 | class Card(MDCard): 60 | pass 61 | 62 | 63 | class Example(MDApp): 64 | def build(self): 65 | modal = ModalView( 66 | size_hint=(0.4, 0.8), 67 | background=f"{images_path}/transparent.png", 68 | overlay_color=(0, 0, 0, 0), 69 | ) 70 | modal.add_widget(Card()) 71 | modal.open() 72 | 73 | 74 | Example().run() 75 | """ 76 | 77 | __all__ = ("FitImage",) 78 | 79 | from kivy.clock import Clock 80 | from kivy.graphics.context_instructions import Color 81 | from kivy.graphics.vertex_instructions import Rectangle 82 | from kivy.lang import Builder 83 | from kivy.properties import BooleanProperty, ListProperty, ObjectProperty 84 | from kivy.uix.boxlayout import BoxLayout 85 | from kivy.uix.image import AsyncImage 86 | from kivy.uix.widget import Widget 87 | 88 | Builder.load_string( 89 | """ 90 | 91 | canvas.before: 92 | StencilPush 93 | RoundedRectangle: 94 | size: self.size 95 | pos: self.pos 96 | radius: root.radius 97 | StencilUse 98 | 99 | canvas.after: 100 | StencilUnUse 101 | RoundedRectangle: 102 | size: self.size 103 | pos: self.pos 104 | radius: root.radius 105 | StencilPop 106 | """ 107 | ) 108 | 109 | 110 | class FitImage(BoxLayout): 111 | source = ObjectProperty() 112 | container = ObjectProperty() 113 | radius = ListProperty([0, 0, 0, 0]) 114 | mipmap = BooleanProperty(False) 115 | 116 | def __init__(self, **kwargs): 117 | super().__init__(**kwargs) 118 | Clock.schedule_once(self._late_init) 119 | 120 | def _late_init(self, *args): 121 | self.container = Container(self.source, self.mipmap) 122 | self.bind(source=self.container.setter("source")) 123 | self.add_widget(self.container) 124 | 125 | def reload(self): 126 | self.container.image.reload() 127 | 128 | 129 | class Container(Widget): 130 | source = ObjectProperty() 131 | image = ObjectProperty() 132 | 133 | def __init__(self, source, mipmap, **kwargs): 134 | super().__init__(**kwargs) 135 | self.image = AsyncImage(mipmap=mipmap) 136 | self.image.bind(on_load=self.adjust_size) 137 | self.source = source 138 | self.bind(size=self.adjust_size, pos=self.adjust_size) 139 | 140 | def on_source(self, instance, value): 141 | if isinstance(value, str): 142 | self.image.source = value 143 | else: 144 | self.image.texture = value 145 | self.adjust_size() 146 | 147 | def adjust_size(self, *args): 148 | if not self.parent or not self.image.texture: 149 | return 150 | 151 | (par_x, par_y) = self.parent.size 152 | 153 | if par_x == 0 or par_y == 0: 154 | with self.canvas: 155 | self.canvas.clear() 156 | return 157 | 158 | par_scale = par_x / par_y 159 | (img_x, img_y) = self.image.texture.size 160 | img_scale = img_x / img_y 161 | 162 | if par_scale > img_scale: 163 | (img_x_new, img_y_new) = (img_x, img_x / par_scale) 164 | else: 165 | (img_x_new, img_y_new) = (img_y * par_scale, img_y) 166 | 167 | crop_pos_x = (img_x - img_x_new) / 2 168 | crop_pos_y = (img_y - img_y_new) / 2 169 | 170 | subtexture = self.image.texture.get_region( 171 | crop_pos_x, crop_pos_y, img_x_new, img_y_new 172 | ) 173 | 174 | with self.canvas: 175 | self.canvas.clear() 176 | Color(1, 1, 1) 177 | Rectangle(texture=subtexture, pos=self.pos, size=(par_x, par_y)) 178 | -------------------------------------------------------------------------------- /reminderscheduler.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | from datetime import datetime 4 | from string import Template 5 | try: 6 | from jnius import cast, autoclass 7 | 8 | except KeyError: 9 | os.environ['JDK_HOME'] = "/usr/lib/jvm/java-1.8.0-openjdk-amd64" 10 | os.environ['JAVA_HOME'] = "/usr/lib/jvm/java-1.8.0-openjdk-amd64" 11 | from jnius import autoclass 12 | 13 | #Import necessary Java classes 14 | 15 | mActivity = autoclass('org.kivy.android.PythonActivity').mActivity 16 | Intent = autoclass('android.content.Intent') 17 | AlarmManager = autoclass('android.app.AlarmManager') 18 | PendingIntent = autoclass('android.app.PendingIntent') 19 | Context = autoclass('android.content.Context') 20 | ReminderAlarmReceiver = autoclass('org.org.remindy.ReminderAlarmReceiver') 21 | ReminderRepeatingAlarmReceiver = autoclass('org.org.remindy.ReminderRepeatingAlarmReceiver') 22 | context = mActivity.getApplicationContext() 23 | String = autoclass('java.lang.String') 24 | mapping = {'Y': 'yyyy', 'm': 'MM', 'd': 'dd', 'H': 'HH', 'M': 'mm'} 25 | Calendar = autoclass('java.util.Calendar') 26 | TimeZone = autoclass('java.util.TimeZone') 27 | SimpleDateFormat = autoclass('java.text.SimpleDateFormat') 28 | ParsePosition = autoclass('java.text.ParsePosition') 29 | Date = autoclass('java.util.Date') 30 | 31 | #Create alarm manager object 32 | 33 | 34 | class ReminderScheduler(): 35 | #To update a reminder just overwrite existing reminder 36 | 37 | def schedule(reminder_id,title,description,date_to_ring,time_to_ring,current_list,intent_id): 38 | #Create Intent and add required properties to it 39 | newdate = Intent() 40 | newdate.setClass(context, ReminderAlarmReceiver) 41 | newdate.setAction('org.org.remindy.ACTION_START_REMINDER') 42 | newdate.putExtra("TITLE", String(title)) 43 | newdate.putExtra("DESCRIPTION", String(description)) 44 | newdate.putExtra("IDENTIFICATION", reminder_id) 45 | newdate.putExtra("INTENT_ID", intent_id) 46 | newdate.putExtra("CURRENT_LIST", String(current_list)) 47 | newdatepending = PendingIntent.getBroadcast(context,intent_id,newdate,PendingIntent.FLAG_CANCEL_CURRENT) 48 | 49 | #Create datetime string in python in the format for date object of java 50 | datetime_string = datetime.strptime(date_to_ring+ ' '+time_to_ring, "%x %I:%M %p").strftime("%Y-%m-%d %H:%M") 51 | 52 | #Calculate time for reminder to ring 53 | formatted_string = Template(datetime_string.replace('%', '$')).substitute(**mapping) 54 | formatted_string +=":00" 55 | convertor = SimpleDateFormat("yyyy-MM-dd HH:mm:ss") #Convert to java data type 56 | parsed_object = convertor.parse(formatted_string, ParsePosition(0)) 57 | 58 | #Create alarm manager 59 | cast(AlarmManager, context.getSystemService(Context.ALARM_SERVICE)).setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,parsed_object.getTime(), newdatepending) 60 | 61 | 62 | def deschedule(id): 63 | deletedate = Intent() 64 | deletedate.setClass(context, ReminderAlarmReceiver) 65 | deletedate.setAction('org.org.remindy.ACTION_START_REMINDER') 66 | newdatepending = PendingIntent.getBroadcast(context,id,deletedate, PendingIntent.FLAG_CANCEL_CURRENT) 67 | cast(AlarmManager, context.getSystemService(Context.ALARM_SERVICE)).cancel(newdatepending) 68 | 69 | def schedule_repeating(reminder_id,title,description,day_to_ring, time_to_ring, current_list, intent_id): 70 | 71 | #Create Intent and add required properties to it 72 | newday = Intent() 73 | newday.setClass(context, ReminderRepeatingAlarmReceiver) 74 | newday.setAction('org.org.remindy.ACTION_START_REMINDER_REPEATING') 75 | newday.putExtra("TITLE", String(title)) 76 | newday.putExtra("DESCRIPTION", String(description)) 77 | newday.putExtra("IDENTIFICATION", reminder_id) 78 | newday.putExtra("INTENT_ID", intent_id) 79 | newday.putExtra("CURRENT_LIST", String(current_list)) 80 | newdaypending = PendingIntent.getBroadcast(context,reminder_id,newday, PendingIntent.FLAG_CANCEL_CURRENT) 81 | 82 | time = datetime.strptime(time_to_ring,"%I:%M %p").strftime("%H:%M") 83 | 84 | calender= Calendar.getInstance() 85 | calender.set(Calendar.DAY_OF_WEEK, day_to_ring) 86 | calender.set(Calendar.HOUR_OF_DAY, int(time[0:2])) 87 | calender.set(Calendar.MINUTE, int(time[3:])) 88 | calender.set(Calendar.SECOND, 0) 89 | calender.set(Calendar.MILLISECOND, 0) 90 | if Calendar.getInstance().getTimeInMillis() > calender.getTimeInMillis(): 91 | calender.add(Calendar.DATE, 7) 92 | #We have to reset the alarm every time it rings as there is no other way to set an exact repeating alarm 93 | cast(AlarmManager, context.getSystemService(Context.ALARM_SERVICE)).setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,calender.getTimeInMillis(), newdaypending) 94 | 95 | def deschedule_repeating(id): 96 | deleteday = Intent() 97 | deleteday.setClass(context, ReminderRepeatingAlarmReceiver) 98 | deleteday.setAction('org.org.remindy.ACTION_START_REMINDER_REPEATING') 99 | newdaypending = PendingIntent.getBroadcast(context,id,deleteday, PendingIntent.FLAG_CANCEL_CURRENT) 100 | cast(AlarmManager, context.getSystemService(Context.ALARM_SERVICE)).cancel(newdaypending) 101 | -------------------------------------------------------------------------------- /kivymd/uix/behaviors/magic_behavior.py: -------------------------------------------------------------------------------- 1 | """ 2 | Behaviors/Magic 3 | =============== 4 | 5 | .. rubric:: Magical effects for buttons. 6 | 7 | .. warning:: Magic effects do not work correctly with `KivyMD` buttons! 8 | 9 | To apply magic effects, you must create a new class that is inherited from the 10 | widget to which you apply the effect and from the :attr:`MagicBehavior` class. 11 | 12 | In `KV file`: 13 | 14 | .. code-block:: kv 15 | 16 | 17 | 18 | In `python file`: 19 | 20 | .. code-block:: python 21 | 22 | class MagicButton(MagicBehavior, MDRectangleFlatButton): 23 | pass 24 | 25 | .. rubric:: The :attr:`MagicBehavior` class provides five effects: 26 | 27 | - :attr:`MagicBehavior.wobble` 28 | - :attr:`MagicBehavior.grow` 29 | - :attr:`MagicBehavior.shake` 30 | - :attr:`MagicBehavior.twist` 31 | - :attr:`MagicBehavior.shrink` 32 | 33 | Example: 34 | 35 | .. code-block:: python 36 | 37 | from kivymd.app import MDApp 38 | from kivy.lang import Builder 39 | 40 | KV = ''' 41 | #:import MagicBehavior kivymd.uix.behaviors.MagicBehavior 42 | 43 | 44 | 45 | 46 | 47 | FloatLayout: 48 | 49 | MagicButton: 50 | text: "WOBBLE EFFECT" 51 | on_release: self.wobble() 52 | pos_hint: {"center_x": .5, "center_y": .3} 53 | 54 | MagicButton: 55 | text: "GROW EFFECT" 56 | on_release: self.grow() 57 | pos_hint: {"center_x": .5, "center_y": .4} 58 | 59 | MagicButton: 60 | text: "SHAKE EFFECT" 61 | on_release: self.shake() 62 | pos_hint: {"center_x": .5, "center_y": .5} 63 | 64 | MagicButton: 65 | text: "TWIST EFFECT" 66 | on_release: self.twist() 67 | pos_hint: {"center_x": .5, "center_y": .6} 68 | 69 | MagicButton: 70 | text: "SHRINK EFFECT" 71 | on_release: self.shrink() 72 | pos_hint: {"center_x": .5, "center_y": .7} 73 | ''' 74 | 75 | 76 | class Example(MDApp): 77 | def build(self): 78 | return Builder.load_string(KV) 79 | 80 | 81 | Example().run() 82 | 83 | 84 | .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/magic-button.gif 85 | :width: 250 px 86 | :align: center 87 | """ 88 | 89 | __all__ = ("MagicBehavior",) 90 | 91 | from kivy.animation import Animation 92 | from kivy.lang import Builder 93 | from kivy.properties import NumericProperty 94 | 95 | Builder.load_string( 96 | """ 97 | 98 | translate_x: 0 99 | translate_y: 0 100 | scale_x: 1 101 | scale_y: 1 102 | rotate: 0 103 | 104 | canvas.before: 105 | PushMatrix 106 | Translate: 107 | x: self.translate_x or 0 108 | y: self.translate_y or 0 109 | Rotate: 110 | origin: self.center 111 | angle: self.rotate or 0 112 | Scale: 113 | origin: self.center 114 | x: self.scale_x or 1 115 | y: self.scale_y or 1 116 | canvas.after: 117 | PopMatrix 118 | """ 119 | ) 120 | 121 | 122 | class MagicBehavior: 123 | 124 | magic_speed = NumericProperty(1) 125 | """ 126 | Animation playback speed. 127 | 128 | :attr:`magic_speed` is a :class:`~kivy.properties.NumericProperty` 129 | and defaults to `1`. 130 | """ 131 | 132 | def grow(self): 133 | """Grow effect animation.""" 134 | 135 | ( 136 | Animation( 137 | scale_x=1.2, 138 | scale_y=1.2, 139 | t="out_quad", 140 | d=0.03 / self.magic_speed, 141 | ) 142 | + Animation( 143 | scale_x=1, scale_y=1, t="out_elastic", d=0.4 / self.magic_speed 144 | ) 145 | ).start(self) 146 | 147 | def shake(self): 148 | """Shake effect animation.""" 149 | 150 | ( 151 | Animation(translate_x=50, t="out_quad", d=0.02 / self.magic_speed) 152 | + Animation( 153 | translate_x=0, t="out_elastic", d=0.5 / self.magic_speed 154 | ) 155 | ).start(self) 156 | 157 | def wobble(self): 158 | """Wobble effect animation.""" 159 | 160 | ( 161 | ( 162 | Animation(scale_y=0.7, t="out_quad", d=0.03 / self.magic_speed) 163 | & Animation( 164 | scale_x=1.4, t="out_quad", d=0.03 / self.magic_speed 165 | ) 166 | ) 167 | + ( 168 | Animation(scale_y=1, t="out_elastic", d=0.5 / self.magic_speed) 169 | & Animation( 170 | scale_x=1, t="out_elastic", d=0.4 / self.magic_speed 171 | ) 172 | ) 173 | ).start(self) 174 | 175 | def twist(self): 176 | """Twist effect animation.""" 177 | 178 | ( 179 | Animation(rotate=25, t="out_quad", d=0.05 / self.magic_speed) 180 | + Animation(rotate=0, t="out_elastic", d=0.5 / self.magic_speed) 181 | ).start(self) 182 | 183 | def shrink(self): 184 | """Shrink effect animation.""" 185 | 186 | Animation( 187 | scale_x=0.95, scale_y=0.95, t="out_quad", d=0.1 / self.magic_speed 188 | ).start(self) 189 | 190 | def on_touch_up(self, *args): 191 | Animation.stop_all(self) 192 | return super().on_touch_up(*args) 193 | -------------------------------------------------------------------------------- /scr/ReminderAlarmReceiver.java: -------------------------------------------------------------------------------- 1 | package org.org.remindy; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Intent; 5 | import android.content.Context; 6 | import android.app.NotificationChannel; 7 | import android.app.NotificationManager; 8 | import androidx.core.app.NotificationCompat; 9 | import androidx.core.app.NotificationManagerCompat; 10 | import android.app.Notification; 11 | import android.app.PendingIntent; 12 | import android.os.Build; 13 | import android.os.Bundle; 14 | import org.kivy.android.PythonActivity; 15 | import android.media.RingtoneManager; 16 | import android.net.Uri; 17 | import android.media.AudioAttributes; 18 | import org.remindy.remindy.R; 19 | import org.org.remindy.FullScreenNotify; 20 | import java.lang.Math; 21 | 22 | public class ReminderAlarmReceiver extends BroadcastReceiver{ 23 | 24 | private void createNotificationChannel(Context context) { 25 | 26 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 27 | Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); 28 | 29 | AudioAttributes att = new AudioAttributes.Builder() 30 | .setUsage(AudioAttributes.USAGE_NOTIFICATION) 31 | .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 32 | .build(); 33 | 34 | CharSequence name = "New Reminder"; 35 | String description = "New Reminder"; 36 | int importance = NotificationManager.IMPORTANCE_HIGH; 37 | NotificationChannel channel = new NotificationChannel("REMINDY", name, importance); 38 | channel.setDescription(description); 39 | channel.setSound(sound, att); 40 | channel.enableLights(true); 41 | channel.enableVibration(true); 42 | NotificationManager notificationManager = context.getSystemService(NotificationManager.class); 43 | notificationManager.createNotificationChannel(channel); 44 | } 45 | } 46 | 47 | private void sendNotification(Context context, Intent intent) { 48 | Uri uri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); 49 | int notification_id = (int)(Math.random()*(8000-1+1)+1); 50 | Intent newintent = new Intent(context, PythonActivity.class); 51 | Short id = intent.getShortExtra("IDENTIFICATION", (short) 0); 52 | String current_list = intent.getStringExtra("CURRENT_LIST"); 53 | newintent.putExtra("LAUNCH_APP_WITH_REMINDER", id); 54 | newintent.putExtra("CURRENT_LIST", current_list); 55 | PendingIntent pendingintent = PendingIntent.getActivity(context,notification_id, newintent, PendingIntent.FLAG_ONE_SHOT); 56 | 57 | Intent mrkcomp = new Intent(context, ReminderMarkComp.class); 58 | mrkcomp.putExtra("CURRENT_LIST", current_list); 59 | mrkcomp.putExtra("IDENTIFICATION", intent.getExtras().getShort("IDENTIFICATION")); 60 | mrkcomp.putExtra("NOTIFICATION_ID", notification_id); 61 | mrkcomp.putExtra("INTENT_ID", intent.getExtras().getShort("INTENT_ID")); 62 | mrkcomp.setAction("org.org.remindy.MRKCOMP"); 63 | PendingIntent pendingmrkcomp = PendingIntent.getBroadcast(context,notification_id,mrkcomp, PendingIntent.FLAG_ONE_SHOT); 64 | String title = "Mark As Complete"; 65 | NotificationCompat.Action mrkcompaction = new NotificationCompat.Action.Builder( 0, title, pendingmrkcomp).build(); 66 | 67 | Intent snooze = new Intent(context, ReminderSnooze.class); 68 | snooze.putExtra("TITLE", intent.getExtras().getString("TITLE")); 69 | snooze.putExtra("DESCRIPTION", intent.getExtras().getString("DESCRIPTION")); 70 | snooze.putExtra("IDENTIFICATION", intent.getExtras().getShort("IDENTIFICATION")); 71 | snooze.putExtra("NOTIFICATION_ID", notification_id); 72 | snooze.putExtra("INTENT_ID", intent.getExtras().getShort("INTENT_ID")); 73 | snooze.putExtra("CURRENT_LIST", current_list); 74 | PendingIntent pendingsnooze = PendingIntent.getBroadcast(context, notification_id, snooze, PendingIntent.FLAG_CANCEL_CURRENT); 75 | NotificationCompat.Action snoozeaction = new NotificationCompat.Action.Builder( 0, "Snooze for 10 mins", pendingsnooze).build(); 76 | 77 | // Intent fsintent = new Intent(context,FullScreenNotify.class); 78 | // PendingIntent fspending = PendingIntent.getActivity(context,notification_id,fsintent, PendingIntent.FLAG_ONE_SHOT); 79 | 80 | NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "REMINDY") 81 | .setSmallIcon(R.drawable.ic_launcher) 82 | .setContentTitle(intent.getExtras().getString("TITLE")) 83 | .setContentText(intent.getExtras().getString("DESCRIPTION")) 84 | .setTicker("New Reminder") 85 | .setVibrate(new long[]{0, 300, 0, 400, 0, 500}) 86 | .setSound(uri) 87 | .setAutoCancel(true) 88 | .setOnlyAlertOnce(false) 89 | .setPriority(NotificationCompat.PRIORITY_HIGH) 90 | .setContentIntent(pendingintent) 91 | .addAction(mrkcompaction) 92 | .addAction(snoozeaction); 93 | // .setFullScreenIntent(fspending,true); 94 | 95 | NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); 96 | notificationManager.notify(notification_id,builder.build()); 97 | } 98 | 99 | 100 | 101 | @Override 102 | public void onReceive(Context context, Intent intent) { 103 | this.createNotificationChannel(context); 104 | this.sendNotification(context, intent); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /kivymd/uix/circularlayout.py: -------------------------------------------------------------------------------- 1 | """ 2 | Components/CircularLayout 3 | ========================= 4 | 5 | CircularLayout is a special layout that places widgets around a circle. 6 | 7 | MDCircularLayout 8 | ---------------- 9 | 10 | .. rubric:: Usage 11 | 12 | .. code-block:: 13 | 14 | from kivy.lang.builder import Builder 15 | from kivy.uix.label import Label 16 | 17 | from kivymd.app import MDApp 18 | 19 | kv = ''' 20 | Screen: 21 | MDCircularLayout: 22 | id: container 23 | pos_hint: {"center_x": .5, "center_y": .5} 24 | row_spacing: min(self.size)*0.1 25 | ''' 26 | 27 | 28 | class Main(MDApp): 29 | def build(self): 30 | return Builder.load_string(kv) 31 | 32 | def on_start(self): 33 | for x in range(1, 49): 34 | self.root.ids.container.add_widget( 35 | Label(text=f"{x}", color=[0, 0, 0, 1]) 36 | ) 37 | 38 | 39 | Main().run() 40 | 41 | """ 42 | 43 | __all__ = ("MDCircularLayout",) 44 | 45 | from math import atan2, cos, degrees, radians, sin 46 | 47 | from kivy.properties import BooleanProperty, NumericProperty 48 | 49 | from kivymd.uix.floatlayout import MDFloatLayout 50 | 51 | 52 | class MDCircularLayout(MDFloatLayout): 53 | 54 | degree_spacing = NumericProperty(30) 55 | """ 56 | The space between children in degree. 57 | 58 | :attr:`degree_spacing` is an :class:`~kivy.properties.NumericProperty` 59 | and defaults to `30`. 60 | """ 61 | 62 | circular_radius = NumericProperty(None, allownone=True) 63 | """ 64 | Radius of circle. Radius will be the greatest value in the layout if `circular_radius` if not specified. 65 | 66 | :attr:`circular_radius` is an :class:`~kivy.properties.NumericProperty` 67 | and defaults to `None`. 68 | """ 69 | 70 | start_from = NumericProperty(60) 71 | """ 72 | The positon of first child in degree. 73 | 74 | :attr:`start_from` is an :class:`~kivy.properties.NumericProperty` 75 | and defaults to `60`. 76 | """ 77 | 78 | max_degree = NumericProperty(360) 79 | """ 80 | Maximum range in degree allowed for each row of widgets before jumping to the next row. 81 | 82 | :attr:`max_degree` is an :class:`~kivy.properties.NumericProperty` 83 | and defaults to `360`. 84 | """ 85 | 86 | circular_padding = NumericProperty("25dp") 87 | """ 88 | Padding between outer widgets and the edge of the biggest circle. 89 | 90 | :attr:`circular_padding` is an :class:`~kivy.properties.NumericProperty` 91 | and defaults to `25dp`. 92 | """ 93 | 94 | row_spacing = NumericProperty("50dp") 95 | """ 96 | Space between each row of widget. 97 | 98 | :attr:`row_spacing` is an :class:`~kivy.properties.NumericProperty` 99 | and defaults to `50dp`. 100 | """ 101 | 102 | clockwise = BooleanProperty(True) 103 | """ 104 | Direction of widgets in circular direction. 105 | 106 | :attr:`clockwise` is an :class:`~kivy.properties.BooleanProperty` 107 | and defaults to `True`. 108 | """ 109 | 110 | def __init__(self, **kwargs): 111 | super().__init__(**kwargs) 112 | self.bind( 113 | row_spacing=self._update_layout, 114 | ) 115 | 116 | def _update_layout(self, *args): 117 | for index, child in enumerate(reversed(self.children)): 118 | pos = self._point_on_circle( 119 | self._calculate_radius(index), 120 | self._calculate_degree(index), 121 | ) 122 | child.center = pos 123 | 124 | def do_layout(self, *largs, **kwargs): 125 | self._update_layout() 126 | return super().do_layout(*largs, **kwargs) 127 | 128 | def _max_per_row(self): 129 | return int(self.max_degree / self.degree_spacing) 130 | 131 | def _calculate_radius(self, index): 132 | """ 133 | calculates the radius for given index 134 | 135 | """ 136 | 137 | idx = int(index / self._max_per_row()) 138 | 139 | if not self.circular_radius: 140 | init_radius = ( 141 | min([self.width / 2, self.height / 2]) - self.circular_padding 142 | ) 143 | else: 144 | init_radius = self.circular_radius 145 | 146 | if idx != 0: 147 | space = self.row_spacing * idx 148 | init_radius -= space 149 | 150 | return init_radius 151 | 152 | def _calculate_degree(self, index): 153 | """ calculates the angle for given index""" 154 | if self.clockwise: 155 | degree = self.start_from - index * self.degree_spacing 156 | else: 157 | degree = self.start_from + index * self.degree_spacing 158 | 159 | return degree 160 | 161 | def remove_widget(self, widget, **kwargs): 162 | super().remove_widget(widget, **kwargs) 163 | self._update_layout() 164 | 165 | def _point_on_circle(self, radius, degree): 166 | angle = radians(degree) 167 | center = [self.pos[0] + self.width / 2, self.pos[1] + self.height / 2] 168 | x = center[0] + (radius * cos(angle)) 169 | y = center[1] + (radius * sin(angle)) 170 | return [x, y] 171 | 172 | def get_angle(self, pos): 173 | """ 174 | Returns the angle of given pos 175 | """ 176 | 177 | center = [self.pos[0] + self.width / 2, self.pos[1] + self.height / 2] 178 | (dx, dy) = (center[0] - pos[0], center[1] - pos[1]) 179 | angle = degrees(atan2(float(dy), float(dx))) 180 | angle += 180 181 | return angle 182 | 183 | 184 | if __name__ == "__main__": 185 | from kivy.lang.builder import Builder 186 | from kivy.uix.label import Label 187 | 188 | from kivymd.app import MDApp 189 | 190 | kv = """ 191 | Screen: 192 | MDCircularLayout: 193 | id: container 194 | pos_hint: {"center_x": .5, "center_y": .5} 195 | row_spacing: min(self.size)*0.1 196 | """ 197 | 198 | class Main(MDApp): 199 | def build(self): 200 | return Builder.load_string(kv) 201 | 202 | def on_start(self): 203 | for x in range(1, 49): 204 | self.root.ids.container.add_widget( 205 | Label(text=f"{x}", color=[0, 0, 0, 1]) 206 | ) 207 | 208 | Main().run() 209 | -------------------------------------------------------------------------------- /kivymd/tools/release/update_icons.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2019-2020 Artem Bulgakov 2 | # 3 | # This file is distributed under the terms of the same license, 4 | # as the Kivy framework. 5 | 6 | """ 7 | Tool for updating Iconic font 8 | ============================= 9 | 10 | Downloads archive from https://github.com/Templarian/MaterialDesign-Webfont and 11 | updates font file with icon_definitions. 12 | """ 13 | 14 | import json 15 | import os 16 | import re 17 | import shutil 18 | import sys 19 | import zipfile 20 | 21 | import requests 22 | 23 | from kivymd.tools.release.git_commands import git_commit 24 | 25 | # Paths to files in kivymd repository 26 | kivymd_path = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) 27 | font_path = os.path.join( 28 | kivymd_path, "fonts", "materialdesignicons-webfont.ttf" 29 | ) 30 | icon_definitions_path = os.path.join(kivymd_path, "icon_definitions.py") 31 | 32 | font_version = "master" 33 | # URL to download new archive (set None if already downloaded) 34 | url = ( 35 | f"https://github.com/Templarian/MaterialDesign-Webfont" 36 | f"/archive/{font_version}.zip" 37 | ) 38 | # url = None 39 | 40 | # Paths to files in loaded archive 41 | temp_path = os.path.join(os.path.dirname(__file__), "temp") 42 | temp_repo_path = os.path.join( 43 | temp_path, f"MaterialDesign-Webfont-{font_version}" 44 | ) 45 | temp_font_path = os.path.join( 46 | temp_repo_path, "fonts", "materialdesignicons-webfont.ttf" 47 | ) 48 | temp_preview_path = os.path.join(temp_repo_path, "preview.html") 49 | 50 | # Regex 51 | re_icons_json = re.compile(r"(?<=var icons = )[\S ]+(?=;)") 52 | re_additional_icons = re.compile(r"(?<=icons\.push\()[\S ]+(?=\);)") 53 | re_version = re.compile(r"(?<=)[\d.]+(?=)") 54 | re_quote_keys = re.compile(r"([{\s,])(\w+)(:)") 55 | re_icon_definitions = re.compile(r"md_icons = {\n([ ]{4}[\s\S]*,\n)*}") 56 | re_version_in_file = re.compile(r"(?<=LAST UPDATED: Version )[\d.]+(?=\n)") 57 | 58 | 59 | def download_file(url, path): 60 | response = requests.get(url, stream=True) 61 | if response.status_code != 200: 62 | return False 63 | with open(path, "wb") as f: 64 | shutil.copyfileobj(response.raw, f) 65 | return True 66 | 67 | 68 | def unzip_archive(archive_path, dir_path): 69 | with zipfile.ZipFile(archive_path, "r") as zip_ref: 70 | zip_ref.extractall(dir_path) 71 | 72 | 73 | def get_icons_list(): 74 | # There is js array with icons in file preview.html 75 | with open(temp_preview_path, "r") as f: 76 | preview_file = f.read() 77 | # Find version 78 | version = re_version.findall(preview_file)[0] 79 | # Load icons 80 | jsons_icons = re_icons_json.findall(preview_file)[0] 81 | json_icons = re_quote_keys.sub(r'\1"\2"\3', jsons_icons) 82 | icons = json.loads(json_icons) 83 | # Find additional icons (like a blank icon) 84 | # jsons_additional_icons = re_additional_icons.findall(preview_file) 85 | # for j in jsons_additional_icons: 86 | # json_additional_icons = re_quote_keys.sub(r'\1"\2"\3', j) 87 | # icons.append(json.loads(json_additional_icons)) 88 | return icons, version 89 | 90 | 91 | def make_icon_definitions(icons): 92 | # Make python dict ("name": hex) 93 | icon_definitions = "md_icons = {\n" 94 | for i in icons: 95 | icon_definitions += " " * 4 96 | if len(i["hex"]) != 4: 97 | # Some icons has 5-digit unicode 98 | i["hex"] = "0" * (8 - len(i["hex"])) + i["hex"] 99 | icon_definitions += f'"{i["name"]}": "\\U{i["hex"].upper()}",\n' 100 | else: 101 | icon_definitions += f'"{i["name"]}": "\\u{i["hex"].upper()}",\n' 102 | icon_definitions += " " * 4 + '"blank": " ",\n' # Add blank icon (space) 103 | icon_definitions += "}" 104 | return icon_definitions 105 | 106 | 107 | def export_icon_definitions(icon_definitions, version): 108 | with open(icon_definitions_path, "r") as f: 109 | icon_definitions_file = f.read() 110 | # Change md_icons list 111 | new_icon_definitions = re_icon_definitions.sub( 112 | icon_definitions.replace("\\", "\\\\"), icon_definitions_file, 1 113 | ) 114 | # Change version 115 | new_icon_definitions = re_version_in_file.sub( 116 | version, new_icon_definitions, 1 117 | ) 118 | with open(icon_definitions_path, "w") as f: 119 | f.write(new_icon_definitions) 120 | 121 | 122 | def update_icons(make_commit: bool = False): 123 | if url is not None: 124 | print(f"Downloading Material Design Icons from {url}") 125 | if download_file(url, "iconic-font.zip"): 126 | print("Archive downloaded") 127 | else: 128 | print("Error: Could not download archive", file=sys.stderr) 129 | else: 130 | print("URL is None. Do not download archive") 131 | if os.path.exists("iconic-font.zip"): 132 | unzip_archive("iconic-font.zip", temp_path) 133 | print("Unzip successful") 134 | os.remove("iconic-font.zip") 135 | if os.path.exists(temp_repo_path): 136 | shutil.copy2(temp_font_path, font_path) 137 | print("Font copied") 138 | icons, version = get_icons_list() 139 | print(f"Version {version}. {len(icons)} icons loaded") 140 | icon_definitions = make_icon_definitions(icons) 141 | export_icon_definitions(icon_definitions, version) 142 | print("File icon_definitions.py updated") 143 | shutil.rmtree(temp_path, ignore_errors=True) 144 | 145 | if make_commit: 146 | git_commit( 147 | f"Update Iconic font (v{version})", 148 | allow_error=True, 149 | add_files=[ 150 | "kivymd/icon_definitions.py", 151 | "kivymd/fonts/materialdesignicons-webfont.ttf", 152 | ], 153 | ) 154 | print("\nSuccessful. You can now push changes") 155 | else: 156 | print( 157 | f'\nSuccessful. Commit message: "Update Iconic font (v{version})"' 158 | ) 159 | else: 160 | print(f"Error: {temp_repo_path} not exists", file=sys.stderr) 161 | exit(1) 162 | 163 | 164 | def main(): 165 | make_commit = "--commit" in sys.argv 166 | if "--commit" in sys.argv: 167 | sys.argv.remove("--commit") 168 | update_icons(make_commit=make_commit) 169 | 170 | 171 | if __name__ == "__main__": 172 | main() 173 | -------------------------------------------------------------------------------- /other/my_gestures.py: -------------------------------------------------------------------------------- 1 | from kivy.gesture import GestureDatabase 2 | 3 | gdb = GestureDatabase() 4 | 5 | cross = gdb.str_to_gesture( 6 | 'eNq1l9tu3DYQhu/1It6bLjicE+cFtrcF/ACBYwv2Iqkt7G7a5u1DDqlT0lZ7I2Mxsj5JP2f4k' 7 | 'xR1OH85//X9+Npfb98uffd7Ow6hO7wM0D0+vD/92T90Q8z/5gN218eH6+3y8aW/5lPqDl8H7g' 8 | '7/KvLot3WDFCnNzw8f5/dbeSyVx+w/Hvuj3NUNUDMoKXzPj0DsTuGIGiRJGCOVbP4pV7E7/Ra' 9 | 'ORJZMwhS1u35++v9WyFvh7rU2ENEMJI1RuLu+NnEEgyhpjEG2xb1y0H3Ek4vbKA6kEmyKEWdx' 10 | 'WPaJsaVN8eidH2Ef8ejiOIqHdbeQLvolaLTFLxlty7ulsVlaNBKChCnmEpp+uRSSIozRBLbl3' 11 | 'dSoe8m7rdF2kkc3FmGSB1FVphYT6qSejY2sOsXtyYRuLOIkHgEtGrZIKJP4Spk13ZG524qzrX' 12 | 'FWLlHmfok/9UvcFndTUe8Rz8OVA7RIYXtAoluKdke3hJU42j0dQ24pwV7ybiptm1oGE+Rz4il' 13 | 'u9w25q8R3qQtnZ2WKd+TutpLeox4pZmt1jHlh3VR3X8nuUceFdIm4qc5uKy9mapCY339jXKb+' 14 | '08tjewlmN5VxH3H3lBcLcASZfzGv4osFPiVk5SnmCb6p766y7qbvvvL0Zg2GKtHGCDjPJ2FKi' 15 | 'cfI2wuNuKsCu2i7qYLzdiP3BXGLYIs1DEAo0hh1eyaJeyq8i7b7KdM26ddNXpPO7SCSTnHbSn' 16 | 'ErxXaQVndSJyeJGQOMMe+RJm1aLrk5bku7kYp7SLuPOvlI6/FHs4+87hH2Fats/p8vff8+beV' 17 | 'Vyl5etTucMA/a7kSE+XAbNHVPmcGK2ZKBsxSciTPUyqAwUmdRKouFCToDqgwLU3MWQmVUmDnD' 18 | '1O7jwsCfOuXFt0JxGKNDaS1rhVwhV5gqpBW0CnEJLaw0G4QKwwrGmlJaQaxw1bp5QRBsBb2iZ' 19 | 'MvczQtSWjGvx09m5uXwmnk1tNKDEGYbZli94TX0aqg1nRrE5Z3WoFdDtWyFBr0aqR2URljLqa' 20 | '1bbNDrsToywth69QfqGIrcaDVoPSoBqkNtbDE1Wi3iqsAtV6gesSdL0vKCalLNdqa5rjpB3vr' 21 | 'z69utfJTmz8qTFclM/z6/3N4cSteSyvT28bW/PL0/935Ffdsd1n9Q7muT+dNw+Xj59lzFU+6W' 22 | 'Y5L8ug5qwTR/PFH5bDz+AM/6Dqo=') 23 | 24 | circle = gdb.str_to_gesture( 25 | 'eNq1WNtyGzcMfd8fiV+iIS4EyB9QXzuTD+g4icbxpLU1ttI2f18QoHa5jpy12qlGAyUw9hA4B' 26 | 'yQh3dx/vf/z++7u8Hz69nSYfumfxzTdfD7C9OHdw+0fh3fTEe2f9kHT84d3z6enx6+HZ/svTz' 27 | 'e/H/N0cxHkg4dNR2lQas8fH+8fTu2x0h6rrzz2a4uajhAZtBS+2yOA0z7tCDMkqjk1y0W1pfN' 28 | '3+zNN+/dpl0pGqmdLJcv0/PH25+uwr5Onu74EMxErVLeGMT3fNXQDT4C1kopbLVBhG92LB91G' 29 | 'h6RJinRb5A2ZF8euM/aP5JyxhVVShbBiJW9ho7OPcMZG1YTzWzTP2LgAm8XyBmx0bJqxsfSkm' 30 | '8UqMzaRluVduW5ju5o4qwkKmFWruM28cGLNcW3eriXOWi5kv8zbNK7GcwmbabtP0LXEWcuB7M' 31 | 'Y3pSVxVuRMiGFJaBOcXEzqYrZtwglLEsluBdOSen7R5LiN7nISzehAwsQZwC3yfwJ3PSnP4FZ' 32 | '31fnNrZX/PS8uKOkCvpBiFkfSF2Sz3PpoC9wVpTqDExXKmkvYmoc274S8nRZ2RXlR1B5u5xGG' 33 | '1bKcK7a5rtz77ILyIihVSVzL2bb8zuB4LefsgnJ+AzjQtTuUXVBeBCVRTKSMbq1HA/u9b7DMo' 34 | 'hpWSLbPFnZFuf4/6NklzYOki57N1rzAQ8YV/HY3Ztc0L5piXR0BMqAj1GItLmELb/OeXdQ87F' 35 | 'KB8QhIOKDXOXGzOb2BGVc1D9sUaNxJNiPM6LQkbpbS9lbKrmpeVAXluRtTTloXdDs2B95z3UY' 36 | 'XV1UWVe2aPydutqAO6HIt7+KqCm0f7A2+Fk1JkNyiTQ+b8C6rzJdpyrkoQUlhUx6IZ61XEi8u' 37 | 'qyzXKSODTSphAcsAjnBlz4irKvN9CjVxsXEwu2UZ9iopXcmLuqgKWwOMb2JJNoh2y284B9Q11' 38 | 'WU6En2NFuRrFVVXVJdhN71QdDhjBIe3a/3xtg3/n54Oh4d5lFdps7zNmjd7Rt2laY9ad3V88X' 39 | 'Q6apluW0TxiAL2Yc7qTkqjs6RwSjgxnOBOhpUTw6krJ7kz06up2D3iETUiNB7L7pT+WLZhf3h' 40 | 'Ji5CIiLyU4zENZ5SlPYWoVSNZTeGMWv25vWnqzhq1amBKYNaotcTjuUdGrSXy8+rMGbWW7E6u' 41 | '66SpRUStJRbgvGZDW0QUXqICjgqqjE6q4dSVM19Yrawi4MJqwUIJyTBqg5TGOpC6F1be9ON6t' 42 | 'tdGVkB+XNA2ZYREjwFfCgmSNJKC8/JBjMbyAN0bzLjS5k3dG9RoLJJK95axY9K52KBAohGShB' 43 | 'eCAgncdIFcABj79nJI8JHzT0L6/kg/CQk+mFd5Q/BBtKoRZNzXZz4g+MC0YhSCD+hqXWhGgCA' 44 | 'n1dcFxWAqdV0uND1gMJWCTIyeBnRy7CtZeLl7KbxRLPaykMObXu1k+1rpIb2VL20Hm9siJFKl' 45 | 'TiTqylu7t4SXx31o35ZW3p4zpZVXLyxNsAq5xBIFH/1syH1FCj76Hs69PSn4KHU8k2w+D5aCZ' 46 | '+lbhKLqGvVJF5+i6hp0yRk3WiLFWSedfepdQOMBCtyFl/GsBe5a9xO4r8axESCNh7UNo+GFVw' 47 | '95YB57VHuaHL0Pebwy7DYPb79IevLcex/W3n7/0dobhWI+X1buzVEoytprhcYN/OVwf/fl1H7' 48 | '0sql+ry83CbbfxP66/3z64iF2m9sJZxjmPT3+fni6ffh08L9w/IixfkGL68PDb8enx8/fPsVS' 49 | 'edrnnc05diDYoIA2CpbUvu7t/gFuoPx3') 50 | 51 | check = gdb.str_to_gesture( 52 | 'eNq1l0tuI0cMhvd9EXsTofgmL6BsA/gAgcYWbGMmtmBpksztwyY1kgZI0rNpbdr+u+pjkX+9+' 53 | 'v718+uf3zbP++Pp68d++vX8PIzp/ukA08Pd2+6P/d10wPwzHzQdH+6Op4/3z/tj/svT/ZeDTP' 54 | 'f/CnmoZtNBZ5Rl/8P769tp7uZzt/iPbr/NraYD9AjmIXzLLoDTdmxgBLsSMMIw5OHzcP6eX9O' 55 | '0/WVsCMFGmCuaGgjBdPy0+/8wXGFkeu4Ig7LzgISbMw/j6fh8hmMMBDIkdBYPimV4pQ7W8EQM' 56 | 'UA4LMhMzCyW5watKgJoOHhxsuIz3wscVb8ExhpIxDoIgvcEzhoaiZ1geA20Rj+UAwlp4LDxd8' 57 | 'OkqO4KHYXLI4oYOwEai4oPRmHiZXr6iXOiY9mXBFUNYacAVDm4uIOCiaXws24plK9oq7PIUr5' 58 | '6iOqsyg+acyOrezJicpTCI3YYy5HtapFNZSldLCcRgCCk4hqniDZ2dHZjCMf1EXh47laNEN2M' 59 | 'fEjkzJFgtK3BLHwEAGTcnlSu7LNPLUbo6+n2m5GbAuVzUr/ShYQzoSBSWi5iXJwyVqWRr4ctX' 60 | '+om1mq+GR7ibAA8dJuHLfC5nGVbjl7dMS/tk1g3tB3OXZyWXsyyrsMtWtlXY5SnHGmwpPwW+s' 61 | '3M15h5CkVvM8FyWcWH3Uce5io00A/8Eu7wUWoVdXoqswi4v5eIlseTWl6e9Cqh6+IUt6OoUwA' 62 | 'JD88KwjC4rJVZAazmpsAa6jFRaA10+qqyBLht1DRu1bNQ1bLSy0S425mWFOc9khtxcnRwuaEW' 63 | '6PZnH8sFp5aPRKuwy0i5GMnsmHJE32dz73a5oG3nJgLyemqDgXKtPu/m2//ix379d7u6m8+Xd' 64 | 'bLrf5jg2Y9picD5OB/NpN4vQIrYYLWKJHiX6aJFblBahRSvRvEUsETuQjRapxe6uHSjPsBK7u' 65 | '0CL0mKUyLKJ25/NLbRaUI+PzwGsRWrxzOr0qKNy5+ydHnVUzsftj7JFdK7cAUSrW3SugrdpRe' 66 | 'eqdluV6Fxdu6hdv6hcCeYabQl7KFG5ElWpiM6itqgtWovWorXYlU6/d234y/71+eWUVud1dRv' 67 | 'z2xT/en06vcwfWiP7QFU51dP7l/3H7u1xX2+gP9F+/MHc7jw1fz98vD99fTxV65yN6YfP81jE' 68 | '8nDMa8j81bD5B2R9zCo=') 69 | 70 | square = gdb.str_to_gesture( 71 | 'eNq1mEluIzcYRvd1EXsT4Z+HC6i3AXyAwG0LttEdW7DUSfr2YZHVEgk4KQGCtZH8RD4OH4eSb' 72 | '1++vfz1c/O0Oxx/vO+mL8v7Hqbbxz1Odzev93/ubqY9lY/ljafD3c3h+P72bXcof8p0+32v0+' 73 | '2HkrtabNrbrPJSf//28nqcq8VcLf+j2u9zqWmPrQdzF36WKkjTFjasKZKMaJwqGTp355/5a56' 74 | '2v8FGREAVLIINymebDl/v/78Zqc3o9LS04EgogK6ECeSlhadFTomIHElsKqoS6/I6dPQL5JiW' 75 | 'aSTKYMZEuS6PKs8L5DD03DB11U51+gnX7EVuGOQUgqDIxHGBnKqc1+XkJXLMyAyXUFkPlGqgp' 76 | 'J/irnmSr7s5kThBIhAB5RJ3jZPOcYpbiIG6elkc81Je3DL222TVzTVMPoVJggFESoEGBIJndy' 77 | 'irWWpYRonyAnfNkk9ZQkQYghuLSlnI7tfIa5i8hDmvZFBSUwdH5ixDgKv6XvNkP+mxbDxgo1S' 78 | '2JIhr3DVPzpOb0IGQ3DTVhTPP8nEH+bpcaqCCJzkHOjlqpISFAp/lZMqMZqIBLnCBvCYqfJKL' 79 | 'EqNyCgkFFNlZjt0qJaD1rS81UTknKuEGqYgRGUZdnsxlnapilrkiKafjurzmKec8Sy12KTPvT' 80 | 'mWn5lle9mS/B2z9MJcaqOSqvC7TflRlkZZ7bM2vNVPFT/PXWJUv8ZO5hkiAQVkz5Wpat9dcVT' 81 | '/JXoNVv8Quoz3Wl43WZDU/x241V1vfq+UrRTFhLicyAxpecG1YTdXOqVLXP4XSRmcHCg/NIPG' 82 | 'AcnOs22uqdk4Vx777dfaaqp2uU+jPWGdkvcpeU7X8HLvXVP10pWJKOdSFksIMSgNXyWuofrpT' 83 | 'yyUKaewgxuCJeJW8ZuqnB6TxIATspkXGJ16r8vkHwMP7bvd6epx3m5/ny0V/uy1X4wamLaWVt' 84 | '+PeY7qfoQ8wG8wGvcKACjMGiDMsj/EDpApRB8gV0lhdKpSxulaoI7QKDQfoDfIAY4Cyyf4lc4' 85 | 'lsJaSV4FotYYDzCd69bC6BfYloU5XUQ88GeYBLA9JD+6BfqX0J1VZtGThVKD72i+cS3k+NUKv' 86 | 'WZkFbhMwfVMu+BOXYHy8lENqcaMuM2vyWp+WB2kJpoLrQNhOqI21Toa3HJAttw5c2fOKFtvGz' 87 | 'jrSNmWikbdAAI11WMw8U23L2HCkOdBkxUk8/msyyCVsj0IeAKAP9aI5R+yJ1+mZqPXVYqPc0f' 88 | 'jUSA82FZk9zmWNqo45hG5WfSB1lWOaCqDMwLDkTD/SXoQy0nTzPu5en52P9f4BO25jbLfTvl8' 89 | 'fjc4VWoDZ4fPu+e79/fdjVL7we0jC+cC63nJJ/7N/fHn88NHdM29xw+VUXOp+Mzm7FcPi6+Re' 90 | 'GcFi7') 91 | -------------------------------------------------------------------------------- /scr/ReminderRepeatingAlarmReceiver.java: -------------------------------------------------------------------------------- 1 | package org.org.remindy; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Intent; 5 | import android.content.Context; 6 | import android.app.NotificationChannel; 7 | import android.app.NotificationManager; 8 | import androidx.core.app.NotificationCompat; 9 | import androidx.core.app.NotificationManagerCompat; 10 | import android.app.Notification; 11 | import android.app.PendingIntent; 12 | import android.os.Build; 13 | import android.os.Bundle; 14 | import org.kivy.android.PythonActivity; 15 | import android.media.RingtoneManager; 16 | import android.net.Uri; 17 | import android.media.AudioAttributes; 18 | import org.remindy.remindy.R; 19 | import java.util.Calendar; 20 | import android.app.AlarmManager; 21 | import java.lang.Math; 22 | 23 | public class ReminderRepeatingAlarmReceiver extends BroadcastReceiver{ 24 | 25 | private void createNotificationChannel(Context context) { 26 | 27 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 28 | Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); 29 | 30 | AudioAttributes att = new AudioAttributes.Builder() 31 | .setUsage(AudioAttributes.USAGE_NOTIFICATION) 32 | .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) 33 | .build(); 34 | 35 | CharSequence name = "New Reminder"; 36 | String description = "New Reminder"; 37 | int importance = NotificationManager.IMPORTANCE_HIGH; 38 | NotificationChannel channel = new NotificationChannel("REMINDY", name, importance); 39 | channel.setDescription(description); 40 | channel.setSound(sound, att); 41 | channel.enableLights(true); 42 | channel.enableVibration(true); 43 | NotificationManager notificationManager = context.getSystemService(NotificationManager.class); 44 | notificationManager.createNotificationChannel(channel); 45 | } 46 | } 47 | 48 | private void sendNotification(Context context, Intent intent) { 49 | Uri uri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); 50 | int notification_id = (int)(Math.random()*(8000-1+1)+1); 51 | Intent newintent = new Intent(context, PythonActivity.class); 52 | Short id = intent.getShortExtra("IDENTIFICATION", (short) 0); 53 | String current_list = intent.getStringExtra("CURRENT_LIST"); 54 | newintent.putExtra("LAUNCH_APP_WITH_REMINDER", id); 55 | newintent.putExtra("CURRENT_LIST",current_list); 56 | PendingIntent pendingintent = PendingIntent.getActivity(context,notification_id, newintent, PendingIntent.FLAG_ONE_SHOT); 57 | 58 | Intent mrkcomp = new Intent(context, ReminderMarkComp.class); 59 | mrkcomp.putExtra("CURRENT_LIST", current_list); 60 | mrkcomp.putExtra("IDENTIFICATION", intent.getExtras().getShort("IDENTIFICATION")); 61 | mrkcomp.putExtra("NOTIFICATION_ID", notification_id); 62 | mrkcomp.putExtra("INTENT_ID", intent.getExtras().getShort("INTENT_ID")); 63 | 64 | mrkcomp.setAction("org.org.remindy.MRKCOMP"); 65 | PendingIntent pendingmrkcomp = PendingIntent.getBroadcast(context,notification_id,mrkcomp, PendingIntent.FLAG_ONE_SHOT); 66 | String title = "Mark As Complete"; 67 | NotificationCompat.Action mrkcompaction = new NotificationCompat.Action.Builder( 0, title, pendingmrkcomp).build(); 68 | 69 | Intent snooze = new Intent(context, ReminderSnooze.class); 70 | snooze.putExtra("TITLE", intent.getExtras().getString("TITLE")); 71 | snooze.putExtra("DESCRIPTION", intent.getExtras().getString("DESCRIPTION")); 72 | snooze.putExtra("IDENTIFICATION", intent.getExtras().getShort("IDENTIFICATION")); 73 | snooze.putExtra("NOTIFICATION_ID", notification_id); 74 | snooze.putExtra("INTENT_ID", intent.getExtras().getShort("INTENT_ID")); 75 | snooze.putExtra("CURRENT_LIST", current_list); 76 | PendingIntent pendingsnooze = PendingIntent.getBroadcast(context, notification_id, snooze, PendingIntent.FLAG_CANCEL_CURRENT); 77 | NotificationCompat.Action snoozeaction = new NotificationCompat.Action.Builder( 0, "Snooze for 10 mins", pendingsnooze).build(); 78 | 79 | NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "REMINDY") 80 | .setSmallIcon(R.drawable.ic_launcher) 81 | .setContentTitle(intent.getExtras().getString("TITLE")) 82 | .setContentText(intent.getExtras().getString("DESCRIPTION")) 83 | .setTicker("New Reminder") 84 | .setVibrate(new long[]{0, 300, 0, 400, 0, 500}) 85 | .setSound(uri) 86 | .setAutoCancel(true) 87 | .setOnlyAlertOnce(false) 88 | .setPriority(NotificationCompat.PRIORITY_HIGH) 89 | .setContentIntent(pendingintent) 90 | .addAction(mrkcompaction) 91 | .addAction(snoozeaction); 92 | 93 | NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context); 94 | notificationManager.notify(192837, builder.build()); 95 | 96 | // We then proceed to reschedule the alarm on the system level alarm manager 97 | 98 | PendingIntent newdaypending = PendingIntent.getBroadcast(context, intent.getExtras().getShort("INTENT_ID"), intent, PendingIntent.FLAG_CANCEL_CURRENT); 99 | Calendar calendar = Calendar.getInstance(); 100 | Long timetoring = calendar.getTimeInMillis() + 7*24*60*60*1000; 101 | AlarmManager alarmManager=(AlarmManager) context.getSystemService(Context.ALARM_SERVICE); 102 | alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,timetoring, newdaypending); 103 | 104 | } 105 | 106 | 107 | 108 | @Override 109 | public void onReceive(Context context, Intent intent) { 110 | this.createNotificationChannel(context); 111 | this.sendNotification(context, intent); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /kivymd/utils/hot_reload_viewer.py: -------------------------------------------------------------------------------- 1 | """ 2 | HotReloadViewer 3 | =============== 4 | 5 | .. Note:: The :class:`~HotReloadViewer` class is based on 6 | the `KvViewerApp `_ class 7 | 8 | :class:`~HotReloadViewer`, for KV-Viewer, is a simple tool allowing you to 9 | dynamically display a KV file, taking its changes into account 10 | (thanks to watchdog). The idea is to facilitate design using the KV language. 11 | 12 | Usage 13 | ----- 14 | 15 | .. code-block:: python 16 | 17 | from kivy.lang import Builder 18 | 19 | from kivymd.app import MDApp 20 | 21 | KV = ''' 22 | #:import KivyLexer kivy.extras.highlight.KivyLexer 23 | #:import HotReloadViewer kivymd.utils.hot_reload_viewer.HotReloadViewer 24 | 25 | 26 | BoxLayout: 27 | 28 | CodeInput: 29 | lexer: KivyLexer() 30 | style_name: "native" 31 | on_text: app.update_kv_file(self.text) 32 | size_hint_x: .7 33 | 34 | HotReloadViewer: 35 | size_hint_x: .3 36 | path: app.path_to_kv_file 37 | errors: True 38 | errors_text_color: 1, 1, 0, 1 39 | errors_background_color: app.theme_cls.bg_dark 40 | ''' 41 | 42 | 43 | class Example(MDApp): 44 | path_to_kv_file = "kv_file.kv" 45 | 46 | def build(self): 47 | self.theme_cls.theme_style = "Dark" 48 | return Builder.load_string(KV) 49 | 50 | def update_kv_file(self, text): 51 | with open(self.path_to_kv_file, "w") as kv_file: 52 | kv_file.write(text) 53 | 54 | 55 | Example().run() 56 | 57 | This will display the test.kv and automatically update the display when the 58 | file changes. 59 | 60 | .. raw:: html 61 | 62 |
63 | 64 |
65 | 66 | 67 | .. rubric:: This scripts uses watchdog to listen for file changes. To install 68 | watchdog. 69 | 70 | .. code-block:: bash 71 | 72 | pip install watchdog 73 | """ 74 | 75 | import os 76 | 77 | from kivy.clock import Clock, mainthread 78 | from kivy.lang import Builder 79 | from kivy.properties import BooleanProperty, ColorProperty, StringProperty 80 | from kivy.uix.scrollview import ScrollView 81 | from watchdog.events import FileSystemEventHandler 82 | from watchdog.observers import Observer 83 | 84 | from kivymd.theming import ThemableBehavior 85 | from kivymd.uix.boxlayout import MDBoxLayout 86 | 87 | Builder.load_string( 88 | """ 89 | 90 | 91 | MDLabel: 92 | size_hint_y: None 93 | height: self.texture_size[1] 94 | theme_text_color: "Custom" 95 | text_color: 96 | root.errors_text_color if root.errors_text_color \ 97 | else root.theme_cls.text_color 98 | text: root.text 99 | """ 100 | ) 101 | 102 | 103 | class HotReloadErrorText(ThemableBehavior, ScrollView): 104 | text = StringProperty() 105 | """Text errors. 106 | 107 | :attr:`text` is an :class:`~kivy.properties.StringProperty` 108 | and defaults to `''`. 109 | """ 110 | 111 | errors_text_color = ColorProperty(None) 112 | """ 113 | Error text color. 114 | 115 | :attr:`errors_text_color` is an :class:`~kivy.properties.ColorProperty` 116 | and defaults to `None`. 117 | """ 118 | 119 | 120 | class HotReloadHandler(FileSystemEventHandler): 121 | def __init__(self, callback, target, **kwargs): 122 | super().__init__(**kwargs) 123 | self.callback = callback 124 | self.target = target 125 | 126 | def on_any_event(self, event): 127 | self.callback() 128 | 129 | 130 | class HotReloadViewer(ThemableBehavior, MDBoxLayout): 131 | """ 132 | :Events: 133 | :attr:`on_error` 134 | Called when an error occurs in the KV-file that the user is editing. 135 | """ 136 | 137 | path = StringProperty() 138 | """Path to KV file. 139 | 140 | :attr:`path` is an :class:`~kivy.properties.StringProperty` 141 | and defaults to `''`. 142 | """ 143 | 144 | errors = BooleanProperty(False) 145 | """ 146 | Show errors while editing KV-file. 147 | 148 | :attr:`errors` is an :class:`~kivy.properties.BooleanProperty` 149 | and defaults to `False`. 150 | """ 151 | 152 | errors_background_color = ColorProperty(None) 153 | """ 154 | Error background color. 155 | 156 | :attr:`errors_background_color` is an :class:`~kivy.properties.ColorProperty` 157 | and defaults to `None`. 158 | """ 159 | 160 | errors_text_color = ColorProperty(None) 161 | """ 162 | Error text color. 163 | 164 | :attr:`errors_text_color` is an :class:`~kivy.properties.ColorProperty` 165 | and defaults to `None`. 166 | """ 167 | 168 | _temp_widget = None 169 | 170 | def __init__(self, **kwargs): 171 | self.observer = Observer() 172 | self.error_text = HotReloadErrorText() 173 | super().__init__(**kwargs) 174 | self.register_event_type("on_error") 175 | 176 | @mainthread 177 | def update(self, *args): 178 | """Updates and displays the KV-file that the user edits.""" 179 | 180 | Builder.unload_file(self.path) 181 | self.clear_widgets() 182 | try: 183 | self.padding = (0, 0, 0, 0) 184 | self.md_bg_color = (0, 0, 0, 0) 185 | self._temp_widget = Builder.load_file(self.path) 186 | self.add_widget(self._temp_widget) 187 | except Exception as error: 188 | self.show_error(error) 189 | self.dispatch("on_error", error) 190 | 191 | def show_error(self, error): 192 | """Displays text with a current error.""" 193 | 194 | if self._temp_widget and not self.errors: 195 | self.add_widget(self._temp_widget) 196 | return 197 | else: 198 | if self.errors_background_color: 199 | self.md_bg_color = self.errors_background_color 200 | self.padding = ("4dp", "4dp", "4dp", "4dp") 201 | self.error_text.text = ( 202 | error.message 203 | if getattr(error, r"message", None) 204 | else str(error) 205 | ) 206 | self.add_widget(self.error_text) 207 | 208 | def on_error(self, *args): 209 | """ 210 | Called when an error occurs in the KV-file that the user is editing. 211 | """ 212 | 213 | def on_errors_text_color(self, instance, value): 214 | self.error_text.errors_text_color = value 215 | 216 | def on_path(self, instance, value): 217 | value = os.path.abspath(value) 218 | self.observer.schedule( 219 | HotReloadHandler(self.update, value), os.path.dirname(value) 220 | ) 221 | self.observer.start() 222 | Clock.schedule_once(self.update, 1) 223 | -------------------------------------------------------------------------------- /kivymd/uix/behaviors/toggle_behavior.py: -------------------------------------------------------------------------------- 1 | """ 2 | Behaviors/ToggleButton 3 | ====================== 4 | 5 | This behavior must always be inherited after the button's Widget class since it 6 | works with the inherited properties of the button class. 7 | 8 | example: 9 | 10 | .. code-block:: python 11 | 12 | class MyToggleButtonWidget(MDFlatButton, MDToggleButton): 13 | # [...] 14 | pass 15 | 16 | 17 | .. code-block:: python 18 | 19 | from kivy.lang import Builder 20 | 21 | from kivymd.app import MDApp 22 | from kivymd.uix.behaviors.toggle_behavior import MDToggleButton 23 | from kivymd.uix.button import MDRectangleFlatButton 24 | 25 | KV = ''' 26 | Screen: 27 | 28 | MDBoxLayout: 29 | adaptive_size: True 30 | pos_hint: {"center_x": .5, "center_y": .5} 31 | 32 | MyToggleButton: 33 | text: "Show ads" 34 | group: "x" 35 | 36 | MyToggleButton: 37 | text: "Do not show ads" 38 | group: "x" 39 | 40 | MyToggleButton: 41 | text: "Does not matter" 42 | group: "x" 43 | ''' 44 | 45 | 46 | class MyToggleButton(MDRectangleFlatButton, MDToggleButton): 47 | def __init__(self, **kwargs): 48 | super().__init__(**kwargs) 49 | self.background_down = self.theme_cls.primary_light 50 | 51 | 52 | class Test(MDApp): 53 | def build(self): 54 | return Builder.load_string(KV) 55 | 56 | 57 | Test().run() 58 | 59 | .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/toggle-button-1.gif 60 | :align: center 61 | 62 | .. code-block:: python 63 | 64 | class MyToggleButton(MDFillRoundFlatButton, MDToggleButton): 65 | def __init__(self, **kwargs): 66 | self.background_down = MDApp.get_running_app().theme_cls.primary_dark 67 | super().__init__(**kwargs) 68 | 69 | .. image:: https://github.com/HeaTTheatR/KivyMD-data/raw/master/gallery/kivymddoc/toggle-button-2.gif 70 | :align: center 71 | 72 | You can inherit the ``MyToggleButton`` class only from the following classes 73 | ---------------------------------------------------------------------------- 74 | 75 | - :class:`~kivymd.uix.button.MDRaisedButton` 76 | - :class:`~kivymd.uix.button.MDFlatButton` 77 | - :class:`~kivymd.uix.button.MDRectangleFlatButton` 78 | - :class:`~kivymd.uix.button.MDRectangleFlatIconButton` 79 | - :class:`~kivymd.uix.button.MDRoundFlatButton` 80 | - :class:`~kivymd.uix.button.MDRoundFlatIconButton` 81 | - :class:`~kivymd.uix.button.MDFillRoundFlatButton` 82 | - :class:`~kivymd.uix.button.MDFillRoundFlatIconButton` 83 | """ 84 | 85 | __all__ = ("MDToggleButton",) 86 | 87 | from kivy.properties import BooleanProperty, ColorProperty 88 | from kivy.uix.behaviors import ToggleButtonBehavior 89 | 90 | from kivymd.uix.button import ( 91 | MDFillRoundFlatButton, 92 | MDFillRoundFlatIconButton, 93 | MDFlatButton, 94 | MDRaisedButton, 95 | MDRectangleFlatButton, 96 | MDRectangleFlatIconButton, 97 | MDRoundFlatButton, 98 | MDRoundFlatIconButton, 99 | ) 100 | 101 | 102 | class MDToggleButton(ToggleButtonBehavior): 103 | background_normal = ColorProperty(None) 104 | """ 105 | Color of the button in ``rgba`` format for the 'normal' state. 106 | 107 | :attr:`background_normal` is a :class:`~kivy.properties.ColorProperty` 108 | and is defaults to `None`. 109 | """ 110 | 111 | background_down = ColorProperty(None) 112 | """ 113 | Color of the button in ``rgba`` format for the 'down' state. 114 | 115 | :attr:`background_down` is a :class:`~kivy.properties.ColorProperty` 116 | and is defaults to `None`. 117 | """ 118 | 119 | font_color_normal = ColorProperty(None) 120 | """ 121 | Color of the font's button in ``rgba`` format for the 'normal' state. 122 | 123 | :attr:`font_color_normal` is a :class:`~kivy.properties.ColorProperty` 124 | and is defaults to `None`. 125 | """ 126 | 127 | font_color_down = ColorProperty([1, 1, 1, 1]) 128 | """ 129 | Color of the font's button in ``rgba`` format for the 'down' state. 130 | 131 | :attr:`font_color_down` is a :class:`~kivy.properties.ColorProperty` 132 | and is defaults to `[1, 1, 1, 1]`. 133 | """ 134 | 135 | __is_filled = BooleanProperty(False) 136 | 137 | def __init__(self, **kwargs): 138 | super().__init__(**kwargs) 139 | classinfo = ( 140 | MDRaisedButton, 141 | MDFlatButton, 142 | MDRectangleFlatButton, 143 | MDRectangleFlatIconButton, 144 | MDRoundFlatButton, 145 | MDRoundFlatIconButton, 146 | MDFillRoundFlatButton, 147 | MDFillRoundFlatIconButton, 148 | ) 149 | # Do the object inherited from the "supported" buttons? 150 | if not issubclass(self.__class__, classinfo): 151 | raise ValueError( 152 | f"Class {self.__class__} must be inherited from one of the classes in the list {classinfo}" 153 | ) 154 | if ( 155 | not self.background_normal 156 | ): # This means that if the value == [] or None will return True. 157 | # If the object inherits from buttons with background: 158 | if isinstance( 159 | self, 160 | ( 161 | MDRaisedButton, 162 | MDFillRoundFlatButton, 163 | MDFillRoundFlatIconButton, 164 | ), 165 | ): 166 | self.__is_filled = True 167 | self.background_normal = self.theme_cls.primary_color 168 | # If not the background_normal must be the same as the inherited one: 169 | else: 170 | self.background_normal = self.md_bg_color[:] 171 | # If no background_down is setted: 172 | if ( 173 | not self.background_down 174 | ): # This means that if the value == [] or None will return True. 175 | self.background_down = ( 176 | self.theme_cls.primary_dark 177 | ) # get the primary_color dark from theme_cls 178 | if not self.font_color_normal: 179 | self.font_color_normal = self.theme_cls.primary_color 180 | # Alternative to bind the function to the property. 181 | # self.bind(state=self._update_bg) 182 | self.fbind("state", self._update_bg) 183 | 184 | def _update_bg(self, ins, val): 185 | """Updates the color of the background.""" 186 | 187 | if val == "down": 188 | self.md_bg_color = self.background_down 189 | if ( 190 | self.__is_filled is False 191 | ): # If the background is transparent, and the button it toggled, 192 | # the font color must be withe [1, 1, 1, 1]. 193 | self.text_color = self.font_color_down 194 | if self.group: 195 | self._release_group(self) 196 | else: 197 | self.md_bg_color = self.background_normal 198 | if ( 199 | self.__is_filled is False 200 | ): # If the background is transparent, the font color must be the 201 | # primary color. 202 | self.text_color = self.font_color_normal 203 | -------------------------------------------------------------------------------- /kivymd/uix/refreshlayout.py: -------------------------------------------------------------------------------- 1 | """ 2 | Components/Refresh Layout 3 | ========================= 4 | 5 | Example 6 | ------- 7 | 8 | .. code-block:: python 9 | 10 | from kivymd.app import MDApp 11 | from kivy.clock import Clock 12 | from kivy.lang import Builder 13 | from kivy.factory import Factory 14 | from kivy.properties import StringProperty 15 | 16 | from kivymd.uix.button import MDIconButton 17 | from kivymd.icon_definitions import md_icons 18 | from kivymd.uix.list import ILeftBodyTouch, OneLineIconListItem 19 | from kivymd.theming import ThemeManager 20 | from kivymd.utils import asynckivy 21 | 22 | Builder.load_string(''' 23 | 24 | text: root.text 25 | 26 | IconLeftSampleWidget: 27 | icon: root.icon 28 | 29 | 30 | 31 | 32 | BoxLayout: 33 | orientation: 'vertical' 34 | 35 | MDToolbar: 36 | title: app.title 37 | md_bg_color: app.theme_cls.primary_color 38 | background_palette: 'Primary' 39 | elevation: 10 40 | left_action_items: [['menu', lambda x: x]] 41 | 42 | MDScrollViewRefreshLayout: 43 | id: refresh_layout 44 | refresh_callback: app.refresh_callback 45 | root_layout: root 46 | 47 | MDGridLayout: 48 | id: box 49 | adaptive_height: True 50 | cols: 1 51 | ''') 52 | 53 | 54 | class IconLeftSampleWidget(ILeftBodyTouch, MDIconButton): 55 | pass 56 | 57 | 58 | class ItemForList(OneLineIconListItem): 59 | icon = StringProperty() 60 | 61 | 62 | class Example(MDApp): 63 | title = 'Example Refresh Layout' 64 | screen = None 65 | x = 0 66 | y = 15 67 | 68 | def build(self): 69 | self.screen = Factory.Example() 70 | self.set_list() 71 | 72 | return self.screen 73 | 74 | def set_list(self): 75 | async def set_list(): 76 | names_icons_list = list(md_icons.keys())[self.x:self.y] 77 | for name_icon in names_icons_list: 78 | await asynckivy.sleep(0) 79 | self.screen.ids.box.add_widget( 80 | ItemForList(icon=name_icon, text=name_icon)) 81 | asynckivy.start(set_list()) 82 | 83 | def refresh_callback(self, *args): 84 | '''A method that updates the state of your application 85 | while the spinner remains on the screen.''' 86 | 87 | def refresh_callback(interval): 88 | self.screen.ids.box.clear_widgets() 89 | if self.x == 0: 90 | self.x, self.y = 15, 30 91 | else: 92 | self.x, self.y = 0, 15 93 | self.set_list() 94 | self.screen.ids.refresh_layout.refresh_done() 95 | self.tick = 0 96 | 97 | Clock.schedule_once(refresh_callback, 1) 98 | 99 | 100 | Example().run() 101 | """ 102 | 103 | from kivy.animation import Animation 104 | from kivy.core.window import Window 105 | from kivy.effects.dampedscroll import DampedScrollEffect 106 | from kivy.lang import Builder 107 | from kivy.metrics import dp 108 | from kivy.properties import ColorProperty, NumericProperty, ObjectProperty 109 | from kivy.uix.floatlayout import FloatLayout 110 | from kivy.uix.scrollview import ScrollView 111 | 112 | from kivymd.theming import ThemableBehavior 113 | 114 | Builder.load_string( 115 | """ 116 | #:import Window kivy.core.window.Window 117 | 118 | 119 | 120 | 121 | AnchorLayout: 122 | id: body_spinner 123 | size_hint: None, None 124 | size: dp(46), dp(46) 125 | y: Window.height 126 | pos_hint: {'center_x': .5} 127 | anchor_x: 'center' 128 | anchor_y: 'center' 129 | 130 | canvas: 131 | Clear 132 | Color: 133 | rgba: root.theme_cls.primary_dark 134 | Ellipse: 135 | pos: self.pos 136 | size: self.size 137 | 138 | MDSpinner: 139 | id: spinner 140 | size_hint: None, None 141 | size: dp(30), dp(30) 142 | color: 1, 1, 1, 1 143 | """ 144 | ) 145 | 146 | 147 | class _RefreshScrollEffect(DampedScrollEffect): 148 | """This class is simply based on DampedScrollEffect. 149 | If you need any documentation please look at kivy.effects.dampedscrolleffect. 150 | """ 151 | 152 | min_scroll_to_reload = NumericProperty("-100dp") 153 | """Minimum overscroll value to reload.""" 154 | 155 | def on_overscroll(self, scrollview, overscroll): 156 | if overscroll < self.min_scroll_to_reload: 157 | scroll_view = self.target_widget.parent 158 | scroll_view._did_overscroll = True 159 | return True 160 | else: 161 | return False 162 | 163 | 164 | class MDScrollViewRefreshLayout(ScrollView): 165 | root_layout = ObjectProperty() 166 | """The spinner will be attached to this layout.""" 167 | 168 | def __init__(self, **kargs): 169 | super().__init__(**kargs) 170 | self.effect_cls = _RefreshScrollEffect 171 | self._work_spinnrer = False 172 | self._did_overscroll = False 173 | self.refresh_spinner = None 174 | 175 | def on_touch_up(self, *args): 176 | if self._did_overscroll and not self._work_spinnrer: 177 | if self.refresh_callback: 178 | self.refresh_callback() 179 | if not self.refresh_spinner: 180 | self.refresh_spinner = RefreshSpinner(_refresh_layout=self) 181 | self.root_layout.add_widget(self.refresh_spinner) 182 | self.refresh_spinner.start_anim_spinner() 183 | self._work_spinnrer = True 184 | self._did_overscroll = False 185 | return True 186 | 187 | return super().on_touch_up(*args) 188 | 189 | def refresh_done(self): 190 | if self.refresh_spinner: 191 | self.refresh_spinner.hide_anim_spinner() 192 | 193 | 194 | class RefreshSpinner(ThemableBehavior, FloatLayout): 195 | spinner_color = ColorProperty([1, 1, 1, 1]) 196 | 197 | _refresh_layout = ObjectProperty() 198 | """kivymd.refreshlayout.MDScrollViewRefreshLayout object.""" 199 | 200 | def start_anim_spinner(self): 201 | spinner = self.ids.body_spinner 202 | Animation( 203 | y=spinner.y - self.theme_cls.standard_increment * 2 + dp(10), 204 | d=0.8, 205 | t="out_elastic", 206 | ).start(spinner) 207 | 208 | def hide_anim_spinner(self): 209 | spinner = self.ids.body_spinner 210 | anim = Animation(y=Window.height, d=0.8, t="out_elastic") 211 | anim.bind(on_complete=self.set_spinner) 212 | anim.start(spinner) 213 | 214 | def set_spinner(self, *args): 215 | body_spinner = self.ids.body_spinner 216 | body_spinner.size = (dp(46), dp(46)) 217 | body_spinner.y = Window.height 218 | body_spinner.opacity = 1 219 | spinner = self.ids.spinner 220 | spinner.size = (dp(30), dp(30)) 221 | spinner.opacity = 1 222 | self._refresh_layout._work_spinnrer = False 223 | self._refresh_layout._did_overscroll = False 224 | -------------------------------------------------------------------------------- /kivymd/uix/behaviors/backgroundcolor_behavior.py: -------------------------------------------------------------------------------- 1 | """ 2 | Behaviors/Background Color 3 | ========================== 4 | 5 | .. note:: The following classes are intended for in-house use of the library. 6 | """ 7 | 8 | __all__ = ("BackgroundColorBehavior", "SpecificBackgroundColorBehavior") 9 | 10 | from kivy.lang import Builder 11 | from kivy.properties import ( 12 | BoundedNumericProperty, 13 | ColorProperty, 14 | ListProperty, 15 | NumericProperty, 16 | OptionProperty, 17 | ReferenceListProperty, 18 | StringProperty, 19 | VariableListProperty, 20 | ) 21 | from kivy.utils import get_color_from_hex 22 | 23 | from kivymd.color_definitions import hue, palette, text_colors 24 | 25 | from .elevation import CommonElevationBehavior 26 | 27 | Builder.load_string( 28 | """ 29 | #:import RelativeLayout kivy.uix.relativelayout.RelativeLayout 30 | 31 | 32 | 33 | canvas.before: 34 | PushMatrix 35 | Rotate: 36 | angle: self.angle 37 | origin: self._background_origin 38 | Color: 39 | rgba: self.md_bg_color 40 | RoundedRectangle: 41 | group: "Background_instruction" 42 | size: self.size 43 | pos: self.pos if not isinstance(self, RelativeLayout) else (0, 0) 44 | radius: root.radius 45 | source: root.background 46 | PopMatrix 47 | """, 48 | filename="BackgroundColorBehavior.kv", 49 | ) 50 | 51 | 52 | class BackgroundColorBehavior(CommonElevationBehavior): 53 | background = StringProperty() 54 | """ 55 | Background image path. 56 | 57 | :attr:`background` is a :class:`~kivy.properties.StringProperty` 58 | and defaults to `None`. 59 | """ 60 | 61 | r = BoundedNumericProperty(1.0, min=0.0, max=1.0) 62 | """ 63 | The value of ``red`` in the ``rgba`` palette. 64 | 65 | :attr:`r` is an :class:`~kivy.properties.BoundedNumericProperty` 66 | and defaults to `1.0`. 67 | """ 68 | 69 | g = BoundedNumericProperty(1.0, min=0.0, max=1.0) 70 | """ 71 | The value of ``green`` in the ``rgba`` palette. 72 | 73 | :attr:`g` is an :class:`~kivy.properties.BoundedNumericProperty` 74 | and defaults to `1.0`. 75 | """ 76 | 77 | b = BoundedNumericProperty(1.0, min=0.0, max=1.0) 78 | """ 79 | The value of ``blue`` in the ``rgba`` palette. 80 | 81 | :attr:`b` is an :class:`~kivy.properties.BoundedNumericProperty` 82 | and defaults to `1.0`. 83 | """ 84 | 85 | a = BoundedNumericProperty(0.0, min=0.0, max=1.0) 86 | """ 87 | The value of ``alpha channel`` in the ``rgba`` palette. 88 | 89 | :attr:`a` is an :class:`~kivy.properties.BoundedNumericProperty` 90 | and defaults to `0.0`. 91 | """ 92 | 93 | radius = VariableListProperty([0], length=4) 94 | """ 95 | Canvas radius. 96 | 97 | .. code-block:: python 98 | 99 | # Top left corner slice. 100 | MDBoxLayout: 101 | md_bg_color: app.theme_cls.primary_color 102 | radius: [25, 0, 0, 0] 103 | 104 | :attr:`radius` is an :class:`~kivy.properties.VariableListProperty` 105 | and defaults to `[0, 0, 0, 0]`. 106 | """ 107 | 108 | md_bg_color = ReferenceListProperty(r, g, b, a) 109 | """ 110 | The background color of the widget (:class:`~kivy.uix.widget.Widget`) 111 | that will be inherited from the :attr:`BackgroundColorBehavior` class. 112 | 113 | For example: 114 | 115 | .. code-block:: kv 116 | 117 | Widget: 118 | canvas: 119 | Color: 120 | rgba: 0, 1, 1, 1 121 | Rectangle: 122 | size: self.size 123 | pos: self.pos 124 | 125 | similar to code: 126 | 127 | .. code-block:: kv 128 | 129 | 130 | md_bg_color: 0, 1, 1, 1 131 | 132 | :attr:`md_bg_color` is an :class:`~kivy.properties.ReferenceListProperty` 133 | and defaults to :attr:`r`, :attr:`g`, :attr:`b`, :attr:`a`. 134 | """ 135 | 136 | angle = NumericProperty(0) 137 | background_origin = ListProperty(None) 138 | 139 | _background_x = NumericProperty(0) 140 | _background_y = NumericProperty(0) 141 | _background_origin = ReferenceListProperty( 142 | _background_x, 143 | _background_y, 144 | ) 145 | 146 | def __init__(self, **kwarg): 147 | super().__init__(**kwarg) 148 | self.bind(pos=self.update_background_origin) 149 | 150 | def update_background_origin(self, *args): 151 | if self.background_origin: 152 | self._background_origin = self.background_origin 153 | else: 154 | self._background_origin = self.center 155 | 156 | 157 | class SpecificBackgroundColorBehavior(BackgroundColorBehavior): 158 | background_palette = OptionProperty( 159 | "Primary", options=["Primary", "Accent", *palette] 160 | ) 161 | """ 162 | See :attr:`kivymd.color_definitions.palette`. 163 | 164 | :attr:`background_palette` is an :class:`~kivy.properties.OptionProperty` 165 | and defaults to `'Primary'`. 166 | """ 167 | 168 | background_hue = OptionProperty("500", options=hue) 169 | """ 170 | See :attr:`kivymd.color_definitions.hue`. 171 | 172 | :attr:`background_hue` is an :class:`~kivy.properties.OptionProperty` 173 | and defaults to `'500'`. 174 | """ 175 | 176 | specific_text_color = ColorProperty([0, 0, 0, 0.87]) 177 | """ 178 | :attr:`specific_text_color` is an :class:`~kivy.properties.ColorProperty` 179 | and defaults to `[0, 0, 0, 0.87]`. 180 | """ 181 | 182 | specific_secondary_text_color = ColorProperty([0, 0, 0, 0.87]) 183 | """ 184 | :attr:`specific_secondary_text_color`is an :class:`~kivy.properties.ColorProperty` 185 | and defaults to `[0, 0, 0, 0.87]`. 186 | """ 187 | 188 | def __init__(self, **kwargs): 189 | super().__init__(**kwargs) 190 | if hasattr(self, "theme_cls"): 191 | self.theme_cls.bind( 192 | primary_palette=self._update_specific_text_color 193 | ) 194 | self.theme_cls.bind(accent_palette=self._update_specific_text_color) 195 | self.theme_cls.bind(theme_style=self._update_specific_text_color) 196 | self.bind(background_hue=self._update_specific_text_color) 197 | self.bind(background_palette=self._update_specific_text_color) 198 | self._update_specific_text_color(None, None) 199 | 200 | def _update_specific_text_color(self, instance, value): 201 | if hasattr(self, "theme_cls"): 202 | palette = { 203 | "Primary": self.theme_cls.primary_palette, 204 | "Accent": self.theme_cls.accent_palette, 205 | }.get(self.background_palette, self.background_palette) 206 | else: 207 | palette = {"Primary": "Blue", "Accent": "Amber"}.get( 208 | self.background_palette, self.background_palette 209 | ) 210 | color = get_color_from_hex(text_colors[palette][self.background_hue]) 211 | secondary_color = color[:] 212 | # Check for black text (need to adjust opacity). 213 | if (color[0] + color[1] + color[2]) == 0: 214 | color[3] = 0.87 215 | secondary_color[3] = 0.54 216 | else: 217 | secondary_color[3] = 0.7 218 | self.specific_text_color = color 219 | self.specific_secondary_text_color = secondary_color 220 | -------------------------------------------------------------------------------- /kivymd/uix/carousel.py: -------------------------------------------------------------------------------- 1 | """ 2 | Components/Carousel 3 | ===================== 4 | 5 | :class:`~kivy.uix.boxlayout.Carousel` class equivalent. Simplifies working 6 | with some widget properties. For example: 7 | 8 | 9 | Carousel 10 | --------- 11 | 12 | .. code-block:: python 13 | 14 | kv=''' 15 | YourCarousel: 16 | BoxLayout: 17 | [...] 18 | BoxLayout: 19 | [...] 20 | BoxLayout: 21 | [...] 22 | ''' 23 | builder.load_string(kv) 24 | 25 | class YourCarousel(Carousel): 26 | def __init__(self,*kwargs): 27 | self.register_event_type("on_slide_progress") 28 | self.register_event_type("on_slide_complete") 29 | 30 | def on_touch_down(self, *args): 31 | ["Code to detect when the slide changes"] 32 | 33 | def on_touch_up(self, *args): 34 | ["Code to detect when the slide changes"] 35 | 36 | def Calculate_slide_pos(self, *args): 37 | ["Code to calculate the current position of the slide"] 38 | 39 | def do_custom_animation(self, *args) 40 | ["Code to recreate an animation"] 41 | 42 | 43 | MDCarousel 44 | ----------- 45 | 46 | .. code-block:: kv 47 | 48 | MDCarousel: 49 | on_slide_progress: 50 | do_something() 51 | on_slide_complete: 52 | do_something() 53 | 54 | """ 55 | # TODO: Add documentation. 56 | 57 | from kivy.animation import Animation 58 | from kivy.uix.carousel import Carousel 59 | 60 | 61 | class MDCarousel(Carousel): 62 | """ 63 | based on kivy's carousel. 64 | 65 | .. seealso:: 66 | `kivy.uix.carousel.Carousel `_ 67 | """ 68 | 69 | _scrolling = False 70 | 71 | def __init__(self, **kwargs): 72 | super().__init__(**kwargs) 73 | self.register_event_type("on_slide_progress") 74 | self.register_event_type("on_slide_complete") 75 | 76 | def on_slide_progress(self, *args): 77 | """ 78 | Event launched when the Slide animation is progress. 79 | rememebr to bind and unbid to this method. 80 | """ 81 | pass 82 | 83 | def on_slide_complete(self, *args): 84 | """ 85 | Event launched when the Slide animation is complete. 86 | rememebr to bind and unbid to this method. 87 | """ 88 | pass 89 | 90 | def _position_visible_slides(self, *args): 91 | slides, index = self.slides, self.index 92 | no_of_slides = len(slides) - 1 93 | if not slides: 94 | return 95 | x, y, width, height = self.x, self.y, self.width, self.height 96 | _offset, direction = self._offset, self.direction 97 | _prev, _next, _current = self._prev, self._next, self._current 98 | get_slide_container = self.get_slide_container 99 | last_slide = get_slide_container(slides[-1]) 100 | first_slide = get_slide_container(slides[0]) 101 | skip_next = False 102 | _loop = self.loop 103 | 104 | if direction[0] in ["r", "l"]: 105 | xoff = x + _offset 106 | x_prev = {"l": xoff + width, "r": xoff - width} 107 | x_next = {"l": xoff - width, "r": xoff + width} 108 | if _prev: 109 | _prev.pos = (x_prev[direction[0]], y) 110 | elif _loop and _next and index == 0: 111 | if (_offset > 0 and direction[0] == "r") or ( 112 | _offset < 0 and direction[0] == "l" 113 | ): 114 | last_slide.pos = (x_prev[direction[0]], y) 115 | skip_next = True 116 | if _current: 117 | _current.pos = (xoff, y) 118 | 119 | if self._scrolling: 120 | self.dispatch("on_slide_progress", (xoff, y)) 121 | 122 | if skip_next: 123 | return 124 | if _next: 125 | _next.pos = (x_next[direction[0]], y) 126 | elif _loop and _prev and index == no_of_slides: 127 | if (_offset < 0 and direction[0] == "r") or ( 128 | _offset > 0 and direction[0] == "l" 129 | ): 130 | first_slide.pos = (x_next[direction[0]], y) 131 | if direction[0] in ["t", "b"]: 132 | yoff = y + _offset 133 | y_prev = {"t": yoff - height, "b": yoff + height} 134 | y_next = {"t": yoff + height, "b": yoff - height} 135 | if _prev: 136 | _prev.pos = (x, y_prev[direction[0]]) 137 | elif _loop and _next and index == 0: 138 | if (_offset > 0 and direction[0] == "t") or ( 139 | _offset < 0 and direction[0] == "b" 140 | ): 141 | last_slide.pos = (x, y_prev[direction[0]]) 142 | skip_next = True 143 | if _current: 144 | _current.pos = (x, yoff) 145 | if skip_next: 146 | return 147 | if _next: 148 | _next.pos = (x, y_next[direction[0]]) 149 | elif _loop and _prev and index == no_of_slides: 150 | if (_offset < 0 and direction[0] == "t") or ( 151 | _offset > 0 and direction[0] == "b" 152 | ): 153 | first_slide.pos = (x, y_next[direction[0]]) 154 | 155 | def on_touch_down(self, touch): 156 | self._scrolling = True 157 | return super().on_touch_down(touch) 158 | 159 | def on_touch_up(self, touch): 160 | self._scrolling = False 161 | return super().on_touch_up(touch) 162 | 163 | def _start_animation(self, *args, **kwargs): 164 | # compute target offset for ease back, next or prev 165 | new_offset = 0 166 | direction = kwargs.get("direction", self.direction)[0] 167 | is_horizontal = direction in "rl" 168 | extent = self.width if is_horizontal else self.height 169 | min_move = kwargs.get("min_move", self.min_move) 170 | _offset = kwargs.get("offset", self._offset) 171 | 172 | if _offset < min_move * -extent: 173 | new_offset = -extent 174 | elif _offset > min_move * extent: 175 | new_offset = extent 176 | 177 | # if new_offset is 0, it wasnt enough to go next/prev 178 | dur = self.anim_move_duration 179 | if new_offset == 0: 180 | dur = self.anim_cancel_duration 181 | 182 | # detect edge cases if not looping 183 | len_slides = len(self.slides) 184 | index = self.index 185 | if not self.loop or len_slides == 1: 186 | is_first = index == 0 187 | is_last = index == len_slides - 1 188 | if direction in "rt": 189 | towards_prev = new_offset > 0 190 | towards_next = new_offset < 0 191 | else: 192 | towards_prev = new_offset < 0 193 | towards_next = new_offset > 0 194 | if (is_first and towards_prev) or (is_last and towards_next): 195 | new_offset = 0 196 | 197 | anim = Animation(_offset=new_offset, d=dur, t=self.anim_type) 198 | anim.cancel_all(self) 199 | 200 | def _cmp(*args): 201 | self.dispatch( 202 | "on_slide_complete", 203 | self.previous_slide, 204 | self.current_slide, 205 | self.next_slide, 206 | ) 207 | if self._skip_slide is not None: 208 | self.index = self._skip_slide 209 | self._skip_slide = None 210 | 211 | anim.bind(on_complete=_cmp) 212 | anim.start(self) 213 | --------------------------------------------------------------------------------