mirror of
https://github.com/OMGeeky/Kivy-Shopping-List.git
synced 2025-12-26 16:07:41 +01:00
Fix theme bug by downgarding to KivyMD 1.0.2, refactor and remove comments, remove hardcoded colors, fix typo in app name
This commit is contained in:
@@ -4,9 +4,9 @@ docutils==0.19
|
||||
idna==3.4
|
||||
Kivy==2.1.0
|
||||
Kivy-Garden==0.1.5
|
||||
kivymd==1.1.1
|
||||
kivymd==1.0.2
|
||||
Pillow==9.4.0
|
||||
Pygments==2.14.0
|
||||
requests==2.28.2
|
||||
urllib3==1.26.15
|
||||
paho-mqtt==1.6.1
|
||||
paho-mqtt==1.6.1
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[app]
|
||||
|
||||
title = Shooping List App
|
||||
title = Shopping List App
|
||||
package.name = shoppingapp
|
||||
package.domain = gsog.shopping
|
||||
|
||||
|
||||
119
src/main.py
119
src/main.py
@@ -8,7 +8,12 @@ from language import TranslationProvider, LANGUAGES
|
||||
from mqtt import MqttClient
|
||||
|
||||
import kivy.utils
|
||||
from kivy.properties import StringProperty, ObjectProperty, BooleanProperty, ListProperty
|
||||
from kivy.properties import (
|
||||
StringProperty,
|
||||
ObjectProperty,
|
||||
BooleanProperty,
|
||||
ListProperty,
|
||||
)
|
||||
from kivy.metrics import dp
|
||||
from kivy.uix.screenmanager import Screen, ScreenManager
|
||||
from kivy.core.window import Window
|
||||
@@ -44,15 +49,13 @@ class ShoppingEntry(OneLineAvatarIconListItem):
|
||||
if self.edit_dialog:
|
||||
return
|
||||
|
||||
# SPRACHE
|
||||
buttons = [
|
||||
MDFlatButton(
|
||||
text=self.get_translated("cancel"),
|
||||
on_release=self.close_edit_popup
|
||||
text=self.get_translated("cancel"), on_release=self.close_edit_popup
|
||||
),
|
||||
MDFlatButton(
|
||||
text=self.get_translated("confirm"),
|
||||
on_release=lambda args: self.save_changes(args)
|
||||
on_release=lambda args: self.save_changes(args),
|
||||
),
|
||||
]
|
||||
|
||||
@@ -109,22 +112,21 @@ class ShoppingEntryScreen(Screen):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
self.from_mqtt = False
|
||||
self.update_from_file()
|
||||
|
||||
|
||||
def update_from_file(self):
|
||||
try:
|
||||
entries = read_entries_from_files()
|
||||
except OSError:
|
||||
return
|
||||
|
||||
self.set_entries(entries['entries'])
|
||||
|
||||
self.set_entries(entries["entries"])
|
||||
|
||||
def update_from_mqtt(self, msg_dict):
|
||||
self.from_mqtt = True
|
||||
self.entries = msg_dict['entries']
|
||||
|
||||
self.entries = msg_dict["entries"]
|
||||
|
||||
def on_bestaetigen(self, *_):
|
||||
if self.add_dialog is None:
|
||||
@@ -180,36 +182,35 @@ class ShoppingEntryScreen(Screen):
|
||||
write_entries_to_files(entries_dict)
|
||||
except OSError:
|
||||
return
|
||||
|
||||
|
||||
# dont push to mqtt if coming from mqtt
|
||||
if not self.from_mqtt:
|
||||
app.mqtt.publish(entries_dict)
|
||||
else:
|
||||
self.from_mqtt = False
|
||||
|
||||
|
||||
@mainthread
|
||||
def on_entries(self, *_):
|
||||
print("on_entries called")
|
||||
self.ids["shopping_list"].clear_widgets()
|
||||
for entry in self.entries:
|
||||
shopping_entry = ShoppingEntry(text=entry['text'])
|
||||
shopping_entry.is_checked = entry['is_checked'] # type: ignore
|
||||
shopping_entry = ShoppingEntry(text=entry["text"])
|
||||
shopping_entry.is_checked = entry["is_checked"] # type: ignore
|
||||
self.ids["shopping_list"].add_widget(shopping_entry)
|
||||
|
||||
self.export_entries()
|
||||
self.export_entries()
|
||||
|
||||
def get_entires(self):
|
||||
entries = []
|
||||
for entry in self.ids.shopping_list.children:
|
||||
entry_dict = {"is_checked": entry.is_checked, "text": entry.text}
|
||||
entries.append(entry_dict)
|
||||
|
||||
entries.sort(key=lambda entry: (entry['is_checked'], entry['text']))
|
||||
|
||||
entries.sort(key=lambda entry: (entry["is_checked"], entry["text"]))
|
||||
return entries
|
||||
|
||||
def set_entries(self, entries: List[Dict[str, Union[str,bool]]]):
|
||||
|
||||
def set_entries(self, entries: List[Dict[str, Union[str, bool]]]):
|
||||
self.entries = entries
|
||||
|
||||
|
||||
def navigate_to_settings(self):
|
||||
self.export_entries()
|
||||
@@ -227,8 +228,8 @@ class SettingsScreen(Screen):
|
||||
self.initialized = False
|
||||
|
||||
# remember previous mqtt-settings to check if they changed
|
||||
self.previous_mqtt_server = app.settings.mqtt_server
|
||||
self.previous_mqtt_topic = app.settings.mqtt_topic
|
||||
self.previous_mqtt_server = app.settings.mqtt_server
|
||||
self.previous_mqtt_topic = app.settings.mqtt_topic
|
||||
self.previous_mqtt_password = app.settings.mqtt_password
|
||||
self.previous_mqtt_username = app.settings.mqtt_username
|
||||
|
||||
@@ -251,21 +252,25 @@ class SettingsScreen(Screen):
|
||||
|
||||
self.menu.bind()
|
||||
# update the current selected from settings
|
||||
self.set_item(app.settings.language)
|
||||
self.set_item(app.settings.language)
|
||||
|
||||
self.initialized = True
|
||||
|
||||
def apply_mqtt_settings(self):
|
||||
if self.previous_mqtt_server != app.settings.mqtt_server or \
|
||||
self.previous_mqtt_topic != app.settings.mqtt_topic or \
|
||||
self.previous_mqtt_password != app.settings.mqtt_password or \
|
||||
self.previous_mqtt_username != app.settings.mqtt_username:
|
||||
if (
|
||||
self.previous_mqtt_server != app.settings.mqtt_server
|
||||
or self.previous_mqtt_topic != app.settings.mqtt_topic
|
||||
or self.previous_mqtt_password != app.settings.mqtt_password
|
||||
or self.previous_mqtt_username != app.settings.mqtt_username
|
||||
):
|
||||
app.mqtt.disconnect()
|
||||
app.mqtt.set_target(app.settings.mqtt_server,
|
||||
app.settings.mqtt_topic,
|
||||
1883,
|
||||
app.settings.mqtt_username,
|
||||
app.settings.mqtt_password)
|
||||
app.mqtt.set_target(
|
||||
app.settings.mqtt_server,
|
||||
app.settings.mqtt_topic,
|
||||
1883,
|
||||
app.settings.mqtt_username,
|
||||
app.settings.mqtt_password,
|
||||
)
|
||||
app.mqtt.connect()
|
||||
|
||||
def navigate_to_shopping_list(self):
|
||||
@@ -285,7 +290,7 @@ class SettingsScreen(Screen):
|
||||
def get_translated(self, key) -> str:
|
||||
language = app.settings.language
|
||||
return TranslationProvider.get_translated(key, language)
|
||||
|
||||
|
||||
def update_language(self):
|
||||
if not self.initialized:
|
||||
return
|
||||
@@ -298,8 +303,7 @@ class SettingsScreen(Screen):
|
||||
if not self.initialized:
|
||||
return
|
||||
self.update_settings()
|
||||
toast(self.get_translated("change_setting_restart_alert"))
|
||||
# app.update_theme() # TODO (1): eventuell ohne restart
|
||||
app.update_theme()
|
||||
|
||||
def update_settings(self):
|
||||
if not self.initialized:
|
||||
@@ -316,9 +320,10 @@ class SettingsScreen(Screen):
|
||||
|
||||
class ShoppingListApp(MDApp):
|
||||
settings = ObjectProperty(AppSettings(), rebind=True)
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.mqtt: MqttClient = None # type: ignore
|
||||
self.mqtt: MqttClient = None # type: ignore
|
||||
|
||||
def build(self):
|
||||
self.title = "Shopping List App"
|
||||
@@ -326,19 +331,18 @@ class ShoppingListApp(MDApp):
|
||||
print(self.settings)
|
||||
print(self.user_data_dir)
|
||||
print(self.directory)
|
||||
|
||||
|
||||
if kivy.utils.platform in ["android", "ios"]:
|
||||
print('android or ios')
|
||||
src_path = Path(self.user_data_dir, 'app')
|
||||
print("android or ios")
|
||||
src_path = Path(self.user_data_dir, "app")
|
||||
else:
|
||||
print('not android or ios')
|
||||
print("not android or ios")
|
||||
src_path = Path(self.directory)
|
||||
|
||||
|
||||
print(src_path)
|
||||
TranslationProvider.src_dir = src_path
|
||||
|
||||
|
||||
# TODO @Tom Theme anpassen
|
||||
self.theme_cls.primary_palette = "Gray"
|
||||
self.update_theme()
|
||||
|
||||
sm = ScreenManager()
|
||||
@@ -346,21 +350,25 @@ class ShoppingListApp(MDApp):
|
||||
sm.add_widget(shoppingEntryScreen)
|
||||
sm.add_widget(SettingsScreen(name="settings"))
|
||||
|
||||
self.mqtt = MqttClient(broker=self.settings.mqtt_server,
|
||||
port=1883,
|
||||
topic=self.settings.mqtt_topic,
|
||||
client_id=None,
|
||||
subscribe_callback=lambda msg_dict, _:shoppingEntryScreen.update_from_mqtt(msg_dict),
|
||||
username=self.settings.mqtt_username,
|
||||
password=self.settings.mqtt_password)
|
||||
self.mqtt = MqttClient(
|
||||
broker=self.settings.mqtt_server,
|
||||
port=1883,
|
||||
topic=self.settings.mqtt_topic,
|
||||
client_id=None,
|
||||
subscribe_callback=lambda msg_dict, _: shoppingEntryScreen.update_from_mqtt(
|
||||
msg_dict
|
||||
),
|
||||
username=self.settings.mqtt_username,
|
||||
password=self.settings.mqtt_password,
|
||||
)
|
||||
|
||||
try:
|
||||
print('getaddrinfo google.com')
|
||||
print(socket.getaddrinfo('google.com', 80))
|
||||
print("getaddrinfo google.com")
|
||||
print(socket.getaddrinfo("google.com", 80))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
try:
|
||||
print(f'getaddrinfo {self.settings.mqtt_server}')
|
||||
print(f"getaddrinfo {self.settings.mqtt_server}")
|
||||
print(socket.getaddrinfo(self.settings.mqtt_server, 1883))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
@@ -374,6 +382,9 @@ class ShoppingListApp(MDApp):
|
||||
return sm
|
||||
|
||||
def update_theme(self):
|
||||
self.theme_cls.primary_palette = "Gray"
|
||||
self.theme_cls.accent_palette = "BlueGray"
|
||||
|
||||
if self.settings.dark_theme:
|
||||
self.theme_cls.theme_style = "Dark"
|
||||
else:
|
||||
|
||||
52
src/mqtt.py
52
src/mqtt.py
@@ -13,14 +13,16 @@ class MqttSendError(ConnectionError):
|
||||
def __init__(self, *args: object) -> None:
|
||||
super().__init__("Error sending message to MQTT broker", *args)
|
||||
|
||||
def _get_broker_and_port(broker: str, port: int):
|
||||
print('getting broker and port', broker, port)
|
||||
|
||||
if ':' in broker:
|
||||
broker, port = broker.split(':') # type: ignore
|
||||
port = int(port)
|
||||
|
||||
return broker, port
|
||||
def _get_broker_and_port(broker: str, port: int):
|
||||
print("getting broker and port", broker, port)
|
||||
|
||||
if ":" in broker:
|
||||
broker, port = broker.split(":") # type: ignore
|
||||
port = int(port)
|
||||
|
||||
return broker, port
|
||||
|
||||
|
||||
class MqttClient:
|
||||
def __init__(
|
||||
@@ -29,7 +31,7 @@ class MqttClient:
|
||||
port: int,
|
||||
topic: str,
|
||||
subscribe_callback: Callable[[dict, str], None],
|
||||
username: Optional[str] = None,
|
||||
username: Optional[str] = None,
|
||||
password: Optional[str] = None,
|
||||
client_id: Optional[str] = None,
|
||||
) -> None:
|
||||
@@ -39,7 +41,14 @@ class MqttClient:
|
||||
self.__client: Optional[mqtt_client.Client] = None
|
||||
self.__subscribe_callback = subscribe_callback
|
||||
|
||||
def set_target(self, broker: str, topic:str, port: int, username: Optional[str] = None, password: Optional[str] = None):
|
||||
def set_target(
|
||||
self,
|
||||
broker: str,
|
||||
topic: str,
|
||||
port: int,
|
||||
username: Optional[str] = None,
|
||||
password: Optional[str] = None,
|
||||
):
|
||||
broker, port = _get_broker_and_port(broker, port)
|
||||
self.__broker = broker
|
||||
self.__port = port
|
||||
@@ -48,7 +57,6 @@ class MqttClient:
|
||||
self.__password = password
|
||||
|
||||
def parse_callback(self, msg, callback: Optional[Callable]):
|
||||
|
||||
if callback is None:
|
||||
callback = self.__subscribe_callback
|
||||
x = json.loads(msg.payload.decode())
|
||||
@@ -61,7 +69,9 @@ class MqttClient:
|
||||
else:
|
||||
print("Failed to connect, return code", rc)
|
||||
|
||||
def publish(self, msg: dict, topic: Optional[str] = None, retain: bool = True) -> None:
|
||||
def publish(
|
||||
self, msg: dict, topic: Optional[str] = None, retain: bool = True
|
||||
) -> None:
|
||||
if self.__client is None:
|
||||
self.connect()
|
||||
if self.__client is None:
|
||||
@@ -84,7 +94,9 @@ class MqttClient:
|
||||
raise MqttConnectionError()
|
||||
|
||||
self.__client.subscribe(self.__topic)
|
||||
self.__client.on_message = lambda _client, _userdata, msg: self.parse_callback(msg, callback)
|
||||
self.__client.on_message = lambda _client, _userdata, msg: self.parse_callback(
|
||||
msg, callback
|
||||
)
|
||||
|
||||
def connect(self) -> None:
|
||||
self.__client = mqtt_client.Client(self.__client_id)
|
||||
@@ -94,8 +106,8 @@ class MqttClient:
|
||||
|
||||
self.__client.on_connect = self.on_connect
|
||||
print("Connecting to MQTT broker...")
|
||||
print('broker:',self.__broker, 'port:', self.__port)
|
||||
self.__client.connect(host=self.__broker, port= self.__port)
|
||||
print("broker:", self.__broker, "port:", self.__port)
|
||||
self.__client.connect(host=self.__broker, port=self.__port)
|
||||
self.__client.loop_start()
|
||||
|
||||
def disconnect(self) -> None:
|
||||
@@ -109,7 +121,6 @@ class MqttClient:
|
||||
|
||||
|
||||
def sample2():
|
||||
|
||||
broker = "broker.hivemq.com"
|
||||
topic = "/gsog/shopping"
|
||||
username = None
|
||||
@@ -118,7 +129,14 @@ def sample2():
|
||||
def on_message(msg: dict, topic: str) -> None:
|
||||
print(f"Received `{msg}` from `{topic}` topic")
|
||||
|
||||
client = MqttClient(broker=broker, port=1883,topic=topic,subscribe_callback= on_message,username= username,password= password)
|
||||
client = MqttClient(
|
||||
broker=broker,
|
||||
port=1883,
|
||||
topic=topic,
|
||||
subscribe_callback=on_message,
|
||||
username=username,
|
||||
password=password,
|
||||
)
|
||||
client.connect()
|
||||
count = 0
|
||||
while True:
|
||||
@@ -138,7 +156,7 @@ def sample2():
|
||||
|
||||
print("Now subscribing...")
|
||||
client.subscribe()
|
||||
|
||||
|
||||
input("Press enter to quit...\n")
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
ImageLeftWidget:
|
||||
MDCheckbox:
|
||||
id: shopping_entry_check
|
||||
# bind to property
|
||||
active: root.is_checked
|
||||
on_active: root.is_checked = self.active
|
||||
|
||||
@@ -23,11 +22,8 @@
|
||||
MDTextField:
|
||||
id: shopping_entry_text
|
||||
pos_hint: { 'center_y': 0.4 }
|
||||
# SPRACHE
|
||||
hint_text: root.get_translated('new_entry')
|
||||
text: root.text
|
||||
text_color_normal: "#000000"
|
||||
text_color_focus: "#000000"
|
||||
mode: "round"
|
||||
|
||||
<ShoppingEntryScreen>:
|
||||
@@ -38,7 +34,6 @@
|
||||
MDTopAppBar:
|
||||
title: root.get_translated('app_title')
|
||||
md_bg_color: app.theme_cls.primary_color
|
||||
specific_text_color: '#1C2120'
|
||||
right_action_items: [['res/settings.png', lambda x: root.navigate_to_settings()]]
|
||||
|
||||
ScrollView:
|
||||
@@ -94,11 +89,8 @@
|
||||
text: root.get_translated('mqtt-server')
|
||||
MDTextField:
|
||||
id: mqtt_server_text_field
|
||||
# SPRACHE?
|
||||
hint_text: 'mqtt.server.de'
|
||||
mode: "round"
|
||||
text_color_normal: "#000000"
|
||||
text_color_focus: "#000000"
|
||||
text: app.settings.mqtt_server
|
||||
on_text: root.update_settings()
|
||||
|
||||
@@ -106,11 +98,8 @@
|
||||
text: root.get_translated('mqtt-topic')
|
||||
MDTextField:
|
||||
id: mqtt_topic_text_field
|
||||
# SPRACHE?
|
||||
hint_text: 'topic'
|
||||
mode: "round"
|
||||
text_color_normal: "#000000"
|
||||
text_color_focus: "#000000"
|
||||
text: app.settings.mqtt_topic
|
||||
on_text: root.update_settings()
|
||||
|
||||
@@ -118,11 +107,8 @@
|
||||
text: root.get_translated('mqtt-username')
|
||||
MDTextField:
|
||||
id: mqtt_username_text_field
|
||||
# SPRACHE?
|
||||
hint_text: 'username'
|
||||
mode: "round"
|
||||
text_color_normal: "#000000"
|
||||
text_color_focus: "#000000"
|
||||
text: app.settings.mqtt_username
|
||||
on_text: root.update_settings()
|
||||
|
||||
@@ -132,7 +118,5 @@
|
||||
id: mqtt_password_text_field
|
||||
password: True
|
||||
mode: "round"
|
||||
text_color_normal: "#000000"
|
||||
text_color_focus: "#000000"
|
||||
text: app.settings.mqtt_password
|
||||
on_text: root.update_settings()
|
||||
|
||||
Reference in New Issue
Block a user