Skip to content

Instantly share code, notes, and snippets.

@Pikachuxxxx
Created January 4, 2026 11:33
Show Gist options
  • Select an option

  • Save Pikachuxxxx/3832bae7a4183045dce3ff1f04370ac6 to your computer and use it in GitHub Desktop.

Select an option

Save Pikachuxxxx/3832bae7a4183045dce3ff1f04370ac6 to your computer and use it in GitHub Desktop.
daily productivity tracker app for myself, I hate writing status updates so this (VibeCoded with 5.1 Codex Max)
from __future__ import annotations
import configparser
import random
import subprocess
import sys
import threading
from dataclasses import dataclass
from datetime import date, datetime, timedelta
from pathlib import Path
from typing import Dict, List, Optional
from PyQt6 import QtCore, QtGui, QtWidgets
DATA_DIR = Path.home() / ".prod_tracker"
CONFIG_PATH = DATA_DIR / "config.ini"
HOURLY_INTERVAL_MINUTES = 60
def ensure_data_dir() -> None:
DATA_DIR.mkdir(parents=True, exist_ok=True)
def format_duration(seconds: float) -> str:
secs = int(seconds)
hrs, rem = divmod(secs, 3600)
mins, rem = divmod(rem, 60)
return f"{hrs:02d}:{mins:02d}:{rem:02d}"
@dataclass
class CommandEntry:
name: str
command: str
class StorageManager:
def __init__(self) -> None:
ensure_data_dir()
self.config = configparser.ConfigParser()
if CONFIG_PATH.exists():
self.config.read(CONFIG_PATH)
if "commands" not in self.config:
self.config["commands"] = {}
self.day_file_path = self._day_file_path(date.today())
def _day_file_path(self, day: date) -> Path:
return DATA_DIR / f"hourly_logs_{day.strftime('%Y%m%d')}.txt"
def write_daily_status(self, text: str) -> None:
stamp = datetime.now().strftime("%Y-%m-%d %H:%M")
header = (
"========================================\n"
f"DAILY STATUS @ {stamp}\n"
"========================================\n"
f"{text.strip()}\n"
"========================================\n\n"
)
self.day_file_path.write_text(header, encoding="utf-8")
def append_hourly_log(self, entry: str) -> None:
stamp = datetime.now().strftime("%Y-%m-%d %H:%M")
with self.day_file_path.open("a", encoding="utf-8") as fh:
fh.write(
"++++++++ HOUR LOG ++++++++\n"
f"[{stamp}]\n"
f"{entry.strip()}\n"
"+++++++++++++++++++++++++++\n\n"
)
def append_break_entry(self, kind: str, duration_seconds: float) -> None:
stamp = datetime.now().strftime("%Y-%m-%d %H:%M")
with self.day_file_path.open("a", encoding="utf-8") as fh:
fh.write(f"[BREAK] {stamp} kind={kind} duration={format_duration(duration_seconds)}\n")
def append_day_summary(self, work_seconds: float, tasks: List[str]) -> None:
stamp = datetime.now().strftime("%Y-%m-%d %H:%M")
with self.day_file_path.open("a", encoding="utf-8") as fh:
fh.write("[DAY_END] {stamp}\n".format(stamp=stamp))
fh.write(f"total_work={format_duration(work_seconds)}\n")
if tasks:
fh.write("remaining_tasks=\n")
for t in tasks:
fh.write(f"- {t}\n")
fh.write("\n")
def load_commands(self) -> List[CommandEntry]:
cmds: List[CommandEntry] = []
if self.config.has_section("commands"):
for name, cmd in self.config.items("commands"):
cmds.append(CommandEntry(name=name, command=cmd))
return cmds
def save_commands(self, entries: List[CommandEntry]) -> None:
self.config["commands"] = {c.name: c.command for c in entries}
with CONFIG_PATH.open("w", encoding="utf-8") as fh:
self.config.write(fh)
def weekly_report_path(self, day: date) -> Path:
iso_year, iso_week, _ = day.isocalendar()
return DATA_DIR / f"weekly_report_{iso_year}_week{iso_week}.txt"
def generate_weekly_report(self, day: date) -> None:
iso_year, iso_week, _ = day.isocalendar()
lines: List[str] = []
for file in DATA_DIR.glob("hourly_logs_*.txt"):
name = file.stem.replace("hourly_logs_", "")
try:
file_day = datetime.strptime(name, "%Y%m%d").date()
except ValueError:
continue
y, w, _ = file_day.isocalendar()
if y == iso_year and w == iso_week:
lines.append(f"# {file_day}\n")
lines.extend(file.read_text(encoding="utf-8").splitlines())
lines.append("\n")
report_path = self.weekly_report_path(day)
if lines:
report_path.write_text("\n".join(lines), encoding="utf-8")
class FullScreenPrompt(QtWidgets.QDialog):
submitted = QtCore.pyqtSignal(str)
def __init__(self, title: str, placeholder: str, parent: Optional[QtWidgets.QWidget] = None) -> None:
super().__init__(parent)
self.setWindowTitle(title)
self.setModal(True)
self.setWindowFlag(QtCore.Qt.WindowType.WindowStaysOnTopHint, True)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint, True)
self.showFullScreen()
layout = QtWidgets.QVBoxLayout()
self.label = QtWidgets.QLabel(title)
self.label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.label.setStyleSheet("color: #0f0; font-size: 28px; font-weight: bold;")
layout.addWidget(self.label)
self.text = QtWidgets.QPlainTextEdit()
self.text.setPlaceholderText(placeholder)
self.text.setStyleSheet("font-size: 18px; background: #111; color: #fff; padding: 16px;")
layout.addWidget(self.text, 1)
self.submit_btn = QtWidgets.QPushButton("Submit")
self.submit_btn.setStyleSheet("background: #0a0; color: #fff; font-size: 22px; padding: 16px;")
self.submit_btn.clicked.connect(self._on_submit)
layout.addWidget(self.submit_btn)
self.setLayout(layout)
def _on_submit(self) -> None:
content = self.text.toPlainText().strip()
if content:
self.submitted.emit(content)
self.accept()
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa: N802
if event.key() in (QtCore.Qt.Key.Key_Escape, QtCore.Qt.Key.Key_Q):
return
super().keyPressEvent(event)
class BreakOverlay(QtWidgets.QDialog):
ended = QtCore.pyqtSignal(float)
def __init__(self, label: str, target_minutes: Optional[int] = None, parent: Optional[QtWidgets.QWidget] = None) -> None:
super().__init__(parent)
self.setModal(True)
self.setWindowFlag(QtCore.Qt.WindowType.WindowStaysOnTopHint, True)
self.setWindowFlag(QtCore.Qt.WindowType.FramelessWindowHint, True)
self.showFullScreen()
self.started_at = datetime.now()
self.target_minutes = target_minutes
layout = QtWidgets.QVBoxLayout()
self.label = QtWidgets.QLabel(f"Break: {label}")
self.label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.label.setStyleSheet("color: #f33; font-size: 32px; font-weight: bold;")
layout.addWidget(self.label)
self.timer_label = QtWidgets.QLabel("00:00:00")
self.timer_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.timer_label.setStyleSheet("color: #fff; font-size: 26px;")
layout.addWidget(self.timer_label)
self.end_btn = QtWidgets.QPushButton("End Break")
self.end_btn.setStyleSheet("background: #a00; color: #fff; font-size: 24px; padding: 18px;")
self.end_btn.clicked.connect(self.finish)
layout.addWidget(self.end_btn)
self.setLayout(layout)
self.update_timer = QtCore.QTimer(self)
self.update_timer.timeout.connect(self._tick)
self.update_timer.start(1000)
def _tick(self) -> None:
elapsed = (datetime.now() - self.started_at).total_seconds()
self.timer_label.setText(format_duration(elapsed))
if self.target_minutes:
remaining = int(self.target_minutes * 60 - elapsed)
if remaining <= 0:
self.timer_label.setStyleSheet("color: #0f0; font-size: 26px;")
def finish(self) -> None:
elapsed = (datetime.now() - self.started_at).total_seconds()
self.ended.emit(elapsed)
self.accept()
def keyPressEvent(self, event: QtGui.QKeyEvent) -> None: # noqa: N802
if event.key() in (QtCore.Qt.Key.Key_Escape, QtCore.Qt.Key.Key_Q):
return
super().keyPressEvent(event)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self) -> None:
super().__init__()
self.setWindowTitle("Prod Tracker")
self.resize(1100, 720)
self.setStyleSheet(
"""
QMainWindow { background: #0c0c0c; color: #eaeaea; }
QLabel { color: #eaeaea; }
QPushButton { background: #1b1b1b; color: #eaeaea; border: 1px solid #333; padding: 8px; }
QPushButton:hover { background: #222; }
QListWidget, QPlainTextEdit, QLineEdit, QTextEdit { background: #111; color: #eaeaea; border: 1px solid #222; }
QTabWidget::pane { border: 1px solid #222; }
"""
)
self.storage = StorageManager()
self.day_started = False
self.day_ended = False
self.start_time: Optional[datetime] = None
self.total_break_seconds = 0.0
self.active_break_overlay: Optional[BreakOverlay] = None
self.daily_status_text = ""
self.work_timer = QtCore.QTimer(self)
self.work_timer.timeout.connect(self._update_work_timer)
self.hourly_timer = QtCore.QTimer(self)
self.hourly_timer.setInterval(HOURLY_INTERVAL_MINUTES * 60 * 1000)
self.hourly_timer.timeout.connect(self.prompt_hourly_log)
self._build_ui()
def _build_ui(self) -> None:
central = QtWidgets.QWidget()
root_layout = QtWidgets.QHBoxLayout()
central.setLayout(root_layout)
# Main tabs
self.tabs = QtWidgets.QTabWidget()
root_layout.addWidget(self.tabs, 2)
# Today tab
today_tab = QtWidgets.QWidget()
today_layout = QtWidgets.QVBoxLayout()
today_tab.setLayout(today_layout)
self.start_btn = QtWidgets.QPushButton("START DAY")
self.start_btn.setStyleSheet("background: #0c7a0c; color: #fff; font-size: 22px; padding: 16px;")
self.start_btn.clicked.connect(self.start_day)
today_layout.addWidget(self.start_btn)
self.timer_label = QtWidgets.QLabel("00:00:00")
self.timer_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
self.timer_label.setStyleSheet(
"font-size: 48px; color: #0f0; padding: 12px;"
"background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #0a0a0a, stop:1 #111);"
"border: 1px solid #0a0; border-radius: 8px;"
)
today_layout.addWidget(self.timer_label)
break_row = QtWidgets.QHBoxLayout()
self.lunch_btn = QtWidgets.QPushButton("Lunch (30m)")
self.lunch_btn.clicked.connect(lambda: self.start_break("Lunch", 30))
break_row.addWidget(self.lunch_btn)
self.water_btn = QtWidgets.QPushButton("Water (5m)")
self.water_btn.clicked.connect(lambda: self.start_break("Water", 5))
break_row.addWidget(self.water_btn)
self.random_btn = QtWidgets.QPushButton("Random (5-15m)")
self.random_btn.clicked.connect(self._random_break)
break_row.addWidget(self.random_btn)
self.custom_break_btn = QtWidgets.QPushButton("Custom Break")
self.custom_break_btn.clicked.connect(lambda: self.start_break("Custom", None))
break_row.addWidget(self.custom_break_btn)
today_layout.addLayout(break_row)
self.test_prompt_btn = QtWidgets.QPushButton("Test Hourly Pop-up")
self.test_prompt_btn.setStyleSheet("background: #444; color: #fff; font-size: 16px; padding: 10px;")
self.test_prompt_btn.setToolTip("Force a full-screen hourly log prompt to grab attention")
self.test_prompt_btn.clicked.connect(lambda: self.prompt_hourly_log(force=True))
today_layout.addWidget(self.test_prompt_btn)
self.log_view = QtWidgets.QTextEdit()
self.log_view.setReadOnly(True)
self.log_view.setPlaceholderText("Hourly logs will appear here")
today_layout.addWidget(self.log_view, 1)
self.end_btn = QtWidgets.QPushButton("END DAY")
self.end_btn.setEnabled(False)
self.end_btn.setStyleSheet("background: #a00; color: #fff; font-size: 20px; padding: 14px;")
self.end_btn.clicked.connect(self.end_day)
today_layout.addWidget(self.end_btn)
self.tabs.addTab(today_tab, "Today")
# Commands tab
cmd_tab = QtWidgets.QWidget()
cmd_layout = QtWidgets.QVBoxLayout()
cmd_tab.setLayout(cmd_layout)
form_row = QtWidgets.QHBoxLayout()
self.cmd_name_input = QtWidgets.QLineEdit()
self.cmd_name_input.setPlaceholderText("Command name")
form_row.addWidget(self.cmd_name_input)
self.cmd_input = QtWidgets.QLineEdit()
self.cmd_input.setPlaceholderText("Command (e.g. open -a Notes)")
form_row.addWidget(self.cmd_input, 2)
self.add_cmd_btn = QtWidgets.QPushButton("Add/Update")
self.add_cmd_btn.clicked.connect(self.add_command)
form_row.addWidget(self.add_cmd_btn)
cmd_layout.addLayout(form_row)
self.cmd_list = QtWidgets.QListWidget()
self.cmd_list.itemSelectionChanged.connect(self._load_selected_command)
cmd_layout.addWidget(self.cmd_list, 1)
cmd_btn_row = QtWidgets.QHBoxLayout()
self.run_cmd_btn = QtWidgets.QPushButton("Run Selected")
self.run_cmd_btn.clicked.connect(self.run_selected_command)
cmd_btn_row.addWidget(self.run_cmd_btn)
self.del_cmd_btn = QtWidgets.QPushButton("Delete Selected")
self.del_cmd_btn.clicked.connect(self.delete_selected_command)
cmd_btn_row.addWidget(self.del_cmd_btn)
cmd_layout.addLayout(cmd_btn_row)
self.cmd_output = QtWidgets.QPlainTextEdit()
self.cmd_output.setReadOnly(True)
self.cmd_output.setPlaceholderText("Command output")
cmd_layout.addWidget(self.cmd_output, 1)
self.tabs.addTab(cmd_tab, "Commands")
# Right panel for daily stack
side_panel = QtWidgets.QVBoxLayout()
root_layout.addLayout(side_panel, 1)
side_panel.addWidget(QtWidgets.QLabel("Daily Stack"))
self.stack_input = QtWidgets.QLineEdit()
self.stack_input.setPlaceholderText("Add a task and press Enter")
self.stack_input.returnPressed.connect(self.add_stack_item)
side_panel.addWidget(self.stack_input)
self.stack_list = QtWidgets.QListWidget()
self.stack_list.setSpacing(6)
side_panel.addWidget(self.stack_list, 1)
stack_btn_row = QtWidgets.QHBoxLayout()
self.stack_up_btn = QtWidgets.QPushButton("Up")
self.stack_up_btn.clicked.connect(lambda: self.move_stack_item(-1))
stack_btn_row.addWidget(self.stack_up_btn)
self.stack_down_btn = QtWidgets.QPushButton("Down")
self.stack_down_btn.clicked.connect(lambda: self.move_stack_item(1))
stack_btn_row.addWidget(self.stack_down_btn)
side_panel.addLayout(stack_btn_row)
self.setCentralWidget(central)
self._load_commands_into_ui()
def start_day(self) -> None:
if self.day_started:
return
prompt = FullScreenPrompt("Start Day - Daily Status", "Write today's intention / status")
prompt.submitted.connect(self._receive_daily_status)
prompt.exec()
def _receive_daily_status(self, text: str) -> None:
self.daily_status_text = text
self.storage.write_daily_status(text)
self.day_started = True
self.start_time = datetime.now()
self.work_timer.start(1000)
self.hourly_timer.start()
self.start_btn.setEnabled(False)
self.end_btn.setEnabled(True)
self.log_view.append("Day started. Timer running.")
self._run_startup_commands()
def _run_startup_commands(self) -> None:
entries = self.storage.load_commands()
if not entries:
return
def runner() -> None:
self._append_log("[cmd] startup sequence ->")
for entry in entries:
self._append_command_output(f"$ {entry.command}\n")
self._append_log(f"[cmd] {entry.name}: {entry.command}")
try:
proc = subprocess.Popen(entry.command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, _ = proc.communicate()
if out:
self._append_command_output(out.decode(errors="ignore"))
except Exception as exc: # noqa: BLE001
self._append_command_output(f"Error running {entry.name}: {exc}\n")
threading.Thread(target=runner, daemon=True).start()
def _append_command_output(self, text: str) -> None:
QtCore.QMetaObject.invokeMethod(
self.cmd_output,
"appendPlainText",
QtCore.Qt.ConnectionType.QueuedConnection,
QtCore.Q_ARG(str, text),
)
def _append_log(self, text: str) -> None:
QtCore.QMetaObject.invokeMethod(
self.log_view,
"append",
QtCore.Qt.ConnectionType.QueuedConnection,
QtCore.Q_ARG(str, text),
)
def prompt_hourly_log(self, force: bool = False) -> None:
if (not self.day_started or self.day_ended) and not force:
return
prompt = FullScreenPrompt("Hourly Log", "What did you finish this hour?")
prompt.submitted.connect(self._receive_hourly_log)
prompt.exec()
def _receive_hourly_log(self, text: str) -> None:
self.storage.append_hourly_log(text)
stamp = datetime.now().strftime("%H:%M")
flair = random.choice(["🚀", "🔥", "🧭", "📈", "✨", "🎯"])
bar = "+" * 26
pretty = f"{bar}\n{flair} [{stamp}]\n{text}\n{bar}"
self.log_view.append(pretty)
def _update_work_timer(self) -> None:
if not self.start_time:
return
elapsed = (datetime.now() - self.start_time).total_seconds()
active = max(0, elapsed - self.total_break_seconds)
self.timer_label.setText(format_duration(active))
def _random_break(self) -> None:
minutes = random.randint(5, 15)
self.start_break("Random", minutes)
def start_break(self, label: str, minutes: Optional[int]) -> None:
if not self.day_started or self.day_ended:
return
if self.active_break_overlay:
return
overlay = BreakOverlay(label, minutes)
overlay.ended.connect(lambda secs, l=label: self.finish_break(l, secs))
self.active_break_overlay = overlay
overlay.exec()
def finish_break(self, label: str, seconds: float) -> None:
self.total_break_seconds += seconds
self.active_break_overlay = None
self.storage.append_break_entry(label, seconds)
self.log_view.append(f"Break ended: {label} ({format_duration(seconds)})")
def add_stack_item(self) -> None:
text = self.stack_input.text().strip()
if text:
self._insert_stack_item(text)
self.stack_input.clear()
def move_stack_item(self, delta: int) -> None:
row = self.stack_list.currentRow()
if row < 0:
return
new_row = row + delta
if 0 <= new_row < self.stack_list.count():
item = self.stack_list.takeItem(row)
widget = self.stack_list.itemWidget(item)
self.stack_list.removeItemWidget(item)
self.stack_list.insertItem(new_row, item)
self.stack_list.setItemWidget(item, widget)
self.stack_list.setCurrentRow(new_row)
def remove_stack_item(self) -> None:
row = self.stack_list.currentRow()
if row >= 0:
item = self.stack_list.takeItem(row)
widget = self.stack_list.itemWidget(item)
self.stack_list.removeItemWidget(item)
if widget:
widget.deleteLater()
del item
def _load_commands_into_ui(self) -> None:
self.cmd_list.clear()
for entry in self.storage.load_commands():
self.cmd_list.addItem(entry.name)
def _insert_stack_item(self, text: str, checked: bool = False) -> None:
item = QtWidgets.QListWidgetItem()
item.setSizeHint(QtCore.QSize(220, 42))
container = QtWidgets.QWidget()
layout = QtWidgets.QHBoxLayout()
layout.setContentsMargins(8, 4, 8, 4)
layout.setSpacing(8)
check_btn = QtWidgets.QPushButton("✓")
check_btn.setCheckable(True)
check_btn.setChecked(checked)
check_btn.setFixedWidth(32)
check_btn.setStyleSheet("background: #163; color: #fff; border-radius: 6px;")
label = QtWidgets.QLabel(text)
label.setStyleSheet("font-size: 14px; color: #eaeaea;")
delete_btn = QtWidgets.QPushButton("✕")
delete_btn.setFixedWidth(32)
delete_btn.setStyleSheet("background: #611; color: #fff; border-radius: 6px;")
layout.addWidget(check_btn)
layout.addWidget(label, 1)
layout.addWidget(delete_btn)
container.setLayout(layout)
def toggle_style(state: bool) -> None:
label.setStyleSheet(
"font-size: 14px; color: #8f8; text-decoration: line-through;" if state else "font-size: 14px; color: #eaeaea;"
)
check_btn.toggled.connect(toggle_style)
delete_btn.clicked.connect(lambda: self._delete_stack_item(item))
self.stack_list.addItem(item)
self.stack_list.setItemWidget(item, container)
toggle_style(checked)
def _delete_stack_item(self, item: QtWidgets.QListWidgetItem) -> None:
row = self.stack_list.row(item)
if row >= 0:
removed = self.stack_list.takeItem(row)
widget = self.stack_list.itemWidget(removed)
self.stack_list.removeItemWidget(removed)
if widget:
widget.deleteLater()
del removed
def _load_selected_command(self) -> None:
item = self.cmd_list.currentItem()
if not item:
return
name = item.text()
entries = {c.name: c.command for c in self.storage.load_commands()}
if name in entries:
self.cmd_name_input.setText(name)
self.cmd_input.setText(entries[name])
def add_command(self) -> None:
name = self.cmd_name_input.text().strip()
cmd = self.cmd_input.text().strip()
if not name or not cmd:
return
entries = self.storage.load_commands()
existing = [c for c in entries if c.name == name]
if existing:
existing[0].command = cmd
else:
entries.append(CommandEntry(name=name, command=cmd))
self.storage.save_commands(entries)
self._load_commands_into_ui()
self.cmd_name_input.clear()
self.cmd_input.clear()
def delete_selected_command(self) -> None:
item = self.cmd_list.currentItem()
if not item:
return
name = item.text()
entries = [c for c in self.storage.load_commands() if c.name != name]
self.storage.save_commands(entries)
self._load_commands_into_ui()
def run_selected_command(self) -> None:
item = self.cmd_list.currentItem()
if not item:
return
name = item.text()
entries = {c.name: c.command for c in self.storage.load_commands()}
cmd = entries.get(name)
if not cmd:
return
def runner() -> None:
self._append_command_output(f"$ {cmd}\n")
try:
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
out, _ = proc.communicate()
if out:
self._append_command_output(out.decode(errors="ignore"))
except Exception as exc: # noqa: BLE001
self._append_command_output(f"Error: {exc}\n")
threading.Thread(target=runner, daemon=True).start()
def end_day(self) -> None:
if not self.day_started or self.day_ended:
return
if self.stack_list.count() > 0:
QtWidgets.QMessageBox.warning(self, "Daily Stack", "Clear the daily stack before ending the day.")
return
confirm = QtWidgets.QMessageBox.question(self, "End Day", "Export logs and stop for today?")
if confirm != QtWidgets.QMessageBox.StandardButton.Yes:
return
self.day_ended = True
self.work_timer.stop()
self.hourly_timer.stop()
active_seconds = 0.0
if self.start_time:
active_seconds = (datetime.now() - self.start_time).total_seconds() - self.total_break_seconds
self.storage.append_day_summary(active_seconds, [])
# Export weekly on Mondays for the previous week
if date.today().isoweekday() == 1:
self.storage.generate_weekly_report(date.today() - timedelta(days=1))
self.log_view.append("Day ended. Wrapping up and closing... ✨")
QtCore.QTimer.singleShot(800, self.close)
self.end_btn.setEnabled(False)
def closeEvent(self, event: QtGui.QCloseEvent) -> None: # noqa: N802
if self.day_started and not self.day_ended:
QtWidgets.QMessageBox.information(self, "Stay Focused", "You need to end the day from the app.")
event.ignore()
return
super().closeEvent(event)
def main() -> None:
app = QtWidgets.QApplication(sys.argv)
app.setWindowIcon(QtGui.QIcon.fromTheme("clock"))
win = MainWindow()
win.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment