You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
200 lines
7.6 KiB
200 lines
7.6 KiB
import datetime
|
|
import logging
|
|
from typing import Tuple
|
|
|
|
from PySide6 import QtGui
|
|
from PySide6.QtCore import QTimer, QObject, Signal, QThread, Qt
|
|
from PySide6.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLabel, QMessageBox, QLineEdit, \
|
|
QHBoxLayout, QCheckBox, QDialogButtonBox, QFormLayout, QDialog
|
|
|
|
from timebot.timebot import TimeBot, TimebotObtainPasswordError
|
|
|
|
package_logger = logging.getLogger(__name__)
|
|
|
|
|
|
class MyPasswordDialog(QDialog):
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
|
|
self.setWindowTitle("Timebot Password")
|
|
|
|
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
|
self.buttonBox.accepted.connect(self.accept)
|
|
self.buttonBox.rejected.connect(self.reject)
|
|
|
|
self.first = QLineEdit(self)
|
|
self.first.setEchoMode(QLineEdit.Password)
|
|
self.second = QCheckBox(self)
|
|
|
|
self.layout = QFormLayout()
|
|
self.layout.addRow("Enter your password:", self.first)
|
|
self.layout.addRow("Cache password:", self.second)
|
|
self.layout.addWidget(self.buttonBox)
|
|
self.setLayout(self.layout)
|
|
|
|
def get_password(self) -> Tuple[bool, str, bool]:
|
|
if self.exec():
|
|
return True, self.first.text(), self.second.isChecked()
|
|
return False, "", False
|
|
|
|
|
|
class HoursPresentLabelArea(QWidget):
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
|
|
self.text_box_hours_present_label = QLabel()
|
|
self.text_box_hours_present_label.setText("Hours present:")
|
|
self.text_box_hours_present = QLabel()
|
|
self.text_box_hours_present.setStyleSheet("background : #E0E0E0")
|
|
self.text_box_hours_present.setAlignment(Qt.AlignCenter)
|
|
|
|
layout = QHBoxLayout()
|
|
layout.addWidget(self.text_box_hours_present_label)
|
|
layout.addWidget(self.text_box_hours_present)
|
|
self.setLayout(layout)
|
|
|
|
|
|
class TimebotMainWindow(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.hours_present = datetime.timedelta(microseconds=0)
|
|
|
|
self.text_box_status = QLabel()
|
|
self.text_box_hours_present_area = HoursPresentLabelArea(parent=self)
|
|
self.btn_update_status = QPushButton("Refresh Status")
|
|
|
|
layout = QVBoxLayout()
|
|
layout.addWidget(self.text_box_status)
|
|
layout.addWidget(self.text_box_hours_present_area)
|
|
layout.addWidget(self.btn_update_status)
|
|
self.setLayout(layout)
|
|
|
|
self.btn_update_status.clicked.connect(self.update_status)
|
|
|
|
self.status_timer_time = 60000 # msec -> 60s
|
|
self.status_timer = QTimer()
|
|
self.status_timer.timeout.connect(self.update_status)
|
|
self.status_timer.start(self.status_timer_time)
|
|
|
|
self.main_window_timer_time = 1000 # msec -> 1s
|
|
self.main_window_timer = QTimer()
|
|
self.main_window_timer.timeout.connect(self.update_main_window)
|
|
self.main_window_timer.start(self.main_window_timer_time)
|
|
|
|
self.error_msg = QMessageBox()
|
|
self.error_msg.setWindowTitle("Timebot ERROR")
|
|
self.error_msg.setIcon(QMessageBox.Critical)
|
|
self.error_msg.finished.connect(self.error_msg_finished)
|
|
|
|
self.update_status_running = False
|
|
self.update_status()
|
|
|
|
def update_main_window(self):
|
|
self.main_window_info_thread = QThread()
|
|
self.main_window_info_worker = MainWindowInfoWorker(self)
|
|
self.main_window_info_worker.moveToThread(self.main_window_info_thread)
|
|
self.main_window_info_thread.started.connect(self.main_window_info_worker.run)
|
|
self.main_window_info_worker.finished.connect(self.main_window_info_thread.quit)
|
|
self.main_window_info_worker.finished.connect(self.main_window_info_worker.deleteLater)
|
|
self.main_window_info_thread.finished.connect(self.main_window_info_thread.deleteLater)
|
|
self.main_window_info_thread.start()
|
|
|
|
def update_status(self):
|
|
if self.update_status_running:
|
|
return
|
|
self.status_thread = QThread()
|
|
self.status_worker = TimebotApiWorker(self, self.timebot)
|
|
self.status_worker.moveToThread(self.status_thread)
|
|
self.status_thread.started.connect(self.status_worker.run)
|
|
self.status_worker.finished.connect(self.status_thread.quit)
|
|
self.status_worker.finished.connect(self.status_worker.deleteLater)
|
|
self.status_thread.finished.connect(self.status_thread.deleteLater)
|
|
self.status_thread.finished.connect(self.update_status_finished)
|
|
self.status_worker.error.connect(lambda exp, *args: self.error_msg_show(str(exp)))
|
|
self.status_worker.obtain_password.connect(lambda *args: self.get_password(self.update_status))
|
|
self.status_thread.start()
|
|
self.update_status_started()
|
|
|
|
def get_password(self, callback: callable = None):
|
|
if self.timebot.mobatime_api.password is not None:
|
|
return
|
|
self.status_timer.stop()
|
|
ok, password, keep = MyPasswordDialog(self).get_password()
|
|
if ok:
|
|
self.timebot.mobatime_api.password = password
|
|
try:
|
|
_ = self.timebot.mobatime_api.session
|
|
except Exception as e:
|
|
self.error_msg_show(str(e))
|
|
if not keep:
|
|
self.timebot.mobatime_api.password = None
|
|
if callback is not None:
|
|
callback()
|
|
self.status_timer.start(self.status_timer_time)
|
|
|
|
def error_msg_show(self, error_text: str):
|
|
self.error_msg.setText(error_text)
|
|
self.status_timer.stop()
|
|
self.error_msg.exec_()
|
|
|
|
def error_msg_finished(self):
|
|
self.status_timer.start(self.status_timer_time)
|
|
|
|
def update_status_started(self):
|
|
self.btn_update_status.setEnabled(False)
|
|
self.btn_update_status.setText("Refreshing...")
|
|
self.update_status_running = True
|
|
|
|
def update_status_finished(self):
|
|
self.btn_update_status.setEnabled(True)
|
|
self.btn_update_status.setText("Refresh Status")
|
|
self.update_status_running = False
|
|
|
|
def update_hours_present(self, override: datetime.timedelta = None):
|
|
if override is not None:
|
|
self.hours_present: datetime.timedelta = override
|
|
elif self.hours_present > datetime.timedelta(seconds=self.main_window_timer_time / 100):
|
|
self.hours_present = self.hours_present + datetime.timedelta(seconds=1)
|
|
hp = self.hours_present - datetime.timedelta(microseconds=self.hours_present.microseconds)
|
|
self.text_box_hours_present_area.text_box_hours_present.setText(str(hp))
|
|
|
|
|
|
class TimebotApiWorker(QObject):
|
|
error = Signal(object)
|
|
obtain_password = Signal()
|
|
finished = Signal()
|
|
|
|
def __init__(self, tmw: TimebotMainWindow, timebot: TimeBot):
|
|
super().__init__()
|
|
self.tmw = tmw
|
|
self.timebot = timebot
|
|
|
|
def run(self):
|
|
try:
|
|
self.tmw.update_hours_present(override=self.timebot.get_hours_present())
|
|
self.tmw.text_box_status.setText(self.timebot.status())
|
|
except TimebotObtainPasswordError:
|
|
self.obtain_password.emit()
|
|
except Exception as e:
|
|
self.error.emit(e)
|
|
self.finished.emit()
|
|
|
|
|
|
class MainWindowInfoWorker(QObject):
|
|
finished = Signal()
|
|
|
|
def __init__(self, tmw: TimebotMainWindow):
|
|
super().__init__()
|
|
self.tmw = tmw
|
|
|
|
def run(self):
|
|
self.tmw.update_hours_present()
|
|
self.finished.emit()
|
|
|