Add about dialog

This commit is contained in:
Fabian 2022-09-29 02:55:45 +02:00
parent 8d332e1262
commit 833b734434
10 changed files with 186 additions and 69 deletions

View File

@ -1,4 +1,4 @@
MIT License Copyright (c) 2020 - 2021 Faerbit MIT License Copyright (c) 2020 - 2022 Faerbit
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -7,6 +7,7 @@ name = "pypi"
pyside6 = "~=6.3" pyside6 = "~=6.3"
requests = "~=2.28" requests = "~=2.28"
requests-futures = "~=1.0" requests-futures = "~=1.0"
packaging = "~=21.3"
[dev-packages] [dev-packages]
pyinstaller = "~=5.1" pyinstaller = "~=5.1"

84
Pipfile.lock generated
View File

@ -1,7 +1,7 @@
{ {
"_meta": { "_meta": {
"hash": { "hash": {
"sha256": "4397ad9a6ead53a68420c5e59d49fc0a7655f9a0079ee66548e0115e6fc3914d" "sha256": "633aca7e0b43a295ce3429d3e12976a4c16dcf422cee53e37d266f8000ef5feb"
}, },
"pipfile-spec": 6, "pipfile-spec": 6,
"requires": { "requires": {
@ -40,6 +40,22 @@
"markers": "python_version >= '3.5'", "markers": "python_version >= '3.5'",
"version": "==3.4" "version": "==3.4"
}, },
"packaging": {
"hashes": [
"sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
"sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"
],
"index": "pypi",
"version": "==21.3"
},
"pyparsing": {
"hashes": [
"sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb",
"sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"
],
"markers": "python_full_version >= '3.6.8'",
"version": "==3.0.9"
},
"pyside6": { "pyside6": {
"hashes": [ "hashes": [
"sha256:4d47a1bac761f480fa06d93d0d9a72603eb6625f1e503288125caaff716e9e97", "sha256:4d47a1bac761f480fa06d93d0d9a72603eb6625f1e503288125caaff716e9e97",
@ -123,7 +139,7 @@
"sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb",
"sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"
], ],
"markers": "python_version >= '3.6'", "index": "pypi",
"version": "==21.3" "version": "==21.3"
}, },
"pep517": { "pep517": {
@ -134,70 +150,6 @@
"markers": "python_version >= '3.6'", "markers": "python_version >= '3.6'",
"version": "==0.13.0" "version": "==0.13.0"
}, },
"pillow": {
"hashes": [
"sha256:0030fdbd926fb85844b8b92e2f9449ba89607231d3dd597a21ae72dc7fe26927",
"sha256:030e3460861488e249731c3e7ab59b07c7853838ff3b8e16aac9561bb345da14",
"sha256:0ed2c4ef2451de908c90436d6e8092e13a43992f1860275b4d8082667fbb2ffc",
"sha256:136659638f61a251e8ed3b331fc6ccd124590eeff539de57c5f80ef3a9594e58",
"sha256:13b725463f32df1bfeacbf3dd197fb358ae8ebcd8c5548faa75126ea425ccb60",
"sha256:1536ad017a9f789430fb6b8be8bf99d2f214c76502becc196c6f2d9a75b01b76",
"sha256:15928f824870535c85dbf949c09d6ae7d3d6ac2d6efec80f3227f73eefba741c",
"sha256:17d4cafe22f050b46d983b71c707162d63d796a1235cdf8b9d7a112e97b15bac",
"sha256:1802f34298f5ba11d55e5bb09c31997dc0c6aed919658dfdf0198a2fe75d5490",
"sha256:1cc1d2451e8a3b4bfdb9caf745b58e6c7a77d2e469159b0d527a4554d73694d1",
"sha256:1fd6f5e3c0e4697fa7eb45b6e93996299f3feee73a3175fa451f49a74d092b9f",
"sha256:254164c57bab4b459f14c64e93df11eff5ded575192c294a0c49270f22c5d93d",
"sha256:2ad0d4df0f5ef2247e27fc790d5c9b5a0af8ade9ba340db4a73bb1a4a3e5fb4f",
"sha256:2c58b24e3a63efd22554c676d81b0e57f80e0a7d3a5874a7e14ce90ec40d3069",
"sha256:2d33a11f601213dcd5718109c09a52c2a1c893e7461f0be2d6febc2879ec2402",
"sha256:336b9036127eab855beec9662ac3ea13a4544a523ae273cbf108b228ecac8437",
"sha256:337a74fd2f291c607d220c793a8135273c4c2ab001b03e601c36766005f36885",
"sha256:37ff6b522a26d0538b753f0b4e8e164fdada12db6c6f00f62145d732d8a3152e",
"sha256:3d1f14f5f691f55e1b47f824ca4fdcb4b19b4323fe43cc7bb105988cad7496be",
"sha256:4134d3f1ba5f15027ff5c04296f13328fecd46921424084516bdb1b2548e66ff",
"sha256:4ad2f835e0ad81d1689f1b7e3fbac7b01bb8777d5a985c8962bedee0cc6d43da",
"sha256:50dff9cc21826d2977ef2d2a205504034e3a4563ca6f5db739b0d1026658e004",
"sha256:510cef4a3f401c246cfd8227b300828715dd055463cdca6176c2e4036df8bd4f",
"sha256:5aed7dde98403cd91d86a1115c78d8145c83078e864c1de1064f52e6feb61b20",
"sha256:69bd1a15d7ba3694631e00df8de65a8cb031911ca11f44929c97fe05eb9b6c1d",
"sha256:6bf088c1ce160f50ea40764f825ec9b72ed9da25346216b91361eef8ad1b8f8c",
"sha256:6e8c66f70fb539301e064f6478d7453e820d8a2c631da948a23384865cd95544",
"sha256:74a04183e6e64930b667d321524e3c5361094bb4af9083db5c301db64cd341f3",
"sha256:75e636fd3e0fb872693f23ccb8a5ff2cd578801251f3a4f6854c6a5d437d3c04",
"sha256:7761afe0126d046974a01e030ae7529ed0ca6a196de3ec6937c11df0df1bc91c",
"sha256:7888310f6214f19ab2b6df90f3f06afa3df7ef7355fc025e78a3044737fab1f5",
"sha256:7b0554af24df2bf96618dac71ddada02420f946be943b181108cac55a7a2dcd4",
"sha256:7c7b502bc34f6e32ba022b4a209638f9e097d7a9098104ae420eb8186217ebbb",
"sha256:808add66ea764ed97d44dda1ac4f2cfec4c1867d9efb16a33d158be79f32b8a4",
"sha256:831e648102c82f152e14c1a0938689dbb22480c548c8d4b8b248b3e50967b88c",
"sha256:93689632949aff41199090eff5474f3990b6823404e45d66a5d44304e9cdc467",
"sha256:96b5e6874431df16aee0c1ba237574cb6dff1dcb173798faa6a9d8b399a05d0e",
"sha256:9a54614049a18a2d6fe156e68e188da02a046a4a93cf24f373bffd977e943421",
"sha256:a138441e95562b3c078746a22f8fca8ff1c22c014f856278bdbdd89ca36cff1b",
"sha256:a647c0d4478b995c5e54615a2e5360ccedd2f85e70ab57fbe817ca613d5e63b8",
"sha256:a9c9bc489f8ab30906d7a85afac4b4944a572a7432e00698a7239f44a44e6efb",
"sha256:ad2277b185ebce47a63f4dc6302e30f05762b688f8dc3de55dbae4651872cdf3",
"sha256:adabc0bce035467fb537ef3e5e74f2847c8af217ee0be0455d4fec8adc0462fc",
"sha256:b6d5e92df2b77665e07ddb2e4dbd6d644b78e4c0d2e9272a852627cdba0d75cf",
"sha256:bc431b065722a5ad1dfb4df354fb9333b7a582a5ee39a90e6ffff688d72f27a1",
"sha256:bdd0de2d64688ecae88dd8935012c4a72681e5df632af903a1dca8c5e7aa871a",
"sha256:c79698d4cd9318d9481d89a77e2d3fcaeff5486be641e60a4b49f3d2ecca4e28",
"sha256:cb6259196a589123d755380b65127ddc60f4c64b21fc3bb46ce3a6ea663659b0",
"sha256:d5b87da55a08acb586bad5c3aa3b86505f559b84f39035b233d5bf844b0834b1",
"sha256:dcd7b9c7139dc8258d164b55696ecd16c04607f1cc33ba7af86613881ffe4ac8",
"sha256:dfe4c1fedfde4e2fbc009d5ad420647f7730d719786388b7de0999bf32c0d9fd",
"sha256:ea98f633d45f7e815db648fd7ff0f19e328302ac36427343e4432c84432e7ff4",
"sha256:ec52c351b35ca269cb1f8069d610fc45c5bd38c3e91f9ab4cbbf0aebc136d9c8",
"sha256:eef7592281f7c174d3d6cbfbb7ee5984a671fcd77e3fc78e973d492e9bf0eb3f",
"sha256:f07f1f00e22b231dd3d9b9208692042e29792d6bd4f6639415d2f23158a80013",
"sha256:f3fac744f9b540148fa7715a435d2283b71f68bfb6d4aae24482a890aed18b59",
"sha256:fa768eff5f9f958270b081bb33581b4b569faabf8774726b283edb06617101dc",
"sha256:fac2d65901fb0fdf20363fbd345c01958a742f2dc62a8dd4495af66e3ff502a4"
],
"markers": "sys_platform == 'win32'",
"version": "==9.2.0"
},
"pyinstaller": { "pyinstaller": {
"hashes": [ "hashes": [
"sha256:0ac78f1145be34adda8afb5fe4c8d659172140092c055994dab57ee2190bec71", "sha256:0ac78f1145be34adda8afb5fe4c8d659172140092c055994dab57ee2190bec71",

View File

@ -9,3 +9,4 @@ build-backend = "setuptools.build_meta"
[tool.setuptools_scm] [tool.setuptools_scm]
version_scheme = "guess-next-dev" version_scheme = "guess-next-dev"
local_scheme = "dirty-tag" local_scheme = "dirty-tag"
write_to = "src/fime/_version.py"

View File

@ -21,6 +21,7 @@ python_requires = >=3.8
install_requires = install_requires =
requests requests
requests-futures requests-futures
packaging
[options.packages.find] [options.packages.find]
where = src where = src
@ -32,4 +33,3 @@ qt6 = PySide6
[options.entry_points] [options.entry_points]
gui_scripts = gui_scripts =
fime = fime.main:main fime = fime.main:main

1
src/fime/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
_version.py

View File

@ -0,0 +1 @@
from _version import __version__, __version_tuple__

5
src/fime/_version.py Normal file
View File

@ -0,0 +1,5 @@
# coding: utf-8
# file generated by setuptools_scm
# don't change, don't track in version control
__version__ = version = '1.0.0.dev0'
__version_tuple__ = version_tuple = (1, 0, 0, 'dev0')

139
src/fime/about.py Normal file
View File

@ -0,0 +1,139 @@
import sys
import traceback
from copy import copy
from textwrap import dedent
from threading import Lock
from typing import Optional
from packaging.version import Version
from requests_futures.sessions import FuturesSession
from fime.progressindicator import ProgressIndicator
from fime.util import get_icon
try:
from PySide6 import QtCore, QtGui, QtWidgets
except ImportError:
from PySide2 import QtCore, QtGui, QtWidgets
import fime
URL = "https://gitlab.com/faerbit/fime/-/releases/permalink/latest"
class UpdateChecker:
def __init__(self):
self.session = FuturesSession()
future = self.session.get(URL, allow_redirects=False)
future.add_done_callback(self.process_response)
self.lock = Lock()
self._done = False
self.result = "Could not determined latest fime version"
@property
def done(self):
with self.lock:
ret = copy(self._done)
return ret
def process_response(self, future):
try:
resp = future.result()
if resp.status_code != 302 or "Location" not in resp.headers:
raise RuntimeError("Requested unexpectedly did not redirect")
latest_version = resp.headers["Location"].split("/")[-1]
latest_version = Version(latest_version)
own_version = Version(fime.__version__)
if own_version == latest_version:
self.result = "Latest fime version installed"
elif own_version > latest_version:
self.result = f"Older fime version available: {latest_version}"
else:
self.result = f"Newer fime version available: {latest_version}"
except Exception:
print("Could not get update info:\n", file=sys.stderr)
print(traceback.format_exc(), file=sys.stderr)
finally:
with self.lock:
self._done = True
class About(QtWidgets.QDialog):
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
self.setWindowTitle("About")
text = dedent(f"""\
fime
Copyright (c) 2020 - 2022 Faerbit
<a href="https://gitlab.com/faerbit/fime/-/blob/main/LICENSE">License</a>
fime Version {fime.__version__}
Qt Version {QtCore.__version__}
Python Version {sys.version}
""")
text = text.replace("\n", "<br/>")
version_label = QtWidgets.QLabel(self)
version_label.setText(text)
version_label.setTextFormat(QtCore.Qt.RichText)
version_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
version_label.setOpenExternalLinks(True)
version_label.setAlignment(QtCore.Qt.AlignHCenter)
self.update_layout = QtWidgets.QHBoxLayout()
self.ok_button = QtWidgets.QPushButton()
self.ok_button.setText("OK")
self.ok_button.setIcon(get_icon("dialog-ok"))
self.ok_button.pressed.connect(self.accept)
self.ok_button.setAutoDefault(True)
hlayout = QtWidgets.QHBoxLayout()
hlayout.addStretch(66)
hlayout.addWidget(self.ok_button, 33)
vlayout = QtWidgets.QVBoxLayout()
vlayout.addWidget(version_label)
vlayout.addLayout(self.update_layout)
vlayout.addLayout(hlayout)
self.setLayout(vlayout)
self.update_checker: Optional[UpdateChecker] = None
self.update_timer = QtCore.QTimer(self)
self.update_timer.setInterval(500)
self.update_timer.timeout.connect(self.timer_callback)
def clear_update_layout(self):
while self.update_layout.count():
child = self.update_layout.takeAt(0)
if child.widget():
child.widget().deleteLater()
def timer_callback(self):
if self.update_checker.done:
self.clear_update_layout()
update_label = QtWidgets.QLabel(self)
update_label.setText(self.update_checker.result)
update_label.setAlignment(QtCore.Qt.AlignHCenter)
self.update_layout.addWidget(update_label)
self.update_timer.stop()
def showEvent(self, _):
self.clear_update_layout()
progress_indicator = ProgressIndicator(self)
progress_indicator.setAnimationDelay(70)
progress_indicator.startAnimation()
update_label = QtWidgets.QLabel(self)
update_label.setText("Checking for latest version...")
self.update_layout.addStretch()
self.update_layout.addWidget(progress_indicator)
self.update_layout.addWidget(update_label)
self.update_layout.addStretch()
self.update_checker = UpdateChecker()
self.update_timer.start()

View File

@ -3,6 +3,7 @@ import signal
import sys import sys
from functools import partial from functools import partial
from fime.about import About
from fime.config import Config from fime.config import Config
from fime.worklog import WorklogDialog from fime.worklog import WorklogDialog
@ -54,6 +55,8 @@ class App:
self.worklogDialog = WorklogDialog(config, Worklog(lcd), None) self.worklogDialog = WorklogDialog(config, Worklog(lcd), None)
self.worklogDialog.accepted.connect(self.log_edited) self.worklogDialog.accepted.connect(self.log_edited)
self.about = About(None)
self.tray = QtWidgets.QSystemTrayIcon() self.tray = QtWidgets.QSystemTrayIcon()
self.tray.setIcon(icon) self.tray.setIcon(icon)
self.tray.setContextMenu(self.menu) self.tray.setContextMenu(self.menu)
@ -104,7 +107,7 @@ class App:
add_tasks(self.tasks.tasks) add_tasks(self.tasks.tasks)
menu_items.append((1, None)) menu_items.append((1, None))
already_taken = (len(self.tasks.tasks) + 4) * action_height already_taken = (len(self.tasks.tasks) + 5) * action_height
available_space = get_screen_height(self.menu) * 0.8 - already_taken available_space = get_screen_height(self.menu) * 0.8 - already_taken
jira_entry_count = int(available_space // action_height) jira_entry_count = int(available_space // action_height)
add_tasks(self.tasks.jira_tasks[-jira_entry_count:]) add_tasks(self.tasks.jira_tasks[-jira_entry_count:])
@ -122,6 +125,7 @@ class App:
menu_items.append((1, None)) menu_items.append((1, None))
menu_items.append(("About", self.about.show))
menu_items.append(("Close", self.app.quit)) menu_items.append(("Close", self.app.quit))
if self.menu_flipped: if self.menu_flipped:
@ -159,6 +163,19 @@ class App:
self.taskEdit.tasks = self.tasks.tasks self.taskEdit.tasks = self.tasks.tasks
self.taskEdit.show() self.taskEdit.show()
#@QtCore.Slot()
#def about(self):
#max_line_length = reduce(lambda x, y: max(x, len(y)), text.splitlines(), 0)
#print(max_line_length)
#final_text = ""
#for line in text.splitlines():
# final_text += line.center(max_line_length)
# final_text += "\n"
#print(final_text)
#QtWidgets.QMessageBox.about(None, "About", final_text)
#a = About(None)
#a.show()
def excepthook(original, e_type, e_value, tb_obj): def excepthook(original, e_type, e_value, tb_obj):
if e_type is FimeException: if e_type is FimeException: