From 9c905cfaa85db7cddb6f5879e5cbcb759cc32457 Mon Sep 17 00:00:00 2001 From: Maximilian Zettler Date: Fri, 4 Mar 2022 16:24:11 +0100 Subject: [PATCH] wip: add qt5 ui --- poetry.lock | 66 +++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 2 ++ timebot/app.py | 28 +++++++++++--------- timebot/gui.py | 37 ++++++++++++++++++++++++++ timebot/timebot.py | 16 +++++++++-- 5 files changed, 133 insertions(+), 16 deletions(-) create mode 100644 timebot/gui.py diff --git a/poetry.lock b/poetry.lock index 7d3c7bf..861ab61 100644 --- a/poetry.lock +++ b/poetry.lock @@ -132,6 +132,34 @@ python-versions = ">=3.6" [package.extras] diagrams = ["jinja2", "railroad-diagrams"] +[[package]] +name = "pyqt5" +version = "5.15.6" +description = "Python bindings for the Qt cross platform application toolkit" +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +PyQt5-Qt5 = ">=5.15.2" +PyQt5-sip = ">=12.8,<13" + +[[package]] +name = "pyqt5-qt5" +version = "5.15.2" +description = "The subset of a Qt installation needed by PyQt5." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "pyqt5-sip" +version = "12.9.1" +description = "The sip module support for PyQt5" +category = "main" +optional = false +python-versions = ">=3.5" + [[package]] name = "pytest" version = "5.4.3" @@ -217,7 +245,7 @@ testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytes [metadata] lock-version = "1.1" python-versions = "^3.6" -content-hash = "69c9457fa471c11ea8c160fbc1fd743e319c7cf8fd88730a60f318d4059e7448" +content-hash = "55bdfbbf52fa812d5d62f1d8117311eff037ce586754aa3541e5917903497643" [metadata.files] atomicwrites = [ @@ -271,6 +299,42 @@ pyparsing = [ {file = "pyparsing-3.0.7-py3-none-any.whl", hash = "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484"}, {file = "pyparsing-3.0.7.tar.gz", hash = "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea"}, ] +pyqt5 = [ + {file = "PyQt5-5.15.6-cp36-abi3-macosx_10_13_x86_64.whl", hash = "sha256:33ced1c876f6a26e7899615a5a4efef2167c263488837c7beed023a64cebd051"}, + {file = "PyQt5-5.15.6-cp36-abi3-manylinux1_x86_64.whl", hash = "sha256:9d6efad0377aa78bf081a20ac752ce86096ded18f04c592d98f5b92dc879ad0a"}, + {file = "PyQt5-5.15.6-cp36-abi3-win32.whl", hash = "sha256:9d2dcdaf82263ae56023410a7af15d1fd746c8e361733a7d0d1bd1f004ec2793"}, + {file = "PyQt5-5.15.6-cp36-abi3-win_amd64.whl", hash = "sha256:f411ecda52e488e1d3c5cce7563e1b2ca9cf0b7531e3c25b03d9a7e56e07e7fc"}, + {file = "PyQt5-5.15.6.tar.gz", hash = "sha256:80343bcab95ffba619f2ed2467fd828ffeb0a251ad7225be5fc06dcc333af452"}, +] +pyqt5-qt5 = [ + {file = "PyQt5_Qt5-5.15.2-py3-none-macosx_10_13_intel.whl", hash = "sha256:76980cd3d7ae87e3c7a33bfebfaee84448fd650bad6840471d6cae199b56e154"}, + {file = "PyQt5_Qt5-5.15.2-py3-none-manylinux2014_x86_64.whl", hash = "sha256:1988f364ec8caf87a6ee5d5a3a5210d57539988bf8e84714c7d60972692e2f4a"}, + {file = "PyQt5_Qt5-5.15.2-py3-none-win32.whl", hash = "sha256:9cc7a768b1921f4b982ebc00a318ccb38578e44e45316c7a4a850e953e1dd327"}, + {file = "PyQt5_Qt5-5.15.2-py3-none-win_amd64.whl", hash = "sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962"}, +] +pyqt5-sip = [ + {file = "PyQt5_sip-12.9.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b2e553e21b7ff124007a6b9168f8bb8c171fdf230d31ca0588df180f10bacbe"}, + {file = "PyQt5_sip-12.9.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:5740a1770d6b92a5dca8bb0bda4620baf0d7a726beb864f69c667ddac91d6f64"}, + {file = "PyQt5_sip-12.9.1-cp310-cp310-win32.whl", hash = "sha256:9699286fcdf4f75a4b91c7e4832c0f926af18d648c62a4ed72dd294c1a93705a"}, + {file = "PyQt5_sip-12.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:e2792af660da7479799f53028da88190ae8b4a0ad5acc2acbfd6c7bbfe110d58"}, + {file = "PyQt5_sip-12.9.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:7ee08ad0ebf85b935f5d8d38306f8665fff9a6026c14fc0a7d780649e889c096"}, + {file = "PyQt5_sip-12.9.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2d21420b0739df2607864e2c80ca01994bc40cb116da6ad024ea8d9f407b0356"}, + {file = "PyQt5_sip-12.9.1-cp36-cp36m-win32.whl", hash = "sha256:ffd25051962c593d1c3c30188b9fbd8589ba17acd23a0202dc987bd3552fa611"}, + {file = "PyQt5_sip-12.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:78ef8f1f41819661aa8e3117d6c1cd76fa14aef265e5bfd515dbfc64d412416b"}, + {file = "PyQt5_sip-12.9.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5e641182bfee0501267c55e687832e4efe05becdae9e555d3695d706009b6598"}, + {file = "PyQt5_sip-12.9.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c9a977d2835a5fbf250b00d61267dc228bdec9e20c7420d4e8d54d6f20410f87"}, + {file = "PyQt5_sip-12.9.1-cp37-cp37m-win32.whl", hash = "sha256:cec6ebf0b1163b18f09bc523160c467a9528b6dca129753827ac0bc432b332ae"}, + {file = "PyQt5_sip-12.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:82c1b3080db7634fa318fddbb3cfaa30e63a67bca1001a76958c31f30b774a9d"}, + {file = "PyQt5_sip-12.9.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cfaad4a773c18b963092589b1a98153d36624601de8597a4dc287e5a295d5625"}, + {file = "PyQt5_sip-12.9.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:ce7a8b3af9db378c46b345d9809d481a74c4bfcd3129486c054fbdbc6a3503f9"}, + {file = "PyQt5_sip-12.9.1-cp38-cp38-win32.whl", hash = "sha256:8fe5b3e4bbb8b472d05631cad21028d073f9f8eda770041449514cb3824a867f"}, + {file = "PyQt5_sip-12.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:5d59c4a5e856a35c41b47f5a23e1635b38cd1672f4f0122a68ebcb6889523ff2"}, + {file = "PyQt5_sip-12.9.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b56aedf7b0a496e4a8bd6087566888cea448aa01c76126cdb8b140e3ff3f5d93"}, + {file = "PyQt5_sip-12.9.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:53e23dcc0fc3857204abd47660e383b930941bd1aeaf3c78ed59c5c12dd48010"}, + {file = "PyQt5_sip-12.9.1-cp39-cp39-win32.whl", hash = "sha256:ee188eac5fd94dfe8d9e04a9e7fbda65c3535d5709278d8b7367ebd54f00e27f"}, + {file = "PyQt5_sip-12.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:989d51c41456cc496cb96f0b341464932b957040d26561f0bb4cf5a0914d6b36"}, + {file = "PyQt5_sip-12.9.1.tar.gz", hash = "sha256:2f24f299b44c511c23796aafbbb581bfdebf78d0905657b7cee2141b4982030e"}, +] pytest = [ {file = "pytest-5.4.3-py3-none-any.whl", hash = "sha256:5c0db86b698e8f170ba4582a492248919255fcd4c79b1ee64ace34301fb589a1"}, {file = "pytest-5.4.3.tar.gz", hash = "sha256:7979331bfcba207414f5e1263b5a0f8f521d0f457318836a7355531ed1a4c7d8"}, diff --git a/pyproject.toml b/pyproject.toml index 7b33f84..8285bed 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,10 +7,12 @@ readme = "README.md" [tool.poetry.scripts] timebot = 'timebot.app:run' +gtimebot = 'timebot.gui:run' [tool.poetry.dependencies] python = "^3.6" requests = "^2.27.1" +PyQt5 = "^5.15.6" [tool.poetry.dev-dependencies] pytest = "^5.2" diff --git a/timebot/app.py b/timebot/app.py index d135b95..ba68fcd 100644 --- a/timebot/app.py +++ b/timebot/app.py @@ -26,6 +26,9 @@ def run(): # subparser command: `status` parser_status = subparsers.add_parser("status", help="show your current tracking status") + # subparser command: `gui` + parser_status = subparsers.add_parser("gui", help="start qt5 gui") + # subparser command: `list-entries` parser_list_entries = subparsers.add_parser("list-entries", help="use this command to list your time entries") parser_list_entries.add_argument("--start-date", @@ -43,8 +46,8 @@ def run(): help=f"type of time entry; this can be {', '.join(PUNCH_COMMANDS)}", default="punch_in", choices=PUNCH_COMMANDS) - parser_punch.add_argument("-s", help=f"timestamp in format `{SIMPLE_DATETIME_FORMAT_HUMAN}` or `now`", - default="now") + parser_punch.add_argument("-s", help=f"timestamp in format `{SIMPLE_DATETIME_FORMAT_HUMAN}`, `{SIMPLE_TIME_FORMAT}`" + f" or `now`", default="now") # subparser command: `smart-punch` parser_smart_punch = subparsers.add_parser("smart-punch", @@ -52,8 +55,8 @@ def run(): "entries; this command tries to detect your last action and will " "create entries in to following order: " "punch_in -> break_start -> break_end -> punch_out") - parser_smart_punch.add_argument("-s", help=f"timestamp in format `{SIMPLE_DATETIME_FORMAT_HUMAN}` or `now`", - default="now") + parser_smart_punch.add_argument("-s", help=f"timestamp in format `{SIMPLE_DATETIME_FORMAT_HUMAN}`," + f" `{SIMPLE_TIME_FORMAT}` or `now`", default="now") args = parser.parse_args() @@ -99,15 +102,14 @@ def run(): for i in data: print("Entry: {} - DateTime: {} - Note: {}".format(i["entryName"], i["dateTime"], i["note"])) elif args.subparser_name == "status": - tracking_data = tb.mobatime_api.get_tracking_data() - account_info = tb.mobatime_api.get_account_information() - print("Tracking Info:") - print(f" Current State: {tracking_data['actualState']}") - print(f" Last Booking: {tracking_data['lastBooking']}") - print(f" Last Booking Date: {tracking_data['lastBookingDate']}") - print("Account Infos:") - for i in account_info: - print(f" {i['accountName']}: {i['value']}") + print(tb.status()) + elif args.subparser_name == "gui": + from PyQt5.QtWidgets import QApplication + from timebot.gui import TimebotMain + app = QApplication(sys.argv) + main_window = TimebotMain(timebot=tb) + main_window.show() + sys.exit(app.exec_()) else: logger.error("Noting done... dunno what you want!") sys.exit(1) diff --git a/timebot/gui.py b/timebot/gui.py new file mode 100644 index 0000000..7f77f45 --- /dev/null +++ b/timebot/gui.py @@ -0,0 +1,37 @@ +from PyQt5 import QtGui +from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLabel + +from timebot.timebot import TimeBot + + +class TimebotMain(QWidget): + def __init__(self, timebot: TimeBot, parent=None): + super().__init__(parent) + + self.timebot = timebot + self.timebot.mobatime_api.ask_for_password = False + + self.setWindowTitle("Timebot") + self.setWindowIcon(QtGui.QIcon.fromTheme('face-devilish')) + self.resize(300, 270) + + self.text_box = QLabel() + self.btnPress1 = QPushButton("Show / Refresh Status") + self.btnPress2 = QPushButton("Button 2") + + layout = QVBoxLayout() + layout.addWidget(self.text_box) + layout.addWidget(self.btnPress1) + layout.addWidget(self.btnPress2) + self.setLayout(layout) + + self.btnPress1.clicked.connect(self.show_status) + self.btnPress2.clicked.connect(self.btnPress2_Clicked) + + self.show_status() + + def show_status(self): + self.text_box.setText(self.timebot.status()) + + def btnPress2_Clicked(self): + pass diff --git a/timebot/timebot.py b/timebot/timebot.py index 02bf556..98cd380 100644 --- a/timebot/timebot.py +++ b/timebot/timebot.py @@ -45,7 +45,7 @@ class MobatimeApi: self.baseurl = self._sanitize_baseurl(baseurl) self.user = user self.password = password - self._ask_for_password = ask_for_password + self.ask_for_password = ask_for_password self._save_session = save_session self._session = None self._cookie_store = cookie_store @@ -89,7 +89,7 @@ class MobatimeApi: :raises: on status code != 2xx """ - if self.password is None and self._ask_for_password: + if self.password is None and self.ask_for_password: self.password = self._get_password() else: raise Exception("could not obtain password") @@ -324,3 +324,15 @@ class TimeBot: punch_datetime.strftime(SIMPLE_TIME_FORMAT), )) getattr(self, method)(punch_datetime) + + def status(self): + tracking_data = self.mobatime_api.get_tracking_data() + account_info = self.mobatime_api.get_account_information() + ret = "Tracking Info:\n" + ret += f" Current State: {tracking_data['actualState']}\n" + ret += f" Last Booking: {tracking_data['lastBooking']}\n" + ret += f" Last Booking Date: {tracking_data['lastBookingDate']}\n" + ret += "Account Infos:\n" + for i in account_info: + ret += f" {i['accountName']}: {i['value']}\n" + return ret \ No newline at end of file