Sfoglia il codice sorgente

Add set_active script

Maarten van den Berg 6 anni fa
parent
commit
fd26dcb90c
4 ha cambiato i file con 168 aggiunte e 24 eliminazioni
  1. 25 22
      piket_client/gui.py
  2. 7 2
      piket_client/model.py
  3. 135 0
      piket_client/set_active.py
  4. 1 0
      piket_server/__init__.py

+ 25 - 22
piket_client/gui.py

@@ -34,7 +34,13 @@ except ImportError:
34 34
     dbus = None
35 35
 
36 36
 from piket_client.sound import PLOP_WAVE, UNDO_WAVE
37
-from piket_client.model import Person, ConsumptionType, Consumption, ServerStatus, Settlement
37
+from piket_client.model import (
38
+    Person,
39
+    ConsumptionType,
40
+    Consumption,
41
+    ServerStatus,
42
+    Settlement,
43
+)
38 44
 import piket_client.logger
39 45
 
40 46
 LOG = logging.getLogger(__name__)
@@ -87,18 +93,17 @@ class NameButton(QPushButton):
87 93
 
88 94
     def process_click(self) -> None:
89 95
         """ Process a click on this button. """
90
-        LOG.debug('Button clicked.')
96
+        LOG.debug("Button clicked.")
91 97
         result = self.person.add_consumption(self.active_id)
92 98
         if result:
93 99
             plop()
94 100
             self.setText(self.current_label)
95 101
             self.consumption_created.emit(result)
96 102
         else:
97
-            LOG.error("Failed to add consumption", extra={'person':
98
-                self.person})
103
+            LOG.error("Failed to add consumption", extra={"person": self.person})
99 104
 
100 105
     def confirm_hide(self) -> None:
101
-        LOG.debug('Button right-clicked.')
106
+        LOG.debug("Button right-clicked.")
102 107
         ok = QMessageBox.warning(
103 108
             self.window(),
104 109
             "Persoon verbergen?",
@@ -132,8 +137,7 @@ class NameButtons(QWidget):
132 137
     def consumption_type_changed(self, new_id: str):
133 138
         """ Process a change of the consumption type and propagate to the
134 139
         contained buttons. """
135
-        LOG.debug('Consumption type updated in NameButtons.',
136
-                extra={'new_id': new_id})
140
+        LOG.debug("Consumption type updated in NameButtons.", extra={"new_id": new_id})
137 141
         self.active_consumption_type_id = new_id
138 142
         self.new_id_set.emit(new_id)
139 143
 
@@ -141,7 +145,7 @@ class NameButtons(QWidget):
141 145
         """ Initialize UI: build GridLayout, retrieve People and build a button
142 146
         for each. """
143 147
 
144
-        LOG.debug('Initializing NameButtons.')
148
+        LOG.debug("Initializing NameButtons.")
145 149
 
146 150
         ps = Person.get_all(True)
147 151
         num_columns = round(len(ps) / 10) + 1
@@ -170,7 +174,7 @@ class PiketMainWindow(QMainWindow):
170 174
     consumption_type_changed = Signal(str)
171 175
 
172 176
     def __init__(self) -> None:
173
-        LOG.debug('Initializing PiketMainWindow.')
177
+        LOG.debug("Initializing PiketMainWindow.")
174 178
         super().__init__()
175 179
 
176 180
         self.main_widget = None
@@ -442,40 +446,39 @@ def main() -> None:
442 446
     # Test unsettled consumptions
443 447
     status = ServerStatus.unsettled_consumptions()
444 448
 
445
-    unsettled = status['unsettled']['amount']
449
+    unsettled = status["unsettled"]["amount"]
446 450
 
447 451
     if unsettled > 0:
448
-        first = status['unsettled']['first']
449
-        first_date = first.strftime('%c')
452
+        first = status["unsettled"]["first"]
453
+        first_date = first.strftime("%c")
450 454
         ok = QMessageBox.information(
451 455
             None,
452 456
             "Onafgesloten lijst",
453 457
             f"Wil je verdergaan met een lijst met {unsettled} onafgesloten "
454 458
             f"consumpties sinds {first_date}?",
455 459
             QMessageBox.Yes,
456
-            QMessageBox.No
460
+            QMessageBox.No,
457 461
         )
458 462
         if ok == QMessageBox.No:
459 463
             main_window.show_keyboard()
460 464
             name, ok = QInputDialog.getText(
461 465
                 None,
462 466
                 "Lijst afsluiten",
463
-                "Voer een naam in voor de lijst of druk op OK. Laat de datum "
464
-                "staan.",
467
+                "Voer een naam in voor de lijst of druk op OK. Laat de datum " "staan.",
465 468
                 QLineEdit.Normal,
466
-                f"{first.strftime('%Y-%m-%d')}"
469
+                f"{first.strftime('%Y-%m-%d')}",
467 470
             )
468 471
             main_window.hide_keyboard()
469 472
 
470 473
             if name and ok:
471 474
                 settlement = Settlement.create(name)
472
-                info = [f'{item["count"]} {item["name"]}' for item in
473
-                settlement.consumption_summary.values()]
474
-                info = ', '.join(info)
475
+                info = [
476
+                    f'{item["count"]} {item["name"]}'
477
+                    for item in settlement.consumption_summary.values()
478
+                ]
479
+                info = ", ".join(info)
475 480
                 QMessageBox.information(
476
-                    None,
477
-                    "Lijst afgesloten",
478
-                    f"VO! Op deze lijst stonden: {info}"
481
+                    None, "Lijst afgesloten", f"VO! Op deze lijst stonden: {info}"
479 482
                 )
480 483
 
481 484
                 main_window = PiketMainWindow()

+ 7 - 2
piket_client/model.py

@@ -52,6 +52,7 @@ class Person(NamedTuple):
52 52
     """ Represents a Person, as retrieved from the database. """
53 53
 
54 54
     name: str
55
+    active: bool
55 56
     person_id: int = None
56 57
     consumptions: dict = {}
57 58
 
@@ -156,8 +157,11 @@ class Person(NamedTuple):
156 157
     @classmethod
157 158
     def get_all(cls, active=None) -> ["Person"]:
158 159
         """ Get all active People. """
159
-        active = int(active)
160
-        req = requests.get(urljoin(SERVER_URL, "/people"), params={"active": active})
160
+        params = {}
161
+        if active is not None:
162
+            params["active"] = int(active)
163
+
164
+        req = requests.get(urljoin(SERVER_URL, "/people"), params=params)
161 165
 
162 166
         try:
163 167
             data = req.json()
@@ -180,6 +184,7 @@ class Person(NamedTuple):
180 184
         """ Reconstruct a Person object from a dict. """
181 185
         return Person(
182 186
             name=data["name"],
187
+            active=data["active"],
183 188
             person_id=data["person_id"],
184 189
             consumptions=data["consumptions"],
185 190
         )

+ 135 - 0
piket_client/set_active.py

@@ -0,0 +1,135 @@
1
+"""
2
+Provides a helper tool to (de-)activate multiple people at once.
3
+"""
4
+
5
+import sys
6
+
7
+# pylint: disable=E0611
8
+from PySide2.QtWidgets import (
9
+    QAction,
10
+    QActionGroup,
11
+    QApplication,
12
+    QGridLayout,
13
+    QInputDialog,
14
+    QLineEdit,
15
+    QMainWindow,
16
+    QMessageBox,
17
+    QPushButton,
18
+    QSizePolicy,
19
+    QToolBar,
20
+    QWidget,
21
+)
22
+from PySide2.QtGui import QIcon
23
+from PySide2.QtCore import QObject, QSize, Qt, Signal, Slot
24
+
25
+# pylint: enable=E0611
26
+
27
+import qdarkstyle
28
+
29
+from piket_client.model import Person, ServerStatus
30
+
31
+
32
+class ActivationButton(QPushButton):
33
+    def __init__(self, person, *args, **kwargs):
34
+        super().__init__(*args, **kwargs)
35
+
36
+        self.setCheckable(True)
37
+        self.person = person
38
+
39
+        self.setText(self.person.name)
40
+        self.setChecked(self.person.active)
41
+
42
+        self.toggled.connect(self.process_toggled)
43
+
44
+    def process_toggled(self, new_state: bool) -> None:
45
+        self.person = self.person.set_active(new_state)
46
+
47
+
48
+class ActivationButtons(QWidget):
49
+    def __init__(self, *args, **kwargs) -> None:
50
+        super().__init__(*args, **kwargs)
51
+
52
+        self.layout = QGridLayout()
53
+        self.setLayout(self.layout)
54
+        self.init_ui()
55
+
56
+    def init_ui(self) -> None:
57
+        ps = Person.get_all()
58
+        num_columns = round(len(ps) / 10) + 1
59
+
60
+        for index, person in enumerate(ps):
61
+            button = ActivationButton(person, self)
62
+            self.layout.addWidget(button, index // num_columns, index % num_columns)
63
+
64
+
65
+class ActiveStateMainWindow(QMainWindow):
66
+    def __init__(self) -> None:
67
+        super().__init__()
68
+
69
+        self.toolbar = None
70
+
71
+        self.init_ui()
72
+
73
+    def init_ui(self) -> None:
74
+        """ Initialize the UI: construct main widget, toolbar. """
75
+
76
+        self.setWindowState(Qt.WindowActive | Qt.WindowFullScreen)
77
+
78
+        font_metrics = self.fontMetrics()
79
+        icon_size = font_metrics.height() * 1.45
80
+
81
+        # Toolbar
82
+        self.toolbar = QToolBar()
83
+        self.toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
84
+        self.toolbar.setIconSize(QSize(icon_size, icon_size))
85
+
86
+        # Left
87
+        self.toolbar.addAction("Afsluiten", self.quit)
88
+
89
+        self.addToolBar(self.toolbar)
90
+
91
+        # Build main widget
92
+        ps = Person.get_all()
93
+        self.main_widget = ActivationButtons()
94
+        self.setCentralWidget(self.main_widget)
95
+
96
+    def quit(self) -> None:
97
+        """ Exit immediately. """
98
+        QApplication.instance().quit()
99
+
100
+
101
+def main() -> None:
102
+    """ Main entry point of GUI client. """
103
+    app = QApplication(sys.argv)
104
+
105
+    # Set dark theme
106
+    app.setStyleSheet(qdarkstyle.load_stylesheet_pyside2())
107
+
108
+    # Enlarge font size
109
+    font = app.font()
110
+    size = font.pointSize()
111
+    font.setPointSize(size * 1.5)
112
+    app.setFont(font)
113
+
114
+    # Test connectivity
115
+    server_running, info = ServerStatus.is_server_running()
116
+
117
+    if not server_running:
118
+        LOG.critical("Could not connect to server", extra={"info": info})
119
+        QMessageBox.critical(
120
+            None,
121
+            "Help er is iets kapot",
122
+            "Kan niet starten omdat de server niet reageert, stuur een foto van "
123
+            "dit naar Maarten: " + repr(info),
124
+        )
125
+        return 1
126
+
127
+    # Load main window
128
+    main_window = ActiveStateMainWindow()
129
+    main_window.show()
130
+
131
+    app.exec_()
132
+
133
+
134
+if __name__ == "__main__":
135
+    main()

+ 1 - 0
piket_server/__init__.py

@@ -41,6 +41,7 @@ class Person(db.Model):
41 41
     def as_dict(self) -> dict:
42 42
         return {
43 43
             "person_id": self.person_id,
44
+            "active": self.active,
44 45
             "name": self.name,
45 46
             "consumptions": {
46 47
                 ct.consumption_type_id: Consumption.query.filter_by(person=self)