From d447dfb343d7cff9562c9e33fba3d1a5329a4995 Mon Sep 17 00:00:00 2001 From: Xevion Date: Wed, 25 Aug 2021 06:32:26 -0500 Subject: [PATCH] Implement input event load dialog with loading gif and debouncing --- bulk_reminders/load.py | 52 +++++++++++++++++++++ bulk_reminders/load.ui | 88 ++++++++++++++++++++++++++++++++++++ bulk_reminders/load_base.py | 48 ++++++++++++++++++++ bulk_reminders/loading.gif | Bin 0 -> 56896 bytes 4 files changed, 188 insertions(+) create mode 100644 bulk_reminders/load.py create mode 100644 bulk_reminders/load.ui create mode 100644 bulk_reminders/load_base.py create mode 100644 bulk_reminders/loading.gif diff --git a/bulk_reminders/load.py b/bulk_reminders/load.py new file mode 100644 index 0000000..80960d6 --- /dev/null +++ b/bulk_reminders/load.py @@ -0,0 +1,52 @@ +import os +import re +from typing import List + +from PyQt5.QtCore import QSize, QTimer +from PyQt5.QtGui import QMovie +from PyQt5.QtWidgets import QApplication, QDialog, QLabel + +from bulk_reminders.api import Event +from bulk_reminders.load_base import Ui_Dialog + +REGEX = re.compile( + r'\s*([\w\d\s,.;\'!\[\]()]{1,})\s+\|\s+(\d{4}-\d{2}-\d{2})\s+(\d{1,2}:\d{2}(?:AM|PM))?\s*(\d{4}-\d{2}-\d{2})(\d{1,2}:\d{2}(?:AM|PM))?') + + +class LoadDialog(QDialog, Ui_Dialog): + def __init__(self, *args, **kwargs): + super(QDialog, self).__init__(*args, **kwargs) + self.setupUi(self) + + self.spinner = QLabel() + path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'loading.gif') + self.movie = QMovie(path) + self.movie.setScaledSize(QSize(26, 26)) + self.spinner.setMovie(self.movie) + self.movie.start() + self.spinner.hide() + self.spinner.setFixedSize(23, 23) + self.horizontalLayout.addWidget(self.spinner) + + self.plainTextEdit.textChanged.connect(self.edited) + self.parseTimer = QTimer() + self.parseTimer.timeout.connect(self.parse) + self.parseTimer.setSingleShot(True) + + self.show() + self.parse() + + self.parsed: List[Event] = [] + + def parse(self) -> None: + """Parse the events entered into the dialog""" + self.spinner.hide() + results = [result.groups() for result in re.finditer(REGEX, self.plainTextEdit.toPlainText())] + self.eventCountLabel.setText(f'{len(results)} group{"s" if len(results) != 0 else ""} found.') + self.parsed = list(map(Event.parse_raw, results)) + + def edited(self) -> None: + """Prepare a timer to be fired to parse the edited text""" + self.parseTimer.stop() + self.spinner.show() + self.parseTimer.start(500) # 0.5 seconds diff --git a/bulk_reminders/load.ui b/bulk_reminders/load.ui new file mode 100644 index 0000000..7e9de6b --- /dev/null +++ b/bulk_reminders/load.ui @@ -0,0 +1,88 @@ + + + Dialog + + + + 0 + 0 + 400 + 300 + + + + Load Events + + + + + + + + + + + ... + + + + + + + 3 events found. + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + false + + + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/bulk_reminders/load_base.py b/bulk_reminders/load_base.py new file mode 100644 index 0000000..57caabb --- /dev/null +++ b/bulk_reminders/load_base.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'load.ui' +# +# Created by: PyQt5 UI code generator 5.15.4 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(400, 300) + self.gridLayout = QtWidgets.QGridLayout(Dialog) + self.gridLayout.setObjectName("gridLayout") + self.plainTextEdit = QtWidgets.QPlainTextEdit(Dialog) + self.plainTextEdit.setObjectName("plainTextEdit") + self.gridLayout.addWidget(self.plainTextEdit, 0, 0, 1, 1) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.toolButton = QtWidgets.QToolButton(Dialog) + self.toolButton.setObjectName("toolButton") + self.horizontalLayout.addWidget(self.toolButton) + self.eventCountLabel = QtWidgets.QLabel(Dialog) + self.eventCountLabel.setObjectName("eventCountLabel") + self.horizontalLayout.addWidget(self.eventCountLabel) + self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setCenterButtons(False) + self.buttonBox.setObjectName("buttonBox") + self.horizontalLayout.addWidget(self.buttonBox) + self.gridLayout.addLayout(self.horizontalLayout, 1, 0, 1, 1) + + self.retranslateUi(Dialog) + self.buttonBox.accepted.connect(Dialog.accept) + self.buttonBox.rejected.connect(Dialog.reject) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + _translate = QtCore.QCoreApplication.translate + Dialog.setWindowTitle(_translate("Dialog", "Load Events")) + self.toolButton.setText(_translate("Dialog", "...")) + self.eventCountLabel.setText(_translate("Dialog", "3 events found.")) diff --git a/bulk_reminders/loading.gif b/bulk_reminders/loading.gif new file mode 100644 index 0000000000000000000000000000000000000000..cbb2c0b327cde6493e44de778cb8d382f5c881ae GIT binary patch literal 56896 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 literal 0 HcmV?d00001