Redesign app, prepare for 3.1.0 release

This commit is contained in:
2025-06-16 12:21:45 +02:00
parent d6a5e90b3c
commit 3a6cd6af3d
19 changed files with 599 additions and 562 deletions

View File

@@ -1,126 +1,123 @@
<ProgramScreen>:
name: "program"
on_enter: self.config_loader = root.load_config()
md_bg_color: app.theme_cls.primary_color
FloatLayout:
Label:
text: "Configuration"
font_size: 40
color: (0, 113, 0, 1)
bold: True
pos_hint: {"y":0.4}
GridLayout:
size_hint: 0.8, 0.5
pos_hint: {"x":0.1, "y":0.2}
MDGridLayout:
cols: 1
pos_hint: {'x': 0, 'y': 0.4}
MDLabel:
text: "Configuration"
font_size: 40
halign: 'center'
valign: 'center'
pos_hint: {'center_x': 0, 'center_y': 0}
bold: True
MDGridLayout:
cols: 1
pos_hint: {'x': 0, 'y': 0.33}
MDLabel:
text: "Change the configuration of the microcontroller"
font_size: 18
halign: 'center'
valign: 'center'
pos_hint: {'center_x': 0, 'center_y': 0}
italic: True
MDGridLayout:
cols: 1
pos_hint: {'x': 0, 'y': 0.25}
MDLabel:
id: status
text: "Loading..."
font_size: 17
halign: 'center'
bold: True
MDGridLayout:
size_hint: 0.9, 0.5
spacing: 10
pos_hint: {"x":0.05, "y":0.2}
cols: 4
Label:
text: "Sensor 1, a:"
TextInput:
MDTextField:
id: s1_a
multiline: False
input_filter: "float"
Label:
text: "Sensor 1, b:"
TextInput:
hint_text: 'Sensor 1 a'
on_text: root.validate_float(self)
MDTextField:
id: s1_b
multiline: False
input_filter: "float"
Label:
text: "Sensor 1, c:"
TextInput:
hint_text: 'Sensor 1 b'
on_text: root.validate_float(self)
MDTextField:
id: s1_c
multiline: False
input_filter: "float"
Label:
text: "Sensor 1, Temp:"
TextInput:
hint_text: 'Sensor 1 c'
on_text: root.validate_float(self)
MDTextField:
id: s1_t
multiline: False
input_filter: "float"
Label:
text: "Sensor 2, a:"
TextInput:
hint_text: 'Sensor 1 Temperature'
on_text: root.validate_float(self)
MDTextField:
id: s2_a
multiline: False
input_filter: "float"
Label:
text: "Sensor 2, b:"
TextInput:
hint_text: 'Sensor 2 a'
on_text: root.validate_float(self)
MDTextField:
id: s2_b
multiline: False
input_filter: "float"
Label:
text: "Sensor 2, c:"
TextInput:
hint_text: 'Sensor 2 b'
on_text: root.validate_float(self)
MDTextField:
id: s2_c
multiline: False
input_filter: "float"
Label:
text: "Sensor 2, Temp:"
TextInput:
hint_text: 'Sensor 2 c'
on_text: root.validate_float(self)
MDTextField:
id: s2_t
multiline: False
input_filter: "float"
Label:
text: "Sensor 3, a:"
TextInput:
hint_text: 'Sensor 2 Temperature'
on_text: root.validate_float(self)
MDTextField:
id: s3_a
multiline: False
input_filter: "float"
Label:
text: "Sensor 3, b:"
TextInput:
hint_text: 'Sensor 3 a'
on_text: root.validate_float(self)
MDTextField:
id: s3_b
multiline: False
input_filter: "float"
Label:
text: "Sensor 3, c:"
TextInput:
hint_text: 'Sensor 3 b'
on_text: root.validate_float(self)
MDTextField:
id: s3_c
multiline: False
input_filter: "float"
Label:
text: "Sensor 3, Temp:"
TextInput:
hint_text: 'Sensor 3 c'
on_text: root.validate_float(self)
MDTextField:
id: s3_t
multiline: False
input_filter: "float"
Label:
text: "Sensor 4, a:"
TextInput:
hint_text: 'Sensor 3 Temperature'
on_text: root.validate_float(self)
MDTextField:
id: s4_a
multiline: False
input_filter: "float"
Label:
text: "Sensor 4, b:"
TextInput:
hint_text: 'Sensor 4 a'
on_text: root.validate_float(self)
MDTextField:
id: s4_b
multiline: False
input_filter: "float"
Label:
text: "Sensor 4, c:"
TextInput:
hint_text: 'Sensor 4 b'
on_text: root.validate_float(self)
MDTextField:
id: s4_c
multiline: False
input_filter: "float"
Label:
text: "Sensor 4, Temp:"
TextInput:
hint_text: 'Sensor 4 c'
on_text: root.validate_float(self)
MDTextField:
id: s4_t
multiline: False
input_filter: "float"
Button:
hint_text: 'Sensor 4 Temperature'
on_text: root.validate_float(self)
MDFillRoundFlatButton:
size_hint: 0.1, 0.07
text: "Back"
size_hint: 0.1, 0.1
pos_hint: {"x":0.1, "y":0.1}
background_color: (255, 0, 0, 0.6)
on_release:
app.root.current = "main"
root.manager.transition.direction = "up"
Button:
MDFillRoundFlatButton:
size_hint: 0.15, 0.09
text: "Save"
size_hint: 0.2, 0.1
pos_hint: {"x":0.6, "y":0.1}
background_color: (255, 0, 0, 0.6)
on_release:
root.save()

View File

@@ -3,7 +3,8 @@ from kivymd.uix.screen import MDScreen
from kivy.lang import Builder
from lib.decoder import Decoder
from lib.instructions import Instructions
from gui.popups.popups import SingleRowPopup, TwoActionPopup, empty_func
from kivymd.uix.button import MDFlatButton
from kivymd.uix.dialog import MDDialog
from lib.com import ComSuperClass
from kivy.clock import Clock
@@ -18,13 +19,60 @@ class ProgramScreen(MDScreen):
self._com = com
self._instructions = Instructions(com)
self._decoder = Decoder()
self.connection_error_dialog = MDDialog(
title="Connection",
text="Failed to connect. Do you wish to retry?",
buttons=[
MDFlatButton(
text="Cancel",
on_release=lambda dt: self.connection_error_dialog.dismiss(),
),
MDFlatButton(text="Retry", on_release=lambda dt: self._load()),
],
)
self.missing_fields_error_dialog = MDDialog(
title="Save",
text="Some fields are missing entries. Please fill them out and try again",
buttons=[
MDFlatButton(
text="Ok",
on_release=lambda dt: self.missing_fields_error_dialog.dismiss(),
),
],
)
self.save_error_dialog = MDDialog(
title="Save",
text="Failed to save data. Please try again",
buttons=[
MDFlatButton(
text="Ok",
on_release=lambda dt: self.save_error_dialog.dismiss(),
),
],
)
self.save_success_dialog = MDDialog(
title="Save",
text="Data saved successfully!",
buttons=[
MDFlatButton(
text="Ok",
on_release=lambda dt: self.save_success_dialog.dismiss(),
),
],
)
super().__init__(**kw)
def load_config(self):
Clock.schedule_once(self._load)
Clock.schedule_once(lambda dt: self._load())
# Load the current configuration from the micro-controller
def _load(self, dt: float):
def _load(self):
self.ids.status.text = "Loading..."
# Hook to the microcontroller's data stream (i.e. sync up with it)
if self._instructions.hook("RD", ["\n", "R", "D", "\n"]):
config: List[List[str]] = []
@@ -37,13 +85,7 @@ class ProgramScreen(MDScreen):
received = self._com.receive(28)
except:
# Open error popup
TwoActionPopup().open(
"Failed to connect to micro-controller, retry?",
"Cancel",
empty_func,
"Retry",
lambda: self._load(0),
)
self.connection_error_dialog.open()
return
# Create a list of strings to store the config for the sensor
@@ -58,16 +100,11 @@ class ProgramScreen(MDScreen):
# Add it to the config
config.append(config_sensor_i)
self.ids.status.text = ""
self._set_ui(config)
else:
TwoActionPopup().open(
"Failed to connect to micro-controller, retry?",
"Cancel",
empty_func,
"Retry",
lambda: self._load(0),
)
self.connection_error_dialog.open()
# Set the elements of the UI to the values of the config
def _set_ui(self, config: List[List[str]]):
@@ -96,16 +133,37 @@ class ProgramScreen(MDScreen):
# Transmit the changed data to the micro-controller to reconfigure it
def save(self):
self.ids.status.text = "Saving..."
data = self._read_ui()
if data == None:
SingleRowPopup().open("Some fields are missing values!")
self.missing_fields_error_dialog()
else:
try:
self._instructions.change_config(data)
except Exception as e:
SingleRowPopup().open("Could not save data!")
self.save_error_dialog.open()
return
SingleRowPopup().open("Data saved successfully")
self.save_success_dialog.open()
self.ids.status.text = "Saved!"
Clock.schedule_once(self.reset_update, 5)
def reset_update(self, dt):
self.ids.status.text = ""
def validate_float(self, instance):
text = instance.text
# Allow only digits and one dot
if text.count(".") > 1 or any(c not in "0123456789." for c in text):
# Remove invalid characters
clean_text = "".join(c for c in text if c in "0123456789.")
# Remove extra dots
if clean_text.count(".") > 1:
first_dot = clean_text.find(".")
clean_text = clean_text[: first_dot + 1] + clean_text[
first_dot + 1 :
].replace(".", "")
instance.text = clean_text
# Load the design file for this screen (.kv files)