diff --git a/.gitignore b/.gitignore index b6e4761..6034e6b 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,6 @@ dmypy.json # Pyre type checker .pyre/ + +# Kivy +.buildozer/ diff --git a/MockUps/Canva/Version 1/1.png b/MockUps/Canva/Version 1/1.png new file mode 100644 index 0000000..b3a66be Binary files /dev/null and b/MockUps/Canva/Version 1/1.png differ diff --git a/MockUps/Canva/Version 1/2.png b/MockUps/Canva/Version 1/2.png new file mode 100644 index 0000000..05e4d9d Binary files /dev/null and b/MockUps/Canva/Version 1/2.png differ diff --git a/MockUps/Canva/Version 1/3.png b/MockUps/Canva/Version 1/3.png new file mode 100644 index 0000000..15ac0f7 Binary files /dev/null and b/MockUps/Canva/Version 1/3.png differ diff --git a/MockUps/Canva/Version 1/4.png b/MockUps/Canva/Version 1/4.png new file mode 100644 index 0000000..f49d16c Binary files /dev/null and b/MockUps/Canva/Version 1/4.png differ diff --git a/MockUps/Canva/Version 2 (finally)/1_1.png b/MockUps/Canva/Version 2 (finally)/1_1.png new file mode 100644 index 0000000..bd8c614 Binary files /dev/null and b/MockUps/Canva/Version 2 (finally)/1_1.png differ diff --git a/MockUps/Canva/Version 2 (finally)/2_1.png b/MockUps/Canva/Version 2 (finally)/2_1.png new file mode 100644 index 0000000..d08f330 Binary files /dev/null and b/MockUps/Canva/Version 2 (finally)/2_1.png differ diff --git a/MockUps/Canva/Version 2 (finally)/3_1.png b/MockUps/Canva/Version 2 (finally)/3_1.png new file mode 100644 index 0000000..6fbe71f Binary files /dev/null and b/MockUps/Canva/Version 2 (finally)/3_1.png differ diff --git a/MockUps/Canva/Version 2 (finally)/4_1.png b/MockUps/Canva/Version 2 (finally)/4_1.png new file mode 100644 index 0000000..ba4961e Binary files /dev/null and b/MockUps/Canva/Version 2 (finally)/4_1.png differ diff --git a/MockUps/DrawIO/mock5.drawio b/MockUps/DrawIO/mock5.drawio new file mode 100644 index 0000000..78e1bec --- /dev/null +++ b/MockUps/DrawIO/mock5.drawio @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/MockUps/DrawIO/mock5.drawio.png b/MockUps/DrawIO/mock5.drawio.png new file mode 100644 index 0000000..63be606 Binary files /dev/null and b/MockUps/DrawIO/mock5.drawio.png differ diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..2f004de --- /dev/null +++ b/requirements.txt @@ -0,0 +1,12 @@ +certifi==2022.12.7 +charset-normalizer==3.1.0 +docutils==0.19 +idna==3.4 +Kivy==2.1.0 +Kivy-Garden==0.1.5 +kivymd==1.1.1 +Pillow==9.4.0 +Pygments==2.14.0 +requests==2.28.2 +urllib3==1.26.15 +watchdog \ No newline at end of file diff --git a/sources.md b/sources.md new file mode 100644 index 0000000..5e479b6 --- /dev/null +++ b/sources.md @@ -0,0 +1 @@ +- icons von: [Google fonts](https://fonts.google.com/icons?selected=Material+Symbols+Rounded:shopping_bag:FILL@0;wght@400;GRAD@0;opsz@48&icon.style=Rounded) diff --git a/src/main.py b/src/main.py new file mode 100644 index 0000000..f4e4113 --- /dev/null +++ b/src/main.py @@ -0,0 +1,130 @@ +from os import name +from kivy.app import App +from kivy.properties import ListProperty, StringProperty, BooleanProperty, ObjectProperty +from kivy.uix.boxlayout import BoxLayout +from kivy.uix.button import Label +from kivy.metrics import dp +from kivy.uix.screenmanager import Screen, ScreenManager +from kivy.core.window import Window + +from kivymd.app import MDApp +from kivymd.uix.button import MDFlatButton +from kivymd.uix.card.card import MDBoxLayout +from kivymd.uix.dialog import MDDialog +from kivymd.uix.menu import MDDropdownMenu +from kivymd.uix.list import OneLineAvatarIconListItem + +from setting_widgets.setting_fields import SettingTextField, SettingToggleField, SettingDropDownField + + +LANGUAGES = { "DE": "Deutsch", "EN": "English", "FR": "Francais" } + +Window.size = (400, 800) + +class ShoppingEntry(OneLineAvatarIconListItem): + def __init__(self, text, **kwargs): + super().__init__(**kwargs) + + self.text = text + self.is_checked = False + + def delete(self, shopping_entry): + self.parent.remove_widget(shopping_entry) + +class AddDialog(MDBoxLayout): + def __init__(self, **kwargs): + super().__init__(**kwargs) + +class ShoppingEntryScreen(Screen): + add_dialog = None + + def open_add_popup(self): + if self.add_dialog: + return + + # SPRACHE + buttons = [ + MDFlatButton(text='Abbrechen', on_release=self.close_add_popup), + MDFlatButton(text='Bestätigen', on_release=lambda args: self.add_shopping_entry("Text")) + ] + # SPRACHE + self.add_dialog = MDDialog( + title='Eintrag hinzufügen', + type='custom', + content_cls=AddDialog(), + buttons=buttons + ) + + self.add_dialog.open() + + # *args ist noetig, da weitere Parameter mitgegeben werden, die aber nicht genutzt werden + def close_add_popup(self, *args): + if not self.add_dialog: + return + + self.add_dialog.dismiss() + self.add_dialog = None + + + def add_shopping_entry(self, text): + self.ids['shopping_list'].add_widget(ShoppingEntry(text=text)) + self.close_add_popup() + + def delete_entry(self): + pass + + def navigate_to_settings(self): + self.manager.transition.direction = 'left' + self.manager.current = 'settings' + +class SettingsScreen(Screen): + #languages = ListProperty(["Deutsch", "English", "Francais"]) + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + menu_items = [ + { + "viewclass": "OneLineListItem", + "text": f"{LANGUAGES.get(language_key)}", + "height": dp(56), + "on_release": lambda x=f"{LANGUAGES.get(language_key)}": self.set_item(language_key), + } for language_key in LANGUAGES.keys() + ] + + self.menu = MDDropdownMenu( + caller=self.ids.language_drop_down, + items=menu_items, + position="center", + width_mult=4, + ) + + self.menu.bind() + + def navigate_to_shopping_list(self): + self.manager.transition.direction = 'right' + self.manager.current = 'shopping' + + def show_languages_menu(self): + self.menu.open() + + def set_item(self, language_key): + language = LANGUAGES.get(language_key) + self.ids.language_drop_down.set_item(language) + self.menu.dismiss() + +class ShoppingListApp(MDApp): + def build(self): + self.theme_cls.primary_palette = "Teal" + self.theme_cls.theme_style = "Light" + self.title = 'Shopping List App' + + sm = ScreenManager() + sm.add_widget(ShoppingEntryScreen(name='shopping')) + sm.add_widget(SettingsScreen(name='settings')) + + return sm + +if __name__ == "__main__": + app = ShoppingListApp() + app.run() diff --git a/src/res/add_circle.png b/src/res/add_circle.png new file mode 100644 index 0000000..41d799a Binary files /dev/null and b/src/res/add_circle.png differ diff --git a/src/res/arrow_back.png b/src/res/arrow_back.png new file mode 100644 index 0000000..ba638b3 Binary files /dev/null and b/src/res/arrow_back.png differ diff --git a/src/res/delete.png b/src/res/delete.png new file mode 100644 index 0000000..f4d2a2e Binary files /dev/null and b/src/res/delete.png differ diff --git a/src/res/expand_more.png b/src/res/expand_more.png new file mode 100644 index 0000000..8d1b445 Binary files /dev/null and b/src/res/expand_more.png differ diff --git a/src/res/filter_list.png b/src/res/filter_list.png new file mode 100644 index 0000000..45e3396 Binary files /dev/null and b/src/res/filter_list.png differ diff --git a/src/res/settings.png b/src/res/settings.png new file mode 100644 index 0000000..1150116 Binary files /dev/null and b/src/res/settings.png differ diff --git a/src/res/shopping_bag.png b/src/res/shopping_bag.png new file mode 100644 index 0000000..2abd192 Binary files /dev/null and b/src/res/shopping_bag.png differ diff --git a/src/setting_widgets/__init__.py b/src/setting_widgets/__init__.py new file mode 100644 index 0000000..689491e --- /dev/null +++ b/src/setting_widgets/__init__.py @@ -0,0 +1,3 @@ +from .setting_fields import SettingTextField +from .setting_fields import SettingToggleField +from .setting_fields import SettingDropDownField \ No newline at end of file diff --git a/src/setting_widgets/setting_fields.kv b/src/setting_widgets/setting_fields.kv new file mode 100644 index 0000000..da52b2e --- /dev/null +++ b/src/setting_widgets/setting_fields.kv @@ -0,0 +1,20 @@ +: + divider: None + _no_ripple_effect: True + + RightTextField: + id: setting_right_text_field + +: + divider: None + _no_ripple_effect: True + + RightToggleField: + id: setting_right_toggle_field + +: + divider: None + _no_ripple_effect: True + + RightDropDownField: + id: setting_right_dropdown_field \ No newline at end of file diff --git a/src/setting_widgets/setting_fields.py b/src/setting_widgets/setting_fields.py new file mode 100644 index 0000000..fb54ff0 --- /dev/null +++ b/src/setting_widgets/setting_fields.py @@ -0,0 +1,31 @@ +from kivymd.uix.dropdownitem import MDDropDownItem +from kivymd.uix.list import BaseListItem, OneLineRightIconListItem, IRightBodyTouch +from kivymd.uix.selectioncontrol.selectioncontrol import MDSwitch +from kivymd.uix.textfield import MDTextField +from kivy.lang import Builder + +Builder.load_file("setting_widgets\setting_fields.kv") + +# ===== TextField ===== + +class SettingTextField(OneLineRightIconListItem): + """DOCS""" + +class RightTextField(IRightBodyTouch, MDTextField): + """DOCS""" + +# ===== ToggleField ===== + +class SettingToggleField(OneLineRightIconListItem): + """DOCS""" + +class RightToggleField(IRightBodyTouch, MDSwitch): + """DOCS""" + +# ===== DropDownField ===== + +class SettingDropDownField(OneLineRightIconListItem): + """DOCS""" + +class RightDropDownField(IRightBodyTouch, MDDropDownItem): + """DOCS""" \ No newline at end of file diff --git a/src/shoppinglist.kv b/src/shoppinglist.kv new file mode 100644 index 0000000..bdfb289 --- /dev/null +++ b/src/shoppinglist.kv @@ -0,0 +1,113 @@ +: + id: shopping_entry + markup: True + + ImageLeftWidget: + MDCheckbox: + id: shopping_entry_check + # bind to property + + IconRightWidget: + icon: 'res/delete.png' + on_release: root.delete(shopping_entry) + +: + size_hint: 1, None + height: '40dp' + orientation: 'vertical' + spacing: '5dp' + + MDTextField: + id: shopping_entry_text + pos_hint: { 'center_y': 0.4 } + # SPRACHE + hint_text: 'Neuer Eintrag' + +: + MDBoxLayout: + orientation: 'vertical' + pos_hint: { 'center_x': 0.5, 'center_y': 0.5 } + + MDTopAppBar: + #SPRACHE + title: 'Shopping-List-App' + md_bg_color: app.theme_cls.primary_color + specific_text_color: '#000000' + right_action_items: [['res/settings.png', lambda x: root.navigate_to_settings()]] + + ScrollView: + size_hint: 0.85, 0.85 + pos_hint: { 'center_y': 1, 'center_x': 0.5 } + MDList: + id: shopping_list + + MDFloatingActionButton: + icon: 'plus' + elevation_normal: 5 + # bottom align is complicated + pos_hint: { 'top': (self.height/root.height)*1.5, 'right':0.95 } + on_release: root.open_add_popup() + +: + MDBoxLayout: + orientation: 'vertical' + + MDTopAppBar: + #SPRACHE + title: 'Shopping-List-App' + md_bg_color: app.theme_cls.primary_color + specific_text_color: '#000000' + left_action_items: [['res/arrow_back.png', lambda x: root.navigate_to_shopping_list()]] + + MDBoxLayout: + orientation: 'horizontal' + pos_hint: { 'center_x': 0.5 } + size_hint: (0.7, 0.25) + # SPRACHE + MDLabel: + text: 'Sprache' + MDDropDownItem: + id: language_drop_down + text: 'Deutsch' + on_release: root.show_languages_menu() + + MDBoxLayout: + orientation: 'horizontal' + pos_hint: { 'center_x': 0.5 } + size_hint: (0.7, 0.25) + # SPRACHE + SettingToggleField: + text: 'Theme' + + MDBoxLayout: + orientation: 'horizontal' + pos_hint: { 'center_x': 0.5 } + size_hint: (0.7, 0.25) + # SPRACHE + SettingTextField: + text: 'MQTT-Server' + + MDBoxLayout: + orientation: 'horizontal' + pos_hint: { 'center_x': 0.5 } + size_hint: (0.7, 0.25) + # SPRACHE + SettingTextField: + text: 'MQTT-Topic' + + MDBoxLayout: + orientation: 'horizontal' + pos_hint: { 'center_x': 0.5 } + size_hint: (0.7, 0.25) + # SPRACHE + SettingTextField: + text: 'MQTT-Benutzername' + + MDBoxLayout: + orientation: 'horizontal' + pos_hint: { 'center_x': 0.5 } + size_hint: (0.7, 0.25) + # SPRACHE + SettingTextField: + text: 'MQTT-Passwort' +