Compare commits
No commits in common. "922cd87fe01fefeb3905d3794bee8540691206ef" and "36e644a736c25f8819e1237a77e36df7c9e876a9" have entirely different histories.
922cd87fe0
...
36e644a736
2
LICENSE
2
LICENSE
@ -1,4 +1,4 @@
|
|||||||
MIT License Copyright (c) 2020 - 2021 Faerbit
|
MIT License Copyright (c) 2020 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
|
||||||
|
16
README.md
16
README.md
@ -2,21 +2,7 @@
|
|||||||
|
|
||||||
Simple time tracking app written with Python and Qt5
|
Simple time tracking app written with Python and Qt5
|
||||||
|
|
||||||
Some Jira integration is built in.
|
Some JIRA integration is available.
|
||||||
|
|
||||||
## Installation, Qt versions and You
|
|
||||||
Fime supports using both Qt 5 and Qt 6 via their respective PySide packages.
|
|
||||||
|
|
||||||
On Linux I recommend installing the PySide package provided by the distribution.
|
|
||||||
Install `PySide2` for Qt 5 or `PySide6` for Qt 6.
|
|
||||||
|
|
||||||
Run `pip install --user fime` in that case.
|
|
||||||
|
|
||||||
On other OSes or if you decide not to follow my recommendation run either
|
|
||||||
* `pip install --user fime[qt5]` or
|
|
||||||
* `pip install --user fime[qt6]`
|
|
||||||
|
|
||||||
Note that it both versions of PySide are installed Qt 6 will be preferred.
|
|
||||||
|
|
||||||
## Config file
|
## Config file
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ author_email = faerbit@posteo.net
|
|||||||
description = Simple time tracking app written with Python and Qt5
|
description = Simple time tracking app written with Python and Qt5
|
||||||
long_description = file: README.md
|
long_description = file: README.md
|
||||||
long_description_content_type = text/markdown
|
long_description_content_type = text/markdown
|
||||||
license = MIT License
|
|
||||||
url = https://git.faerb.it/faerbit/fime
|
url = https://git.faerb.it/faerbit/fime
|
||||||
classifiers =
|
classifiers =
|
||||||
Programming Language :: Python :: 3
|
Programming Language :: Python :: 3
|
||||||
@ -13,7 +12,6 @@ classifiers =
|
|||||||
Operating System :: OS Independent
|
Operating System :: OS Independent
|
||||||
|
|
||||||
[options]
|
[options]
|
||||||
zip_safe = True
|
|
||||||
package_dir =
|
package_dir =
|
||||||
= src
|
= src
|
||||||
packages = find:
|
packages = find:
|
||||||
@ -21,14 +19,11 @@ python_requires = >=3.8
|
|||||||
install_requires =
|
install_requires =
|
||||||
requests
|
requests
|
||||||
requests-futures
|
requests-futures
|
||||||
|
PySide2
|
||||||
|
|
||||||
[options.packages.find]
|
[options.packages.find]
|
||||||
where = src
|
where = src
|
||||||
|
|
||||||
[options.extras_require]
|
|
||||||
qt5 = PySide2
|
|
||||||
qt6 = PySide6
|
|
||||||
|
|
||||||
[options.entry_points]
|
[options.entry_points]
|
||||||
gui_scripts =
|
gui_scripts =
|
||||||
fime = fime.main:main
|
fime = fime.main:main
|
||||||
|
@ -22,7 +22,6 @@ class Config:
|
|||||||
config_dir_path = Path(QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.ConfigLocation))
|
config_dir_path = Path(QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.ConfigLocation))
|
||||||
config_path = config_dir_path / "fime" / "fime.conf"
|
config_path = config_dir_path / "fime" / "fime.conf"
|
||||||
if config_path.exists():
|
if config_path.exists():
|
||||||
print(f'Reading config file "{config_path}"')
|
|
||||||
with open(config_path) as f:
|
with open(config_path) as f:
|
||||||
config_text = f.read()
|
config_text = f.read()
|
||||||
config_text = "[DEFAULT]\n" + config_text
|
config_text = "[DEFAULT]\n" + config_text
|
||||||
@ -40,7 +39,3 @@ class Config:
|
|||||||
def jira_token(self):
|
def jira_token(self):
|
||||||
return dequotify(self._configparser["DEFAULT"]["jira_token"])
|
return dequotify(self._configparser["DEFAULT"]["jira_token"])
|
||||||
|
|
||||||
@property
|
|
||||||
def tray_theme(self):
|
|
||||||
val = dequotify(self._configparser.get("DEFAULT", "tray_theme", fallback="dark"))
|
|
||||||
return val if val in ["light", "dark"] else "dark"
|
|
||||||
|
@ -176,46 +176,6 @@ ty:1;stroke:none\
|
|||||||
s=\x22ColorScheme-T\
|
s=\x22ColorScheme-T\
|
||||||
ext\x22/>\x0a </g>\x0a</\
|
ext\x22/>\x0a </g>\x0a</\
|
||||||
svg>\x0a\
|
svg>\x0a\
|
||||||
\x00\x00\x02`\
|
|
||||||
<\
|
|
||||||
svg xmlns=\x22http:\
|
|
||||||
//www.w3.org/200\
|
|
||||||
0/svg\x22 viewBox=\x22\
|
|
||||||
0 0 32 32\x22>\x0a <d\
|
|
||||||
efs\x0a id=\x22def\
|
|
||||||
s3051\x22>\x0a <sty\
|
|
||||||
le\x0a type=\x22\
|
|
||||||
text/css\x22\x0a \
|
|
||||||
id=\x22current-col\
|
|
||||||
or-scheme\x22>\x0a \
|
|
||||||
.ColorScheme-T\
|
|
||||||
ext {\x0a co\
|
|
||||||
lor:#dcd9d6;\x0a \
|
|
||||||
}\x0a </sty\
|
|
||||||
le>\x0a </defs>\x0a \
|
|
||||||
<path\x0a style\
|
|
||||||
=\x22fill:currentCo\
|
|
||||||
lor;fill-opacity\
|
|
||||||
:1;stroke:none\x22 \
|
|
||||||
\x0a d=\x22M 16 4 \
|
|
||||||
A 12 12 0 0 0 4 \
|
|
||||||
16 A 12 12 0 0 0\
|
|
||||||
16 28 A 12 12 0\
|
|
||||||
0 0 28 16 A 12 \
|
|
||||||
12 0 0 0 16 4 z \
|
|
||||||
M 16 5 A 11 11 0\
|
|
||||||
0 1 27 16 A 11 \
|
|
||||||
11 0 0 1 16 27 A\
|
|
||||||
11 11 0 0 1 5 1\
|
|
||||||
6 A 11 11 0 0 1 \
|
|
||||||
16 5 z M 15 7 L \
|
|
||||||
15 17 L 24 17 L \
|
|
||||||
24 16 L 16 16 L \
|
|
||||||
16 7 L 15 7 z \x22\x0a\
|
|
||||||
id=\x22path78\x22\
|
|
||||||
\x0a class=\x22Co\
|
|
||||||
lorScheme-Text\x22\x0a\
|
|
||||||
/>\x0a</svg>\x0a\
|
|
||||||
\x00\x00\x01L\
|
\x00\x00\x01L\
|
||||||
<\
|
<\
|
||||||
svg viewBox=\x220 0\
|
svg viewBox=\x220 0\
|
||||||
@ -322,11 +282,6 @@ qt_resource_name = b"\
|
|||||||
\x09\xc6\x14\xa7\
|
\x09\xc6\x14\xa7\
|
||||||
\x00l\
|
\x00l\
|
||||||
\x00i\x00s\x00t\x00-\x00a\x00d\x00d\x00.\x00s\x00v\x00g\
|
\x00i\x00s\x00t\x00-\x00a\x00d\x00d\x00.\x00s\x00v\x00g\
|
||||||
\x00\x19\
|
|
||||||
\x0b9\x06g\
|
|
||||||
\x00a\
|
|
||||||
\x00p\x00p\x00o\x00i\x00n\x00t\x00m\x00e\x00n\x00t\x00-\x00n\x00e\x00w\x00-\x00l\
|
|
||||||
\x00i\x00g\x00h\x00t\x00.\x00s\x00v\x00g\
|
|
||||||
\x00\x0b\
|
\x00\x0b\
|
||||||
\x0c+\x12G\
|
\x0c+\x12G\
|
||||||
\x00g\
|
\x00g\
|
||||||
@ -344,9 +299,9 @@ qt_resource_name = b"\
|
|||||||
qt_resource_struct = b"\
|
qt_resource_struct = b"\
|
||||||
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x09\x00\x00\x00\x02\
|
\x00\x00\x00\x00\x00\x02\x00\x00\x00\x08\x00\x00\x00\x02\
|
||||||
\x00\x00\x00\x00\x00\x00\x00\x00\
|
\x00\x00\x00\x00\x00\x00\x00\x00\
|
||||||
\x00\x00\x01<\x00\x00\x00\x00\x00\x01\x00\x00\x0e\xe9\
|
\x00\x00\x01\x04\x00\x00\x00\x00\x00\x01\x00\x00\x0c\x85\
|
||||||
\x00\x00\x01}.b\xfd-\
|
\x00\x00\x01}.b\xfd-\
|
||||||
\x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
\x00\x00\x00\x10\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\
|
||||||
\x00\x00\x01}.a\xe4+\
|
\x00\x00\x01}.a\xe4+\
|
||||||
@ -354,13 +309,11 @@ qt_resource_struct = b"\
|
|||||||
\x00\x00\x01}.\x1a\xb9\xf9\
|
\x00\x00\x01}.\x1a\xb9\xf9\
|
||||||
\x00\x00\x00\x88\x00\x00\x00\x00\x00\x01\x00\x00\x06\x95\
|
\x00\x00\x00\x88\x00\x00\x00\x00\x00\x01\x00\x00\x06\x95\
|
||||||
\x00\x00\x01}.b $\
|
\x00\x00\x01}.b $\
|
||||||
\x00\x00\x01\x1c\x00\x00\x00\x00\x00\x01\x00\x00\x0d\x82\
|
\x00\x00\x00\xe4\x00\x00\x00\x00\x00\x01\x00\x00\x0b\x1e\
|
||||||
\x00\x00\x01}.a\xce_\
|
\x00\x00\x01}.a\xce_\
|
||||||
\x00\x00\x00\xaa\x00\x00\x00\x00\x00\x01\x00\x00\x07\xe4\
|
\x00\x00\x00\xaa\x00\x00\x00\x00\x00\x01\x00\x00\x07\xe4\
|
||||||
\x00\x00\x01}.b\xe1.\
|
\x00\x00\x01}.b\xe1.\
|
||||||
\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x01\x00\x00\x09\xce\
|
\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x01\x00\x00\x09\xce\
|
||||||
\x00\x00\x01}/\x83\xea~\
|
|
||||||
\x00\x00\x01\x00\x00\x00\x00\x00\x00\x01\x00\x00\x0c2\
|
|
||||||
\x00\x00\x01}.b\x05\xfc\
|
\x00\x00\x01}.b\x05\xfc\
|
||||||
\x00\x00\x00d\x00\x00\x00\x00\x00\x01\x00\x00\x05E\
|
\x00\x00\x00d\x00\x00\x00\x00\x00\x01\x00\x00\x05E\
|
||||||
\x00\x00\x01}.b1)\
|
\x00\x00\x01}.b1)\
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
|
||||||
<defs
|
|
||||||
id="defs3051">
|
|
||||||
<style
|
|
||||||
type="text/css"
|
|
||||||
id="current-color-scheme">
|
|
||||||
.ColorScheme-Text {
|
|
||||||
color:#dcd9d6;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</defs>
|
|
||||||
<path
|
|
||||||
style="fill:currentColor;fill-opacity:1;stroke:none"
|
|
||||||
d="M 16 4 A 12 12 0 0 0 4 16 A 12 12 0 0 0 16 28 A 12 12 0 0 0 28 16 A 12 12 0 0 0 16 4 z M 16 5 A 11 11 0 0 1 27 16 A 11 11 0 0 1 16 27 A 11 11 0 0 1 5 16 A 11 11 0 0 1 16 5 z M 15 7 L 15 17 L 24 17 L 24 16 L 16 16 L 16 7 L 15 7 z "
|
|
||||||
id="path78"
|
|
||||||
class="ColorScheme-Text"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 608 B |
@ -2,7 +2,6 @@
|
|||||||
<RCC version="1.0">
|
<RCC version="1.0">
|
||||||
<qresource prefix="icons">
|
<qresource prefix="icons">
|
||||||
<file>appointment-new.svg</file>
|
<file>appointment-new.svg</file>
|
||||||
<file>appointment-new-light.svg</file>
|
|
||||||
<file>arrow-left.svg</file>
|
<file>arrow-left.svg</file>
|
||||||
<file>arrow-right.svg</file>
|
<file>arrow-right.svg</file>
|
||||||
<file>dialog-cancel.svg</file>
|
<file>dialog-cancel.svg</file>
|
||||||
|
@ -1,3 +1,2 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
rcc resources.qrc -g python -o __init__.py
|
rcc resources.qrc -g python -o __init__.py
|
||||||
sed -i 's/^.*import QtCore.*$/try:\n from PySide6 import QtCore\nexcept ImportError:\n from PySide2 import QtCore/g' __init__.py
|
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
from fime.config import Config
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PySide6 import QtGui, QtWidgets
|
from PySide6 import QtGui, QtWidgets
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -10,12 +8,12 @@ from fime.util import get_icon
|
|||||||
|
|
||||||
|
|
||||||
class ImportTask(QtWidgets.QDialog):
|
class ImportTask(QtWidgets.QDialog):
|
||||||
def __init__(self, config: Config, parent, *args, **kwargs):
|
def __init__(self, parent, *args, **kwargs):
|
||||||
super().__init__(parent, *args, **kwargs)
|
super().__init__(parent, *args, **kwargs)
|
||||||
self.setWindowTitle("New Tasks")
|
self.setWindowTitle("New Tasks")
|
||||||
|
|
||||||
self.line_edit = QtWidgets.QLineEdit()
|
self.line_edit = QtWidgets.QLineEdit()
|
||||||
completer = TaskCompleter(config)
|
completer = TaskCompleter()
|
||||||
self.line_edit.setCompleter(completer)
|
self.line_edit.setCompleter(completer)
|
||||||
self.line_edit.textChanged.connect(completer.update_picker)
|
self.line_edit.textChanged.connect(completer.update_picker)
|
||||||
|
|
||||||
|
@ -4,8 +4,6 @@ import signal
|
|||||||
import sys
|
import sys
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
from fime.config import Config
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from PySide6 import QtCore, QtWidgets
|
from PySide6 import QtCore, QtWidgets
|
||||||
PYSIDE_6 = True
|
PYSIDE_6 = True
|
||||||
@ -33,15 +31,11 @@ class App:
|
|||||||
self.log = Log(data)
|
self.log = Log(data)
|
||||||
self._active_task = self.log.last_log() or "Nothing"
|
self._active_task = self.log.last_log() or "Nothing"
|
||||||
|
|
||||||
self.config = Config()
|
|
||||||
if self.config.tray_theme == "light":
|
|
||||||
icon = get_icon("appointment-new-light")
|
|
||||||
else:
|
|
||||||
icon = get_icon("appointment-new")
|
icon = get_icon("appointment-new")
|
||||||
|
|
||||||
self.menu = QtWidgets.QMenu(None)
|
self.menu = QtWidgets.QMenu(None)
|
||||||
|
|
||||||
self.import_task = ImportTask(self.config, None)
|
self.import_task = ImportTask(None)
|
||||||
self.import_task.accepted.connect(self.new_task_imported)
|
self.import_task.accepted.connect(self.new_task_imported)
|
||||||
|
|
||||||
self.taskEdit = TaskEdit(None)
|
self.taskEdit = TaskEdit(None)
|
||||||
|
@ -15,12 +15,12 @@ from fime.config import Config
|
|||||||
|
|
||||||
|
|
||||||
class TaskCompleter(QtWidgets.QCompleter):
|
class TaskCompleter(QtWidgets.QCompleter):
|
||||||
def __init__(self, config: Config, parent=None, *args, **kwargs):
|
def __init__(self, parent=None, *args, **kwargs):
|
||||||
super().__init__([], parent, *args, **kwargs)
|
super().__init__([], parent, *args, **kwargs)
|
||||||
self.setFilterMode(QtCore.Qt.MatchFlag.MatchContains)
|
self.setFilterMode(QtCore.Qt.MatchFlag.MatchContains)
|
||||||
self.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
self.setCaseSensitivity(QtCore.Qt.CaseInsensitive)
|
||||||
self.session = FuturesSession()
|
self.session = FuturesSession()
|
||||||
self.config = config
|
self.config = Config()
|
||||||
self.picker_url = os.path.join(self.config.jira_url, "rest/api/2/issue/picker")
|
self.picker_url = os.path.join(self.config.jira_url, "rest/api/2/issue/picker")
|
||||||
self.search_url = os.path.join(self.config.jira_url, "rest/api/2/search")
|
self.search_url = os.path.join(self.config.jira_url, "rest/api/2/search")
|
||||||
self.text = ""
|
self.text = ""
|
||||||
|
@ -13,6 +13,5 @@ def get_screen_height(qobject):
|
|||||||
|
|
||||||
|
|
||||||
def get_icon(icon_name):
|
def get_icon(icon_name):
|
||||||
theme_name = icon_name.replace("-light", "") # respect system theme
|
|
||||||
fallback = QtGui.QIcon(f":/icons/{icon_name}").pixmap(256, 256)
|
fallback = QtGui.QIcon(f":/icons/{icon_name}").pixmap(256, 256)
|
||||||
return QtGui.QIcon.fromTheme(theme_name, fallback)
|
return QtGui.QIcon.fromTheme(icon_name, fallback)
|
||||||
|
Loading…
Reference in New Issue
Block a user