commit 14ddde9fec478598abe46495030e633cc663b7a9 Author: Xevion Date: Wed Aug 25 02:30:10 2021 -0500 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..900f242 --- /dev/null +++ b/.gitignore @@ -0,0 +1,145 @@ +.idea + +# Token & Credentials File +credentials.json +token.json + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..3b4bad3 --- /dev/null +++ b/Pipfile @@ -0,0 +1,15 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] +pyqt5 = "*" +google-api-python-client = "*" +google-auth-httplib2 = "*" +google-auth-oauthlib = "*" + +[requires] +python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..7310bc9 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,247 @@ +{ + "_meta": { + "hash": { + "sha256": "1e521438cd45c13459a03381d4f560b52410944107e197af4fc52ea0836b2601" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "cachetools": { + "hashes": [ + "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001", + "sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff" + ], + "version": "==4.2.2" + }, + "certifi": { + "hashes": [ + "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee", + "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8" + ], + "version": "==2021.5.30" + }, + "charset-normalizer": { + "hashes": [ + "sha256:0c8911edd15d19223366a194a513099a302055a962bca2cec0f54b8b63175d8b", + "sha256:f23667ebe1084be45f6ae0538e4a5a865206544097e4e8bbcacf42cd02a348f3" + ], + "markers": "python_version >= '3'", + "version": "==2.0.4" + }, + "google-api-core": { + "hashes": [ + "sha256:428805de17b48ca1af2fdb5bbfc2334e1bbcb0ea4a16506fa1337fb29c8f37c8", + "sha256:bd9eb0709f4e10dd6fddb32fd0788a190b434426c258be6e00ef40da136d768d" + ], + "version": "==2.0.0" + }, + "google-api-python-client": { + "hashes": [ + "sha256:6e990fc4d0419c2011f75ca5c2762efbb7eb4def67bbe2f1b98a8ccb73117bf5", + "sha256:a25661ec6cf4c159f41fe9c061c2bee31b2dddaf2ad787e23617048a25b53842" + ], + "index": "pypi", + "version": "==2.18.0" + }, + "google-auth": { + "hashes": [ + "sha256:c012c8be7c442c8309ca8fa0876fef33f5fd977c467be1e1c1c2f721e8ebd73c", + "sha256:ea1af050b3e06eb73e4470f704d23007307bc0e87c13e015f6b90460f1407bd3" + ], + "version": "==2.0.1" + }, + "google-auth-httplib2": { + "hashes": [ + "sha256:31e49c36c6b5643b57e82617cb3e021e3e1d2df9da63af67252c02fa9c1f4a10", + "sha256:a07c39fd632becacd3f07718dfd6021bf396978f03ad3ce4321d060015cc30ac" + ], + "index": "pypi", + "version": "==0.1.0" + }, + "google-auth-oauthlib": { + "hashes": [ + "sha256:4ab58e6c3dc6ccf112f921fcced40e5426fba266768986ea502228488276eaba", + "sha256:b5a1ce7c617d247ccb2dfbba9d4bfc734b41096803d854a2c52592ae80150a67" + ], + "index": "pypi", + "version": "==0.4.5" + }, + "googleapis-common-protos": { + "hashes": [ + "sha256:a88ee8903aa0a81f6c3cec2d5cf62d3c8aa67c06439b0496b49048fb1854ebf4", + "sha256:f6d561ab8fb16b30020b940e2dd01cd80082f4762fa9f3ee670f4419b4b8dbd0" + ], + "version": "==1.53.0" + }, + "httplib2": { + "hashes": [ + "sha256:0b12617eeca7433d4c396a100eaecfa4b08ee99aa881e6df6e257a7aad5d533d", + "sha256:2ad195faf9faf079723f6714926e9a9061f694d07724b846658ce08d40f522b4" + ], + "version": "==0.19.1" + }, + "idna": { + "hashes": [ + "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a", + "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" + ], + "markers": "python_version >= '3'", + "version": "==3.2" + }, + "oauthlib": { + "hashes": [ + "sha256:42bf6354c2ed8c6acb54d971fce6f88193d97297e18602a3a886603f9d7730cc", + "sha256:8f0215fcc533dd8dd1bee6f4c412d4f0cd7297307d43ac61666389e3bc3198a3" + ], + "version": "==3.1.1" + }, + "protobuf": { + "hashes": [ + "sha256:13ee7be3c2d9a5d2b42a1030976f760f28755fcf5863c55b1460fd205e6cd637", + "sha256:145ce0af55c4259ca74993ddab3479c78af064002ec8227beb3d944405123c71", + "sha256:14c1c9377a7ffbeaccd4722ab0aa900091f52b516ad89c4b0c3bb0a4af903ba5", + "sha256:1556a1049ccec58c7855a78d27e5c6e70e95103b32de9142bae0576e9200a1b0", + "sha256:26010f693b675ff5a1d0e1bdb17689b8b716a18709113288fead438703d45539", + "sha256:2ae692bb6d1992afb6b74348e7bb648a75bb0d3565a3f5eea5bec8f62bd06d87", + "sha256:2bfb815216a9cd9faec52b16fd2bfa68437a44b67c56bee59bc3926522ecb04e", + "sha256:4ffbd23640bb7403574f7aff8368e2aeb2ec9a5c6306580be48ac59a6bac8bde", + "sha256:59e5cf6b737c3a376932fbfb869043415f7c16a0cf176ab30a5bbc419cd709c1", + "sha256:6902a1e4b7a319ec611a7345ff81b6b004b36b0d2196ce7a748b3493da3d226d", + "sha256:6ce4d8bf0321e7b2d4395e253f8002a1a5ffbcfd7bcc0a6ba46712c07d47d0b4", + "sha256:6d847c59963c03fd7a0cd7c488cadfa10cda4fff34d8bc8cba92935a91b7a037", + "sha256:72804ea5eaa9c22a090d2803813e280fb273b62d5ae497aaf3553d141c4fdd7b", + "sha256:7a4c97961e9e5b03a56f9a6c82742ed55375c4a25f2692b625d4087d02ed31b9", + "sha256:85d6303e4adade2827e43c2b54114d9a6ea547b671cb63fafd5011dc47d0e13d", + "sha256:8727ee027157516e2c311f218ebf2260a18088ffb2d29473e82add217d196b1c", + "sha256:99938f2a2d7ca6563c0ade0c5ca8982264c484fdecf418bd68e880a7ab5730b1", + "sha256:9b7a5c1022e0fa0dbde7fd03682d07d14624ad870ae52054849d8960f04bc764", + "sha256:a22b3a0dbac6544dacbafd4c5f6a29e389a50e3b193e2c70dae6bbf7930f651d", + "sha256:a38bac25f51c93e4be4092c88b2568b9f407c27217d3dd23c7a57fa522a17554", + "sha256:a981222367fb4210a10a929ad5983ae93bd5a050a0824fc35d6371c07b78caf6", + "sha256:ab6bb0e270c6c58e7ff4345b3a803cc59dbee19ddf77a4719c5b635f1d547aa8", + "sha256:c56c050a947186ba51de4f94ab441d7f04fcd44c56df6e922369cc2e1a92d683", + "sha256:e76d9686e088fece2450dbc7ee905f9be904e427341d289acbe9ad00b78ebd47", + "sha256:ebcb546f10069b56dc2e3da35e003a02076aaa377caf8530fe9789570984a8d2", + "sha256:f0e59430ee953184a703a324b8ec52f571c6c4259d496a19d1cabcdc19dabc62", + "sha256:ffea251f5cd3c0b9b43c7a7a912777e0bc86263436a87c2555242a348817221b" + ], + "version": "==3.17.3" + }, + "pyasn1": { + "hashes": [ + "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d", + "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba" + ], + "version": "==0.4.8" + }, + "pyasn1-modules": { + "hashes": [ + "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e", + "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74" + ], + "version": "==0.2.8" + }, + "pyparsing": { + "hashes": [ + "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1", + "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b" + ], + "version": "==2.4.7" + }, + "pyqt5": { + "hashes": [ + "sha256:213bebd51821ed89b4d5b35bb10dbe67564228b3568f463a351a08e8b1677025", + "sha256:2a69597e0dd11caabe75fae133feca66387819fc9bc050f547e5551bce97e5be", + "sha256:883a549382fc22d29a0568f3ef20b38c8e7ab633a59498ac4eb63a3bf36d3fd3", + "sha256:8c0848ba790a895801d5bfd171da31cad3e551dbcc4e59677a3b622de2ceca98", + "sha256:a88526a271e846e44779bb9ad7a738c6d3c4a9d01e15a128ecfc6dd4696393b7" + ], + "index": "pypi", + "version": "==5.15.4" + }, + "pyqt5-qt5": { + "hashes": [ + "sha256:1988f364ec8caf87a6ee5d5a3a5210d57539988bf8e84714c7d60972692e2f4a", + "sha256:750b78e4dba6bdf1607febedc08738e318ea09e9b10aea9ff0d73073f11f6962", + "sha256:76980cd3d7ae87e3c7a33bfebfaee84448fd650bad6840471d6cae199b56e154", + "sha256:9cc7a768b1921f4b982ebc00a318ccb38578e44e45316c7a4a850e953e1dd327" + ], + "version": "==5.15.2" + }, + "pyqt5-sip": { + "hashes": [ + "sha256:055581c6fed44ba4302b70eeb82e979ff70400037358908f251cd85cbb3dbd93", + "sha256:42274a501ab4806d2c31659170db14c282b8313d2255458064666d9e70d96206", + "sha256:4347bd81d30c8e3181e553b3734f91658cfbdd8f1a19f254777f906870974e6d", + "sha256:4f8e05fe01d54275877c59018d8e82dcdd0bc5696053a8b830eecea3ce806121", + "sha256:69a3ad4259172e2b1aa9060de211efac39ddd734a517b1924d9c6c0cc4f55f96", + "sha256:6a8701892a01a5a2a4720872361197cc80fdd5f49c8482d488ddf38c9c84f055", + "sha256:83c3220b1ca36eb8623ba2eb3766637b19eb0ce9f42336ad8253656d32750c0a", + "sha256:a25b9843c7da6a1608f310879c38e6434331aab1dc2fe6cb65c14f1ecf33780e", + "sha256:ac57d796c78117eb39edd1d1d1aea90354651efac9d3590aac67fa4983f99f1f", + "sha256:b09f4cd36a4831229fb77c424d89635fa937d97765ec90685e2f257e56a2685a", + "sha256:c446971c360a0a1030282a69375a08c78e8a61d568bfd6dab3dcc5cf8817f644", + "sha256:c5216403d4d8d857ec4a61f631d3945e44fa248aa2415e9ee9369ab7c8a4d0c7", + "sha256:d3e4489d7c2b0ece9d203ae66e573939f7f60d4d29e089c9f11daa17cfeaae32", + "sha256:d85002238b5180bce4b245c13d6face848faa1a7a9e5c6e292025004f2fd619a", + "sha256:d8b2bdff7bbf45bc975c113a03b14fd669dc0c73e1327f02706666a7dd51a197", + "sha256:dd05c768c2b55ffe56a9d49ce6cc77cdf3d53dbfad935258a9e347cbfd9a5850", + "sha256:fc43f2d7c438517ee33e929e8ae77132749c15909afab6aeece5fcf4147ffdb5" + ], + "version": "==12.9.0" + }, + "requests": { + "hashes": [ + "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", + "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" + ], + "version": "==2.26.0" + }, + "requests-oauthlib": { + "hashes": [ + "sha256:7f71572defaecd16372f9006f33c2ec8c077c3cfa6f5911a9a90202beb513f3d", + "sha256:b4261601a71fd721a8bd6d7aa1cc1d6a8a93b4a9f5e96626f8e4d91e8beeaa6a" + ], + "version": "==1.3.0" + }, + "rsa": { + "hashes": [ + "sha256:78f9a9bf4e7be0c5ded4583326e7461e3a3c5aae24073648b4bdfa797d78c9d2", + "sha256:9d689e6ca1b3038bc82bf8d23e944b6b6037bc02301a574935b2dd946e0353b9" + ], + "version": "==4.7.2" + }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "version": "==1.16.0" + }, + "uritemplate": { + "hashes": [ + "sha256:07620c3f3f8eed1f12600845892b0e036a2420acf513c53f7de0abd911a5894f", + "sha256:5af8ad10cec94f215e3f48112de2022e1d5a37ed427fbd88652fa908f2ab7cae" + ], + "version": "==3.0.1" + }, + "urllib3": { + "hashes": [ + "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4", + "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f" + ], + "version": "==1.26.6" + } + }, + "develop": {} +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..0dee11c --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# bulk-reminders + +Do you use Google Calendars to track your classes? I do. Or at least I'm trying to. + +The issue with this is that the way of setting up all the times is quick annoying, and I would like to do it all in one go without lifting a finger for the most part. + +This is a very small app designed to do that exactly. + +For example, a simple input like such: + +``` +08/23 08/29 "Module 1 +``` + +## Features + +- Small GUI for interacting with the Google Calendar API +- Bulk Text to API/GUI translation +- Easy undo button + +## API Setup + +This application uses a testing API and is not built for production usage. Just a warning before you try and set this up. + +1. [Create a Google API Project and enable the Calendar API](https://developers.google.com/calendar/api/quickstart/python) + +2. [Add a user as a test user](https://i.imgur.com/wKp0ipd.png) + +3. Create OAuth2.0 Credentials and download the file. Rename it and place it in the root of the repository directory. + +4. Start the application. Follow the prompt and sign in with the test user you added. diff --git a/bulk_reminders/__init__.py b/bulk_reminders/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bulk_reminders/gui.py b/bulk_reminders/gui.py new file mode 100644 index 0000000..a9caaaa --- /dev/null +++ b/bulk_reminders/gui.py @@ -0,0 +1,38 @@ +from PyQt5 import QtCore, QtGui +from PyQt5.QtWidgets import QDialog, QMainWindow + +from bulk_reminders import api +from bulk_reminders.gui_base import Ui_MainWindow +from bulk_reminders.oauth import OAuthDialog + + +class MainWindow(QMainWindow, Ui_MainWindow): + def __init__(self, *args, **kwargs): + # Initial UI setup + super(MainWindow, self).__init__(*args, **kwargs) + self.setupUi(self) + self.show() + + calendar = api.Calendar() + + # Authenticate user into Google API Engine + self.authenticated = calendar.authenticate_via_token() + if not self.authenticated: + temp_dialog = OAuthDialog(callback=calendar.authenticate_via_oauth) + temp_dialog.show() + calendar.setupService() + + # Get Calendars, Setup Calendar Selection Combobox + calendars = calendar.getCalendarsSimplified() + self.comboModel = QtGui.QStandardItemModel() + for id, summary in calendars: + item = QtGui.QStandardItem(summary) + item.setData(id) + self.comboModel.appendRow(item) + self.calendarCombobox.setModel(self.comboModel) + self.calendarCombobox.currentIndexChanged[int].connect(self.comboBoxChanged) + + @QtCore.pyqtSlot(int) + def comboBoxChanged(self, row) -> None: + """When the Calendar Selection combobox""" + self.currentCalendar = self.comboModel.item(row).data() diff --git a/bulk_reminders/gui_base.py b/bulk_reminders/gui_base.py new file mode 100644 index 0000000..e67b454 --- /dev/null +++ b/bulk_reminders/gui_base.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'gui.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_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(672, 553) + self.centralwidget = QtWidgets.QWidget(MainWindow) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth()) + self.centralwidget.setSizePolicy(sizePolicy) + self.centralwidget.setObjectName("centralwidget") + self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) + self.gridLayout.setObjectName("gridLayout") + self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout.setObjectName("verticalLayout") + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.loadEventsButton = QtWidgets.QPushButton(self.centralwidget) + self.loadEventsButton.setObjectName("loadEventsButton") + self.horizontalLayout_2.addWidget(self.loadEventsButton) + self.verticalLayout.addLayout(self.horizontalLayout_2) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + self.submitButton = QtWidgets.QPushButton(self.centralwidget) + self.submitButton.setMinimumSize(QtCore.QSize(100, 0)) + self.submitButton.setObjectName("submitButton") + self.horizontalLayout.addWidget(self.submitButton) + self.calendarCombobox = QtWidgets.QComboBox(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.calendarCombobox.sizePolicy().hasHeightForWidth()) + self.calendarCombobox.setSizePolicy(sizePolicy) + self.calendarCombobox.setMinimumSize(QtCore.QSize(140, 0)) + self.calendarCombobox.setObjectName("calendarCombobox") + self.horizontalLayout.addWidget(self.calendarCombobox) + spacerItem = QtWidgets.QSpacerItem(30, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.undoButton = QtWidgets.QPushButton(self.centralwidget) + self.undoButton.setObjectName("undoButton") + self.horizontalLayout.addWidget(self.undoButton) + self.verticalLayout.addLayout(self.horizontalLayout) + self.eventsView = QtWidgets.QColumnView(self.centralwidget) + self.eventsView.setObjectName("eventsView") + self.verticalLayout.addWidget(self.eventsView) + self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1) + MainWindow.setCentralWidget(self.centralwidget) + self.menubar = QtWidgets.QMenuBar(MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 672, 21)) + self.menubar.setObjectName("menubar") + MainWindow.setMenuBar(self.menubar) + self.statusbar = QtWidgets.QStatusBar(MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + self.loadEventsButton.setText(_translate("MainWindow", "Load events")) + self.submitButton.setText(_translate("MainWindow", "Submit")) + self.undoButton.setText(_translate("MainWindow", "Undo")) diff --git a/bulk_reminders/main.ui b/bulk_reminders/main.ui new file mode 100644 index 0000000..c594dc0 --- /dev/null +++ b/bulk_reminders/main.ui @@ -0,0 +1,111 @@ + + + MainWindow + + + + 0 + 0 + 672 + 553 + + + + MainWindow + + + + + 1 + 0 + + + + + + + + + + + Load events + + + + + + + + + + + + 100 + 0 + + + + Submit + + + + + + + + 0 + 0 + + + + + 140 + 0 + + + + + + + + Qt::Horizontal + + + + 30 + 20 + + + + + + + + Undo + + + + + + + + + + + + + + + + 0 + 0 + 672 + 21 + + + + + + + + diff --git a/main.py b/main.py new file mode 100644 index 0000000..7bcdd91 --- /dev/null +++ b/main.py @@ -0,0 +1,9 @@ +from PyQt5.QtWidgets import QApplication + +from bulk_reminders.gui import MainWindow + +if __name__ == '__main__': + app = QApplication([]) + app.setApplicationName("TCPChat Client") + window = MainWindow() + app.exec_()