quizzy 0.2.0__tar.gz → 0.3.1__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {quizzy-0.2.0 → quizzy-0.3.1}/.github/workflows/ci.yaml +2 -0
- {quizzy-0.2.0 → quizzy-0.3.1}/.pre-commit-config.yaml +8 -5
- quizzy-0.3.1/CHANGELOG.md +19 -0
- {quizzy-0.2.0 → quizzy-0.3.1}/PKG-INFO +1 -1
- {quizzy-0.2.0 → quizzy-0.3.1}/pyproject.toml +1 -1
- {quizzy-0.2.0 → quizzy-0.3.1}/quizzy/app.py +57 -15
- {quizzy-0.2.0 → quizzy-0.3.1}/quizzy/quizzy.tcss +25 -5
- {quizzy-0.2.0 → quizzy-0.3.1}/uv.lock +1 -1
- quizzy-0.2.0/CHANGELOG.md +0 -9
- {quizzy-0.2.0 → quizzy-0.3.1}/.github/workflows/publish-to-pypi.yaml +0 -0
- {quizzy-0.2.0 → quizzy-0.3.1}/.gitignore +0 -0
- {quizzy-0.2.0 → quizzy-0.3.1}/LICENSE +0 -0
- {quizzy-0.2.0 → quizzy-0.3.1}/README.md +0 -0
- {quizzy-0.2.0 → quizzy-0.3.1}/assets/question-board.png +0 -0
- {quizzy-0.2.0 → quizzy-0.3.1}/examples/quizzy.yaml +0 -0
- {quizzy-0.2.0 → quizzy-0.3.1}/quizzy/__init__.py +0 -0
- {quizzy-0.2.0 → quizzy-0.3.1}/quizzy/__main__.py +0 -0
- {quizzy-0.2.0 → quizzy-0.3.1}/quizzy/models.py +0 -0
@@ -5,16 +5,19 @@ repos:
|
|
5
5
|
- id: check-yaml
|
6
6
|
- id: end-of-file-fixer
|
7
7
|
- id: trailing-whitespace
|
8
|
-
- repo: https://github.com/psf/black
|
9
|
-
rev: "24.10.0"
|
10
|
-
hooks:
|
11
|
-
- id: black
|
12
8
|
- repo: https://github.com/charliermarsh/ruff-pre-commit
|
13
9
|
# Ruff version.
|
14
10
|
rev: "v0.8.3"
|
15
11
|
hooks:
|
16
|
-
|
12
|
+
- id: ruff
|
13
|
+
args: [ --fix ]
|
14
|
+
- id: ruff-format
|
17
15
|
- repo: https://github.com/pycqa/isort
|
18
16
|
rev: "5.13.2"
|
19
17
|
hooks:
|
20
18
|
- id: isort
|
19
|
+
- repo: https://github.com/astral-sh/uv-pre-commit
|
20
|
+
rev: 0.5.10
|
21
|
+
hooks:
|
22
|
+
# Update the uv lockfile
|
23
|
+
- id: uv-lock
|
@@ -0,0 +1,19 @@
|
|
1
|
+
|
2
|
+
# Changelog
|
3
|
+
|
4
|
+
## v0.3.1
|
5
|
+
|
6
|
+
* Fixed the lockfile for this version
|
7
|
+
|
8
|
+
## v0.3.0
|
9
|
+
|
10
|
+
* Add *Escape* keybinding to dismiss question and answer modals
|
11
|
+
* Add score modifier buttons
|
12
|
+
|
13
|
+
## v0.2.0
|
14
|
+
|
15
|
+
* Added support for Markdown syntax in questions and answers
|
16
|
+
|
17
|
+
## v0.1.0
|
18
|
+
|
19
|
+
* Initial release with basic functionality
|
@@ -3,10 +3,13 @@ from __future__ import annotations
|
|
3
3
|
import argparse
|
4
4
|
import pathlib
|
5
5
|
|
6
|
-
from textual import app, containers, log, message, reactive, screen, widgets
|
6
|
+
from textual import app, binding, containers, log, message, reactive, screen, widgets
|
7
7
|
|
8
8
|
from quizzy import __version__, models
|
9
9
|
|
10
|
+
NoCorrectAnswerType = type("NoCorrectAnswerType", (object,), {})
|
11
|
+
NoCorrectAnswer = NoCorrectAnswerType()
|
12
|
+
|
10
13
|
|
11
14
|
def get_arg_parser() -> argparse.ArgumentParser:
|
12
15
|
parser = argparse.ArgumentParser(prog=__name__.split(".")[0], description="A terminal quiz app")
|
@@ -15,9 +18,16 @@ def get_arg_parser() -> argparse.ArgumentParser:
|
|
15
18
|
return parser
|
16
19
|
|
17
20
|
|
18
|
-
|
21
|
+
QuestionScreenResult = models.Team | NoCorrectAnswerType | None
|
22
|
+
|
23
|
+
|
24
|
+
class AnswerScreen(screen.ModalScreen[QuestionScreenResult], can_focus=True):
|
19
25
|
NOONE_ANSWERED_ID = "__noone-answered"
|
20
26
|
|
27
|
+
BINDINGS = [
|
28
|
+
binding.Binding("escape", "no_correct_answer", "Dismiss", key_display="Esc"),
|
29
|
+
]
|
30
|
+
|
21
31
|
def __init__(self, category: str, question: models.Question, teams: list[models.Team]) -> None:
|
22
32
|
super().__init__(classes="question-answer-screen")
|
23
33
|
self.category = category
|
@@ -32,7 +42,7 @@ class AnswerScreen(screen.ModalScreen[models.Team | None]):
|
|
32
42
|
answer_widget = widgets.Markdown(self.question.answer, id="answer")
|
33
43
|
answer_widget.border_title = "Answer"
|
34
44
|
|
35
|
-
|
45
|
+
who_answered = containers.HorizontalGroup(
|
36
46
|
*[
|
37
47
|
containers.Vertical(widgets.Button(team.name, id=team_id, variant="primary"))
|
38
48
|
for team_id, team in self.teams.items()
|
@@ -40,12 +50,12 @@ class AnswerScreen(screen.ModalScreen[models.Team | None]):
|
|
40
50
|
id="who-answered",
|
41
51
|
classes="horizontal-100",
|
42
52
|
)
|
43
|
-
|
53
|
+
who_answered.border_title = "Who Answered Correctly?"
|
44
54
|
|
45
55
|
container = containers.Grid(
|
46
56
|
question_widget,
|
47
57
|
answer_widget,
|
48
|
-
|
58
|
+
who_answered,
|
49
59
|
containers.Horizontal(
|
50
60
|
widgets.Button(
|
51
61
|
"😭 No one answered correctly 😭", id=self.NOONE_ANSWERED_ID, variant="error", classes="button-100"
|
@@ -57,18 +67,25 @@ class AnswerScreen(screen.ModalScreen[models.Team | None]):
|
|
57
67
|
)
|
58
68
|
|
59
69
|
container.border_title = f"{self.category} - {self.question.value} points"
|
70
|
+
yield widgets.Footer()
|
60
71
|
yield container
|
61
72
|
|
73
|
+
def action_no_correct_answer(self) -> None:
|
74
|
+
self.dismiss(NoCorrectAnswer)
|
75
|
+
|
62
76
|
def on_button_pressed(self, event: widgets.Button.Pressed) -> None:
|
63
77
|
if event.button.id == self.NOONE_ANSWERED_ID:
|
64
|
-
self.dismiss(
|
78
|
+
self.dismiss(NoCorrectAnswer)
|
65
79
|
elif event.button.id in self.teams:
|
66
80
|
team = self.teams[event.button.id]
|
67
81
|
self.dismiss(team)
|
68
82
|
|
69
83
|
|
70
|
-
class QuestionScreen(screen.ModalScreen[
|
84
|
+
class QuestionScreen(screen.ModalScreen[QuestionScreenResult], can_focus=True):
|
71
85
|
SHOW_ANSWER_ID = "show-answer"
|
86
|
+
BINDINGS = [
|
87
|
+
binding.Binding("escape", "dismiss(None)", "Dismiss"),
|
88
|
+
]
|
72
89
|
|
73
90
|
def __init__(self, category: str, question: models.Question, teams: list[models.Team]) -> None:
|
74
91
|
super().__init__(classes="question-answer-screen")
|
@@ -91,17 +108,22 @@ class QuestionScreen(screen.ModalScreen[models.Team | None]):
|
|
91
108
|
)
|
92
109
|
|
93
110
|
container.border_title = f"{self.category} - {self.question.value} points"
|
111
|
+
yield widgets.Footer()
|
94
112
|
yield container
|
95
113
|
|
96
114
|
def on_button_pressed(self, event: widgets.Button.Pressed) -> None:
|
97
|
-
def dismiss(team:
|
115
|
+
def dismiss(team: QuestionScreenResult) -> None:
|
98
116
|
self.dismiss(team)
|
99
117
|
|
100
118
|
if event.button.id == self.SHOW_ANSWER_ID:
|
119
|
+
event.stop()
|
101
120
|
self.app.push_screen(AnswerScreen(self.category, self.question, self.teams), dismiss)
|
102
121
|
|
103
122
|
|
104
|
-
class TeamScore(containers.
|
123
|
+
class TeamScore(containers.Horizontal):
|
124
|
+
MODIFIER_BUTTON_VALUE = 100
|
125
|
+
_ADD_BUTTON_ID = f"add-{MODIFIER_BUTTON_VALUE}"
|
126
|
+
_SUBTRACT_BUTTON_ID = f"subtract-{MODIFIER_BUTTON_VALUE}"
|
105
127
|
score = reactive.reactive(0, recompose=True)
|
106
128
|
|
107
129
|
def __init__(self, team: models.Team) -> None:
|
@@ -112,6 +134,22 @@ class TeamScore(containers.Vertical):
|
|
112
134
|
|
113
135
|
def compose(self) -> app.ComposeResult:
|
114
136
|
yield widgets.Static(str(self.score))
|
137
|
+
yield containers.Horizontal(
|
138
|
+
widgets.Button("+ 100", id=self._ADD_BUTTON_ID, variant="success"),
|
139
|
+
widgets.Button("- 100", id=self._SUBTRACT_BUTTON_ID, variant="error"),
|
140
|
+
classes="modifier-buttons-container",
|
141
|
+
)
|
142
|
+
|
143
|
+
def on_button_pressed(self, event: widgets.Button.Pressed) -> None:
|
144
|
+
if event.button.id == self._ADD_BUTTON_ID:
|
145
|
+
self.score += self.MODIFIER_BUTTON_VALUE
|
146
|
+
event.stop()
|
147
|
+
elif event.button.id == self._SUBTRACT_BUTTON_ID:
|
148
|
+
if self.score <= self.MODIFIER_BUTTON_VALUE:
|
149
|
+
self.score = 0
|
150
|
+
else:
|
151
|
+
self.score -= self.MODIFIER_BUTTON_VALUE
|
152
|
+
event.stop()
|
115
153
|
|
116
154
|
def watch_score(self, score: int) -> None:
|
117
155
|
"""
|
@@ -152,13 +190,14 @@ class QuestionButton(widgets.Button):
|
|
152
190
|
self.disabled = question.answered
|
153
191
|
|
154
192
|
def on_click(self) -> None:
|
155
|
-
|
156
|
-
self.disabled = True
|
157
|
-
self.question.answered = True
|
158
|
-
|
159
|
-
def wait_for_result(team: models.Team | None) -> None:
|
193
|
+
def wait_for_result(team: QuestionScreenResult) -> None:
|
160
194
|
if team is None:
|
161
|
-
|
195
|
+
return
|
196
|
+
# First, disable the button to prevent multiple clicks
|
197
|
+
self.disabled = True
|
198
|
+
self.question.answered = True
|
199
|
+
if isinstance(team, NoCorrectAnswerType):
|
200
|
+
log("question-button: No one answered the question")
|
162
201
|
else:
|
163
202
|
log(f"question-button: {team.id} answered the question")
|
164
203
|
self.post_message(self.Answered(team, self.question.value))
|
@@ -206,3 +245,6 @@ class QuizzyApp(app.App[None]):
|
|
206
245
|
|
207
246
|
def on_question_button_answered(self, event: QuestionButton.Answered) -> None:
|
208
247
|
self.scoreboard_widget.update_team_score(event.team.id, event.value)
|
248
|
+
|
249
|
+
def on_mount(self) -> None:
|
250
|
+
self.theme = "textual-light"
|
@@ -1,8 +1,28 @@
|
|
1
1
|
TeamScore {
|
2
|
-
border:
|
2
|
+
border: round $primary;
|
3
3
|
align: center top;
|
4
4
|
height: 3;
|
5
5
|
margin: 1;
|
6
|
+
|
7
|
+
Static {
|
8
|
+
max-width: 50%;
|
9
|
+
}
|
10
|
+
|
11
|
+
Horizontal.modifier-buttons-container {
|
12
|
+
align: right middle;
|
13
|
+
|
14
|
+
Button {
|
15
|
+
margin: 0 2;
|
16
|
+
padding: 0;
|
17
|
+
min-width: 8;
|
18
|
+
border: none;
|
19
|
+
width: 8;
|
20
|
+
&:focus {
|
21
|
+
/* Disable reversing for text of focussed buttons in the team score row */
|
22
|
+
text-style: bold;
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
6
26
|
}
|
7
27
|
|
8
28
|
|
@@ -15,20 +35,20 @@ TeamScore {
|
|
15
35
|
height: 80%;
|
16
36
|
min-height: 40;
|
17
37
|
padding: 0 2;
|
18
|
-
border:
|
38
|
+
border: round $primary;
|
19
39
|
background: $surface;
|
20
40
|
content-align: center middle;
|
21
41
|
|
22
42
|
#question {
|
23
43
|
content-align: center middle;
|
24
44
|
padding: 2;
|
25
|
-
border:
|
45
|
+
border: round $foreground 80%;
|
26
46
|
}
|
27
47
|
|
28
48
|
#answer {
|
29
49
|
content-align: center middle;
|
30
50
|
padding: 2;
|
31
|
-
border:
|
51
|
+
border: round $success 80%;
|
32
52
|
|
33
53
|
}
|
34
54
|
}
|
@@ -59,7 +79,7 @@ AnswerScreen {
|
|
59
79
|
grid-rows: 40% 40% 5 4;
|
60
80
|
|
61
81
|
#who-answered {
|
62
|
-
border:
|
82
|
+
border: round $foreground 80%;
|
63
83
|
Button {
|
64
84
|
margin: 0 1;
|
65
85
|
width: 100%;
|
quizzy-0.2.0/CHANGELOG.md
DELETED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|