Style Buttons, re-layout Login

This commit is contained in:
Yuri Becker
2025-03-13 17:23:36 +01:00
parent 343e15c873
commit 7099102e13
21 changed files with 278 additions and 251 deletions

17
.idea/QtSettings.xml generated Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="QtSettings">
<option name="mySettingsPerProfile">
<map>
<entry key="">
<value>
<PerProfileState>
<option name="myCustomQmlPath" value="/opt/homebrew/share/qt/qml" />
<option name="myCustomQtBinPath" value="/opt/homebrew/bin" />
</PerProfileState>
</value>
</entry>
</map>
</option>
</component>
</project>

17
.idea/qmlSettings.xml generated Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="QmlSettings">
<option name="mySettingsPerProfile">
<map>
<entry key="">
<value>
<PerProfileState>
<option name="myLSPEnabled" value="true" />
<option name="myQmlFormatEnabled" value="true" />
</PerProfileState>
</value>
</entry>
</map>
</option>
</component>
</project>

View File

@@ -0,0 +1,17 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Compile pyqcrm.qrc" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value=".venv/bin/pyside6-rcc -o rc_pyqcrm.py pyqcrm.qrc" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value=".venv/bin/pyside6-rcc" />
<option name="SCRIPT_OPTIONS" value="-o rc_qml.py qml.qrc" />
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
<option name="INTERPRETER_PATH" value="/bin/zsh" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="EXECUTE_IN_TERMINAL" value="false" />
<option name="EXECUTE_SCRIPT_FILE" value="false" />
<envs />
<method v="2" />
</configuration>
</component>

View File

@@ -0,0 +1,17 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Compile qml.qrc" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value=".venv/bin/pyside6-rcc -o rc_qml.py qml.qrc" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value=".venv/bin/pyside6-rcc" />
<option name="SCRIPT_OPTIONS" value="-o rc_qml.py qml.qrc" />
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
<option name="INTERPRETER_PATH" value="/bin/zsh" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="EXECUTE_IN_TERMINAL" value="false" />
<option name="EXECUTE_SCRIPT_FILE" value="false" />
<envs />
<method v="2" />
</configuration>
</component>

31
.idea/runConfigurations/main.xml generated Normal file
View File

@@ -0,0 +1,31 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="main" type="PythonConfigurationType" factoryName="Python" nameIsGenerated="true">
<module name="pyqcrm" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
<env name="QT_LOGGING_RULES" value="*.debug=true; qt.*.debug=false" />
<env name="QT_LOGGING_TO_CONSOLE" value="1" />
<env name="QT_QML_DEBUG" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="SDK_NAME" value="Python 3.12 (pyqcrm)" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="false" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/main.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2">
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Compile qml.qrc" run_configuration_type="ShConfigurationType" />
<option name="RunConfigurationTask" enabled="true" run_configuration_name="Compile pyqcrm.qrc" run_configuration_type="ShConfigurationType" />
</method>
</configuration>
</component>

45
.idea/watcherTasks.xml generated
View File

@@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectTasksOptions">
<TaskOptions isEnabled="true">
<option name="arguments" value="-o rc_qml.py qml.qrc" />
<option name="checkSyntaxErrors" value="true" />
<option name="description" />
<option name="exitCodeBehavior" value="ERROR" />
<option name="fileExtension" value="qml" />
<option name="immediateSync" value="true" />
<option name="name" value="qml.qrc" />
<option name="output" value="" />
<option name="outputFilters">
<array />
</option>
<option name="outputFromStdout" value="false" />
<option name="program" value="$PROJECT_DIR$/.venv/bin/pyside6-rcc" />
<option name="runOnExternalChanges" value="true" />
<option name="scopeName" value="Project Files" />
<option name="trackOnlyRoot" value="false" />
<option name="workingDir" value="$PROJECT_DIR$" />
<envs />
</TaskOptions>
<TaskOptions isEnabled="true">
<option name="arguments" value="-o rc_pyqcrm.py pyqcrm.qrc" />
<option name="checkSyntaxErrors" value="true" />
<option name="description" />
<option name="exitCodeBehavior" value="ERROR" />
<option name="fileExtension" value="qml" />
<option name="immediateSync" value="true" />
<option name="name" value="pyqcrm.qrc" />
<option name="output" value="" />
<option name="outputFilters">
<array />
</option>
<option name="outputFromStdout" value="false" />
<option name="program" value="$PROJECT_DIR$/.venv/bin/pyside6-rcc" />
<option name="runOnExternalChanges" value="true" />
<option name="scopeName" value="Project Files" />
<option name="trackOnlyRoot" value="false" />
<option name="workingDir" value="$PROJECT_DIR$" />
<envs />
</TaskOptions>
</component>
</project>

View File

@@ -3,226 +3,128 @@ import QtQuick
import QtQuick.Controls import QtQuick.Controls
import QtQuick.Dialogs import QtQuick.Dialogs
import QtQuick.Layouts import QtQuick.Layouts
import TeroStyle
Item {
Item
{
property string recpass: "" property string recpass: ""
anchors.fill: parent
ColumnLayout function dbConnectionFailed(msg) {
{ oschkar.notificationBox.informativeText = msg;
oschkar.notificationBox.text = "Verbindung zum Datenbankserver verloren";
oschkar.notificationBox.open();
}
function getEncryptionKey() {
recoveryPaswordDialog.open();
}
function loggedin() {
appLoader.source = "Dashboard.qml";
}
anchors.fill: parent anchors.fill: parent
FontLoader Component.onCompleted: {
{ loggedin_user.loginOkay.connect(loggedin);
id: helloStranger config.invalidEncryptionKey.connect(getEncryptionKey);
source: "qrc:/fonts/HelloStranger.otf" config.checkEncryptionKey();
loggedin_user.noDbConnection.connect(dbConnectionFailed);
benutzerName.forceActiveFocus();
} }
FontLoader ColumnLayout {
{ anchors.fill: parent
id: damarWulan spacing: Dimensions.m
source: "qrc:/fonts/Damarwulan.ttf" Label {
font: Typography.h1
text: qsTr("Login")
} }
Label {
FontLoader text: qsTr("Benutzername")
{
id: hussarPrint
source: "qrc:/fonts/HussarPrintA.otf"
} }
TextField {
FontLoader
{
id: reginaldScript
source: "qrc:/fonts/ReginaldScript.ttf"
}
Item
{
height: 65
}
Label
{
text: qsTr ("Login*****")
font.family: helloStranger.font.family
font.weight: helloStranger.font.weight
font.styleName: helloStranger.font.styleName
font.pixelSize: 89
font.bold: true
Layout.alignment: Qt.AlignHCenter
color: "yellow"
}
Item
{
height: 25
}
RowLayout
{
Layout.alignment: Qt.AlignHCenter
spacing: 15
Label
{
text: qsTr ("Benutzername")
minimumPixelSize: 20
Layout.preferredWidth: 150
horizontalAlignment: Text.AlignRight
font.family: damarWulan.font.family
font.weight: damarWulan.font.weight
font.styleName: damarWulan.font.styleName
font.pixelSize: 21
}
TextField
{
id: benutzerName id: benutzerName
placeholderText: qsTr ("Benutzernamen eingeben")
implicitWidth: 300
font: hussarPrint.font
focus: true focus: true
onAccepted:
{
if (benutzerName.text.trim() && passwort.text.trim())
loggedin_user.login(benutzerName.text.trim(), passwort.text)
else if(benutzerName.text.trim()) passwort.forceActiveFocus()
}
}
}
RowLayout
{
Layout.alignment: Qt.AlignHCenter
spacing: 15
Label
{
minimumPixelSize: 20
Layout.preferredWidth: 150
text: qsTr ("Passwort")
font.family: damarWulan.font.family
font.weight: damarWulan.font.weight
font.styleName: damarWulan.font.styleName
font.pixelSize: 21
horizontalAlignment: Text.AlignRight
}
TextField
{
id: passwort
placeholderText: qsTr ("Passwort eingeben")
implicitWidth: 300 implicitWidth: 300
font: hussarPrint.font placeholderText: qsTr("Benutzernamen eingeben")
onAccepted: {
if (benutzerName.text.trim() && passwort.text.trim())
loggedin_user.login(benutzerName.text.trim(), passwort.text);
else if (benutzerName.text.trim())
passwort.forceActiveFocus();
}
}
Label {
text: qsTr("Passwort")
}
TextField {
id: passwort
echoMode: TextInput.Password echoMode: TextInput.Password
onAccepted: implicitWidth: 300
{ placeholderText: qsTr("Passwort eingeben")
onAccepted: {
if (benutzerName.text.trim() && passwort.text.trim()) if (benutzerName.text.trim() && passwort.text.trim())
loggedin_user.login(benutzerName.text.trim(), passwort.text) loggedin_user.login(benutzerName.text.trim(), passwort.text);
else if(passwort.text.trim()) benutzerName.forceActiveFocus() else if (passwort.text.trim())
} benutzerName.forceActiveFocus();
} }
} }
Button {
text: qsTr("Primary")
RowLayout onClicked: {
{
Layout.preferredWidth: 465
Layout.alignment: Qt.AlignHCenter
Button
{
text: qsTr ("Feierabend für heute!")
Layout.alignment: Qt.AlignRight
font: reginaldScript.font
onClicked:
{
if (benutzerName.text.trim() && passwort.text.trim()) if (benutzerName.text.trim() && passwort.text.trim())
loggedin_user.login(benutzerName.text.trim(), passwort.text) loggedin_user.login(benutzerName.text.trim(), passwort.text);
}
} }
} }
Item Item {
{
Layout.fillHeight: true Layout.fillHeight: true
} }
Dialog Dialog {
{
id: recoveryPaswordDialog id: recoveryPaswordDialog
modal: true
title: qsTr("Wiederherstellung")
anchors.centerIn: parent anchors.centerIn: parent
modal: true
standardButtons: Dialog.Ok | Dialog.Cancel standardButtons: Dialog.Ok | Dialog.Cancel
onAccepted: title: qsTr("Wiederherstellung")
{
recpass = recoveryPaswordInput.text onAccepted: {
getRecoveryDialog.open() recpass = recoveryPaswordInput.text;
getRecoveryDialog.open();
} }
ColumnLayout ColumnLayout {
{ RowLayout {
RowLayout Label {
{
Label
{
text: qsTr("Wiederherstellungspasswort eingeben: ") text: qsTr("Wiederherstellungspasswort eingeben: ")
} }
TextField {
TextField
{
id: recoveryPaswordInput id: recoveryPaswordInput
text: ""
echoMode: TextInput.Password echoMode: TextInput.Password
implicitWidth: 300 implicitWidth: 300
placeholderText: qsTr("Hier Wiederherstellungspasswort eingeben") placeholderText: qsTr("Hier Wiederherstellungspasswort eingeben")
text: ""
} }
} }
} }
} }
FileDialog {
FileDialog
{
id: getRecoveryDialog id: getRecoveryDialog
title: qsTr("Wiederherstellungsdatei")
currentFolder: StandardPaths.standardLocations(StandardPaths.DocumentsLocation)[0]
fileMode: FileDialog.OpenFile fileMode: FileDialog.OpenFile
nameFilters: ["PYQCRM Recovery files (*.pyqrec)"] nameFilters: ["PYQCRM Recovery files (*.pyqrec)"]
currentFolder: StandardPaths.standardLocations(StandardPaths.DocumentsLocation)[0] title: qsTr("Wiederherstellungsdatei")
onAccepted: config.getRecoveryKey(getRecoveryDialog.currentFile, recpass) onAccepted: config.getRecoveryKey(getRecoveryDialog.currentFile, recpass)
onRejected: quit() onRejected: quit()
} }
Notifications Notifications {
{
id: oschkar id: oschkar
}
}
Component.onCompleted:
{
loggedin_user.loginOkay.connect(loggedin)
config.invalidEncryptionKey.connect(getEncryptionKey)
config.checkEncryptionKey()
loggedin_user.noDbConnection.connect(dbConnectionFailed)
benutzerName.forceActiveFocus()
} }
function loggedin()
{
appLoader.source = "Dashboard.qml"
}
function getEncryptionKey()
{
recoveryPaswordDialog.open()
}
function dbConnectionFailed(msg)
{
oschkar.notificationBox.informativeText = msg
oschkar.notificationBox.text = "Verbindung zum Datenbankserver verloren"
oschkar.notificationBox.open()
} }
} }

View File

@@ -1,8 +0,0 @@
import QtQuick
import QtQuick.Controls.Basic
Button {
background: Rectangle {
radius: 4003
}
}

View File

@@ -1,3 +0,0 @@
module TeroStyle
singleton Colors Colors.qml
Button Button.qml

View File

@@ -6,12 +6,13 @@ import QtCore
ApplicationWindow ApplicationWindow
{ {
//property alias appLoader: appLoader
id: appWindow id: appWindow
width: Screen.width * .75 width: Screen.width * .75
height: Screen.height * .85 height: Screen.height * .85
visible: true visible: true
title: "PYQCRM" title: "TERO Personal"
font: Typography.body
color: Colors.mantle
property string confile: "" property string confile: ""
property alias settingsFileDialog: settingsFiledialog property alias settingsFileDialog: settingsFiledialog

30
TeroStyle/Button.qml Normal file
View File

@@ -0,0 +1,30 @@
import QtQuick
import QtQuick.Templates as T
T.Button {
id: control
implicitHeight: implicitContentHeight
implicitWidth: contentItem.width
background: Rectangle {
color: Colors.primary
radius: Dimensions.radius
}
contentItem: Text {
color: Colors.foreground
font: control.font
padding: Dimensions.s + 2
text: control.text
// Make sure the button is at least wide enough to be comfortably clickable
width: Math.max(implicitWidth, 120)
horizontalAlignment: Text.AlignHCenter
}
MouseArea {
id: mouseArea
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onPressed: (mouse) => mouse.accepted = false
}
}

11
TeroStyle/Dimensions.qml Normal file
View File

@@ -0,0 +1,11 @@
pragma Singleton
import QtQuick
QtObject {
readonly property int s: 9
readonly property int m: 15
readonly property int l: 30
readonly property int radius: 4
}

33
TeroStyle/Typography.qml Normal file
View File

@@ -0,0 +1,33 @@
pragma Singleton
import QtCore
import QtQuick
Item {
readonly property FontLoader robotoCondensed: FontLoader {
source: "qrc:/fonts/RobotoCondensed.otf"
}
readonly property font body: ({
family: robotoCondensed.font,
pointSize: 16,
weight: Font.Medium,
letterSpacing: 0,
kerning: true
})
readonly property font h1: ({
family: body.family,
pointSize: 38,
weight: body.weight,
letterSpacing: body.letterSpacing
})
//
// readonly property font h2: ({
// family: regular.font,
// pointSize: 38,
// weight: Font.Normal
// })
}

5
TeroStyle/qmldir Normal file
View File

@@ -0,0 +1,5 @@
module TeroStyle
singleton Colors Colors.qml
singleton Dimensions Dimensions.qml
singleton Typography Typography.qml
Button Button.qml

Binary file not shown.

Binary file not shown.

BIN
fonts/RobotoCondensed.otf Normal file

Binary file not shown.

15
main.py
View File

@@ -6,7 +6,7 @@ from PySide6.QtNetwork import QLocalServer, QLocalSocket
from PySide6.QtWidgets import QSystemTrayIcon from PySide6.QtWidgets import QSystemTrayIcon
from PySide6.QtGui import QGuiApplication, QIcon from PySide6.QtGui import QGuiApplication, QIcon
from PySide6.QtQml import QQmlApplicationEngine from PySide6.QtQml import QQmlApplicationEngine
from PySide6.QtCore import QIODevice #, QResource from PySide6.QtCore import QIODevice
from lib.ConfigLoader import ConfigLoader from lib.ConfigLoader import ConfigLoader
from lib.DB.BusinessModel import BusinessModel from lib.DB.BusinessModel import BusinessModel
import rc_pyqcrm import rc_pyqcrm
@@ -20,7 +20,6 @@ from lib.DB.EmployeeModel import EmployeeModel
from lib.DB.ObjectModel import ObjectModel from lib.DB.ObjectModel import ObjectModel
from lib.Printers import Printers from lib.Printers import Printers
os.environ['QML_XHR_ALLOW_FILE_READ'] = '1' os.environ['QML_XHR_ALLOW_FILE_READ'] = '1'
# [pyqcrm] # [pyqcrm]
@@ -47,6 +46,7 @@ object_model = None
printers = None printers = None
user = None user = None
def initializeProgram(): def initializeProgram():
print(f"In {__file__} file, initializeProgram()") print(f"In {__file__} file, initializeProgram()")
global address_model, bad_config, business_model, user, business_type, contact_model, employee_model, object_model, db_con, printers global address_model, bad_config, business_model, user, business_type, contact_model, employee_model, object_model, db_con, printers
@@ -65,6 +65,7 @@ def initializeProgram():
object_model = ObjectModel() object_model = ObjectModel()
publishContext() publishContext()
def configReady(): def configReady():
global bad_config global bad_config
bad_config = False bad_config = False
@@ -82,12 +83,11 @@ def publishContext():
engine.rootContext().setContextProperty("employee_model", employee_model) engine.rootContext().setContextProperty("employee_model", employee_model)
engine.rootContext().setContextProperty("object_model", object_model) engine.rootContext().setContextProperty("object_model", object_model)
if __name__ == "__main__": if __name__ == "__main__":
#QResource.registerResource("rc_qml.py")
app = QGuiApplication(sys.argv) app = QGuiApplication(sys.argv)
engine = QQmlApplicationEngine() engine = QQmlApplicationEngine()
pyq_sok = QLocalSocket() pyq_sok = QLocalSocket()
pyq_sok.connectToServer("PYQCRM_INSTANCE", QIODevice.ReadOnly) pyq_sok.connectToServer("PYQCRM_INSTANCE", QIODevice.ReadOnly)
@@ -100,9 +100,7 @@ if __name__ == "__main__":
pyq_server = QLocalServer() pyq_server = QLocalServer()
pyq_server.listen("PYQCRM_INSTANCE") pyq_server.listen("PYQCRM_INSTANCE")
engine.addImportPath("qrc:/"); engine.addImportPath("qrc:/")
# qml_file = Path(__file__).resolve().parent / "Gui/main.qml"
qml_file = "qrc:/Gui/main.qml" qml_file = "qrc:/Gui/main.qml"
@@ -123,13 +121,12 @@ if __name__ == "__main__":
engine.rootContext().setContextProperty("config", config) engine.rootContext().setContextProperty("config", config)
engine.rootContext().setContextProperty("sys_printers", printers) engine.rootContext().setContextProperty("sys_printers", printers)
engine.rootContext().setContextProperty("bad_config", bad_config) # print(f"Fehler: {i}") engine.rootContext().setContextProperty("bad_config", bad_config)
engine.rootContext().setContextProperty("db_con", db_con) engine.rootContext().setContextProperty("db_con", db_con)
engine.rootContext().setContextProperty("systray", tray) engine.rootContext().setContextProperty("systray", tray)
engine.load(qml_file) engine.load(qml_file)
if not engine.rootObjects(): if not engine.rootObjects():
sys.exit(-1) sys.exit(-1)
sys.exit(app.exec()) sys.exit(app.exec())

View File

@@ -16,7 +16,7 @@
<file>fonts/HelloStranger.otf</file> <file>fonts/HelloStranger.otf</file>
<file>fonts/HussarPrintA.otf</file> <file>fonts/HussarPrintA.otf</file>
<file>fonts/LittleBirdsRegular.ttf</file> <file>fonts/LittleBirdsRegular.ttf</file>
<file>fonts/ReginaldScript.ttf</file> <file>fonts/RobotoCondensed.otf</file>
<file>images/account.svg</file> <file>images/account.svg</file>
<file>README</file> <file>README</file>
<file>LICENSE</file> <file>LICENSE</file>

View File

@@ -49,7 +49,12 @@
<file>Gui/UtilityDialogs.qml</file> <file>Gui/UtilityDialogs.qml</file>
<file>Gui/OffersTable.qml</file> <file>Gui/OffersTable.qml</file>
<file>Gui/OfferTable.qml</file> <file>Gui/OfferTable.qml</file>
<file>Gui/Style/qmldir</file> <file>TeroStyle/Button.qml</file>
<file>Gui/Style/Button.qml</file> <file>TeroStyle/Colors.qml</file>
<file>TeroStyle/Dimensions.qml</file>
<file>TeroStyle/qmldir</file>
<file>TeroStyle/Typography.qml</file>
</qresource> </qresource>
<qresource prefix="/TeroStyle"/>
</RCC> </RCC>