fix: dynamic height layout + bundle mysql locales to fix 'no localization for eng' error\n\n- Replace all fixed pixel heights in content_layout with size_hint_y proportions\n so the 6 rows fill available space on any screen (800p, 1080p, etc.)\n- Remove AnchorLayout wrapper that caused dead space above content\n- Bundle mysql/connector/locales in PyInstaller build (spec + build_windows.py)\n- Add mysql.connector.plugins hidden imports to spec and build script"

This commit is contained in:
2026-04-07 16:52:10 +03:00
parent b51e8bcc2a
commit 0f7e157406
4 changed files with 78 additions and 83 deletions

116
main.py
View File

@@ -3,7 +3,6 @@ from kivy.config import Config
Config.set('kivy', 'keyboard_mode', 'system')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
@@ -26,64 +25,43 @@ class DatabaseApp(App):
Window.fullscreen = 'auto'
# ------------------------------------------------------------------
# Responsive sizing: derive all dimensions from the actual screen height
# so the layout fits on any display (800p, 900p, 1080p, etc.)
# Responsive sizing: derive dimensions from the actual screen height
# ------------------------------------------------------------------
wh = Window.height # actual screen height after fullscreen
wh = Window.height
# Numpad occupies 29% of screen height (fixed proportion)
h_numpad_wr = int(wh * 0.29)
# Scale factor (1.0 at 1080p, down to 0.65 on small screens)
s = max(0.65, min(1.0, wh / 1080.0))
# Main layout outer padding and spacing (scaled)
s = max(0.65, min(1.0, wh / 1080.0))
pad_v = max(8, int(20 * s)) # top / bottom padding
pad_h = max(8, int(30 * s)) # left / right padding
m_spacing = max(4, int(10 * s)) # gap between content and numpad
# Padding / spacing (all scaled)
pad_v = max(8, int(20 * s))
pad_h = max(8, int(30 * s))
m_spacing = max(4, int(10 * s))
c_spacing = max(4, int(12 * s))
sp = max(6, int(10 * s))
upd_pad = max(4, int(8 * s))
upd_spc = max(4, int(8 * s))
np_pad_v = max(3, int(6 * s))
np_spc = max(3, int(6 * s))
# Space available for the 6 content rows (after numpad + padding + gap)
avail_total = wh - h_numpad_wr - 2 * pad_v - m_spacing
c_spacing = max(4, int(12 * s)) # gap between content rows
avail_items = avail_total - c_spacing * 5 # 6 rows → 5 gaps
# Distribute height proportionally among rows
# Reference weights: title=50, search=100, mode=38, buttons=65, update=187, status=40
_w = [50, 100, 38, 65, 187, 40]
_t = sum(_w)
def _h(weight):
return max(24, int(avail_items * weight / _t))
h_title = _h(_w[0])
h_search = _h(_w[1])
h_row = max(20, h_search // 2)
h_mode = _h(_w[2])
h_buttons = _h(_w[3])
h_update = _h(_w[4])
h_status = _h(_w[5])
# Update-frame internal heights
upd_pad = max(4, int(8 * s))
upd_spc = max(4, int(8 * s))
h_upd_title = max(20, int(h_update * 0.20))
h_upd_row = max(20, int(h_update * 0.24))
h_upd_inputs = h_upd_row * 2 + upd_spc
h_upd_btns = max(28, h_update - h_upd_title - h_upd_inputs - 2*upd_pad - 2*upd_spc)
# Numpad internal heights
np_pad_v = max(3, int(6 * s))
np_spc = max(3, int(6 * s))
h_enter_btn = max(34, int(h_numpad_wr * 0.24))
h_numpad_gr = h_numpad_wr - h_enter_btn - 2 * np_pad_v - np_spc
# Numpad (fixed height at bottom 29 % of screen)
h_numpad_wr = int(wh * 0.29)
h_enter_btn = max(34, int(h_numpad_wr * 0.24))
h_numpad_gr = h_numpad_wr - h_enter_btn - 2 * np_pad_v - np_spc
# Font sizes (scaled)
f_title = max(14, int(26 * s))
f_normal = max(11, int(18 * s))
f_btn = max(12, int(20 * s))
f_numpad = max(15, int(26 * s))
f_enter = max(14, int(24 * s))
f_mode = max(10, int(16 * s))
f_override = max(10, int(14 * s))
f_status = max(12, int(20 * s))
sp = max(6, int(10 * s)) # generic widget spacing
f_title = max(14, int(26 * s))
f_normal = max(11, int(18 * s))
f_btn = max(12, int(20 * s))
f_numpad = max(15, int(26 * s))
f_enter = max(14, int(24 * s))
f_mode = max(10, int(16 * s))
f_override = max(10, int(14 * s))
f_status = max(12, int(20 * s))
# Proportional size_hint_y weights for the 6 content rows
# title | search | mode | buttons | update-frame | status
_w = [50, 100, 38, 65, 187, 40]
_t = sum(_w)
# ------------------------------------------------------------------
# Build UI
@@ -98,12 +76,11 @@ class DatabaseApp(App):
pos_hint={'x': 0, 'y': 0}
)
# --- Content container (fills remaining space above numpad) ---
content_layout = BoxLayout(orientation='vertical', spacing=c_spacing, size_hint_y=None)
content_layout.bind(minimum_height=content_layout.setter('height'))
# --- Content container: size_hint_y=1 so it fills all space above numpad ---
content_layout = BoxLayout(orientation='vertical', spacing=c_spacing, size_hint_y=1)
# Title row: title + Exit button
title_row = BoxLayout(orientation='horizontal', size_hint_y=None, height=h_title, spacing=sp)
title_row = BoxLayout(orientation='horizontal', size_hint_y=_w[0]/_t, spacing=sp)
title = Label(text='Database Search & Update', font_size=f_title, bold=True)
title_row.add_widget(title)
exit_btn = Button(
@@ -121,8 +98,8 @@ class DatabaseApp(App):
# Search section (ID + Mass)
search_layout = GridLayout(
cols=2, size_hint_y=None, height=h_search,
spacing=sp, row_force_default=True, row_default_height=h_row
cols=2, size_hint_y=_w[1]/_t,
spacing=sp
)
search_layout.add_widget(Label(text='ID:', size_hint_x=0.25, font_size=f_normal, bold=True))
self.id_input = TextInput(
@@ -145,7 +122,7 @@ class DatabaseApp(App):
# Mode indicator row
self.manual_override = None
mode_row = BoxLayout(orientation='horizontal', size_hint_y=None, height=h_mode, spacing=sp)
mode_row = BoxLayout(orientation='horizontal', size_hint_y=_w[2]/_t, spacing=sp)
self.mode_label = Label(
text='Article type detected: PRODUCT',
size_hint_x=0.75, font_size=f_mode, bold=True, color=(0.4, 0.8, 1, 1)
@@ -160,7 +137,7 @@ class DatabaseApp(App):
content_layout.add_widget(mode_row)
# Action buttons (Add/Update, Reset, Settings)
button_layout = GridLayout(cols=3, size_hint_y=None, height=h_buttons, spacing=sp)
button_layout = GridLayout(cols=3, size_hint_y=_w[3]/_t, spacing=sp)
add_update_btn = Button(text='Add/Update', font_size=f_btn, bold=True)
add_update_btn.bind(on_press=self.show_update_frame)
button_layout.add_widget(add_update_btn)
@@ -175,16 +152,15 @@ class DatabaseApp(App):
# Update frame
self.update_frame = BoxLayout(
orientation='vertical', padding=upd_pad, spacing=upd_spc,
size_hint_y=None, height=h_update
size_hint_y=_w[4]/_t
)
self.update_frame_label = Label(
text='Update Values', size_hint_y=None, height=h_upd_title,
text='Update Values', size_hint_y=0.20,
font_size=f_btn, bold=True
)
self.update_frame.add_widget(self.update_frame_label)
update_inputs = GridLayout(
cols=2, spacing=sp, size_hint_y=None, height=h_upd_inputs,
row_force_default=True, row_default_height=h_upd_row
cols=2, spacing=sp, size_hint_y=0.52
)
update_inputs.add_widget(Label(text='ID:', size_hint_x=0.25, font_size=f_normal, bold=True))
self.update_id_input = TextInput(
@@ -198,7 +174,7 @@ class DatabaseApp(App):
self.update_mass_input.bind(focus=self.on_mass_input_focus)
update_inputs.add_widget(self.update_mass_input)
self.update_frame.add_widget(update_inputs)
update_buttons = GridLayout(cols=2, size_hint_y=None, height=h_upd_btns, spacing=sp)
update_buttons = GridLayout(cols=2, size_hint_y=0.28, spacing=sp)
self.update_confirm_btn = Button(text='Confirm Add/Update', disabled=True, font_size=f_btn, bold=True)
self.update_confirm_btn.bind(on_press=self.add_update_record)
update_buttons.add_widget(self.update_confirm_btn)
@@ -212,16 +188,12 @@ class DatabaseApp(App):
# Status label
self.status_label = Label(
text='Ready', size_hint_y=None, height=h_status,
text='Ready', size_hint_y=_w[5]/_t,
color=(0, 0.8, 0, 1), font_size=f_status, bold=True
)
content_layout.add_widget(self.status_label)
# Wrap content in an AnchorLayout that fills all space above the numpad
# so the content block is vertically centred regardless of screen size
content_anchor = AnchorLayout(anchor_x='center', anchor_y='center', size_hint_y=1)
content_anchor.add_widget(content_layout)
main_layout.add_widget(content_anchor)
main_layout.add_widget(content_layout)
# --- Numeric keypad ---
numpad_wrapper = BoxLayout(