Skip to content

Commit 8398333

Browse files
author
MarcoBenelli
committed
Add Makefile and possibility to delete a deck
The Makefile is compatible with Linux, macOS and Windows To delete a deck there is now an option in the file menu Also added a way to quit from the file menu
1 parent bc0a962 commit 8398333

File tree

8 files changed

+148
-61
lines changed

8 files changed

+148
-61
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
**/__pycache__
22
src/img/fugue-icons-3.5.6
3+
build
4+
dist
5+
*.spec
36
.vscode

Makefile

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
ifeq ($(OS),Windows_NT)
2+
pathsep = ;
3+
options = --onefile --windowed
4+
else
5+
pathsep = :
6+
UNAME := $(shell uname)
7+
ifeq ($(UNAME),Darwin)
8+
options = --windowed --name 'Study and Repeat'
9+
else
10+
options = --onefile
11+
endif
12+
endif
13+
14+
dist/study_and_repeat : src/**/*.py
15+
pyinstaller $(options) --icon src/img/favicon.ico \
16+
--add-data 'src/img/fugue-icons-3.5.6/icons-shadowless/*.png$(pathsep)src/img/fugue-icons-3.5.6/icons-shadowless' \
17+
--add-data 'src/img/favicon.ico$(pathsep)src/img' \
18+
src/study_and_repeat.py
19+
20+
.PHONY : clean
21+
clean :
22+
ifeq ($(OS),Windows_NT)
23+
-rmdir /s /q build dist
24+
-erase .\*.spec
25+
else
26+
rm --recursive --force build dist ./*.spec
27+
endif

src/model/deck.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,14 @@ def calculate_delay(self, correctness: bool) -> None:
9292
self._cards_strengths[c.identifier] = 1
9393
self._queues[0].append(c)
9494

95-
def dump(self):
96-
with open(f'{config.DECKS_DIR}{self.name}/{config.DECK_FILE}', 'wb') as f:
95+
def dump(self) -> None:
96+
with open(f'{config.DECKS_DIR}{self.name}/{config.DECK_FILE}',
97+
'wb') as f:
9798
pickle.dump(self, f)
9899

100+
def delete(self) -> None:
101+
shutil.rmtree(f'{config.DECKS_DIR}{self.name}')
102+
99103

100104
def load_deck(filepath: str) -> Deck:
101105
with open(filepath, 'rb') as f:

src/view/editor_widget.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,9 @@ class EditorWidget(secondary_widget.SecondaryWidget):
1010
question_prefix = '- '
1111
proportion = 6
1212

13-
def __init__(self, d: deck.Deck, *args, **kwargs) -> None:
13+
def __init__(self, *args, **kwargs) -> None:
1414
super().__init__(*args, **kwargs)
1515

16-
self.window().setWindowTitle(f'Study and Repeat - {d.name}')
17-
18-
self._deck = d
1916
h_layout = QtWidgets.QHBoxLayout()
2017

2118
left_widget = QtWidgets.QWidget()

src/view/home_widget.py

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,41 @@
99

1010
class HomeWidget(QtWidgets.QWidget):
1111

12-
def __init__(self, *args, **kwargs):
12+
def __init__(self, *args, **kwargs) -> None:
1313
super().__init__(*args, **kwargs)
1414

15-
horizontal_layout = QtWidgets.QHBoxLayout(self)
15+
outer_layout = QtWidgets.QVBoxLayout(self)
16+
label = QtWidgets.QLabel('Your decks')
17+
label.setAlignment(QtCore.Qt.AlignCenter)
18+
font = label.font()
19+
font.setBold(True)
20+
font.setPointSize(24)
21+
label.setFont(font)
22+
outer_layout.addWidget(label)
23+
1624
self._scroll_area = QtWidgets.QScrollArea(self)
1725
self._scroll_area.setWidgetResizable(True)
18-
self._scroll_area_widget_contents = QtWidgets.QWidget()
19-
self._vertical_layout = QtWidgets.QVBoxLayout(
20-
self._scroll_area_widget_contents)
21-
self._vertical_layout.setAlignment(QtCore.Qt.AlignCenter)
2226
self.populate_list()
23-
horizontal_layout.addWidget(self._scroll_area)
27+
outer_layout.addWidget(self._scroll_area)
2428

2529
def populate_list(self) -> None:
30+
self._scroll_area_widget_contents = QtWidgets.QWidget()
31+
self._inner_layout = QtWidgets.QVBoxLayout(
32+
self._scroll_area_widget_contents)
33+
self._inner_layout.setAlignment(QtCore.Qt.AlignCenter)
2634
for deck_name in sorted(os.listdir(config.DECKS_DIR)):
2735
if deck_name.startswith('.'):
2836
continue
29-
widget = QtWidgets.QWidget(self._scroll_area_widget_contents)
30-
horizontal_layout = QtWidgets.QHBoxLayout(widget)
37+
frame = QtWidgets.QFrame(self._scroll_area_widget_contents)
38+
frame.setFrameStyle(QtWidgets.QFrame.Box)
39+
horizontal_layout = QtWidgets.QHBoxLayout(frame)
3140
horizontal_layout.setAlignment(QtCore.Qt.AlignCenter)
32-
line_edit = QtWidgets.QLineEdit(deck_name, widget)
33-
line_edit.setReadOnly(True)
34-
line_edit.setMaximumWidth(400)
35-
horizontal_layout.addWidget(line_edit)
41+
label = QtWidgets.QLabel(deck_name, frame)
42+
label.setFixedWidth(400)
43+
font = label.font()
44+
font.setPointSize(12)
45+
label.setFont(font)
46+
horizontal_layout.addWidget(label)
3647
study_btn = QtWidgets.QPushButton(
3748
QtGui.QIcon(f'{config.ICONS_DIR}book-open.png'), '')
3849
study_btn.setFixedWidth(32)
@@ -43,7 +54,7 @@ def populate_list(self) -> None:
4354
edit_btn.setFixedWidth(32)
4455
edit_btn.released.connect(lambda d=deck_name: self.edit_deck(d))
4556
horizontal_layout.addWidget(edit_btn)
46-
self._vertical_layout.addWidget(widget)
57+
self._inner_layout.addWidget(frame)
4758
self._scroll_area.setWidget(self._scroll_area_widget_contents)
4859

4960
def edit_deck(self, name: str) -> None:
@@ -56,5 +67,41 @@ def study_deck(self, name: str) -> None:
5667
f'{config.DECKS_DIR}{name}/{config.DECK_FILE}'),
5768
parent=self.window())
5869

70+
def delete_deck(self) -> None:
71+
dlg = SelectDeckDialog('delete', self)
72+
if dlg.exec():
73+
dlg.deck.delete()
74+
self.populate_list()
75+
5976
def exit(self) -> None:
6077
pass
78+
79+
80+
class SelectDeckDialog(QtWidgets.QDialog):
81+
82+
def __init__(self, action: str, *args, **kwargs) -> None:
83+
super().__init__(*args, **kwargs)
84+
self.setWindowTitle(f'Select deck to {action}')
85+
self.resize(400, 150)
86+
self.setMinimumSize(self.size())
87+
layout = QtWidgets.QVBoxLayout()
88+
self.setLayout(layout)
89+
90+
self._combo_box = QtWidgets.QComboBox()
91+
for deck_name in sorted(os.listdir(config.DECKS_DIR)):
92+
if deck_name.startswith('.'):
93+
continue
94+
self._combo_box.addItem(deck_name)
95+
layout.addWidget(self._combo_box)
96+
97+
q_btn = QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel
98+
button_box = QtWidgets.QDialogButtonBox(q_btn, parent=self)
99+
button_box.accepted.connect(self.accept)
100+
button_box.rejected.connect(self.reject)
101+
layout.addWidget(button_box)
102+
103+
def accept(self, *args, **kwargs) -> None:
104+
super().accept()
105+
self.deck = deck.load_deck(
106+
f'{config.DECKS_DIR}{self._combo_box.currentText()}/'
107+
+ config.DECK_FILE)

src/view/main_window.py

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,52 +20,55 @@ def __init__(self, *args, **kwargs) -> None:
2020
menubar = QtWidgets.QMenuBar(self)
2121

2222
menu_file = QtWidgets.QMenu(menubar)
23-
menu_export_deck = QtWidgets.QMenu(menu_file)
23+
# menu_export_deck = QtWidgets.QMenu(menu_file)
2424
self.setMenuBar(menubar)
25-
action_new_deck = QtWidgets.QAction(self)
25+
self.action_new_deck = QtWidgets.QAction(self)
2626
action_quit = QtWidgets.QAction(self)
27-
action_import_deck = QtWidgets.QAction(self)
28-
action_local_export = QtWidgets.QAction(self)
29-
action_remote_export = QtWidgets.QAction(self)
27+
# action_import_deck = QtWidgets.QAction(self)
28+
# action_local_export = QtWidgets.QAction(self)
29+
# action_remote_export = QtWidgets.QAction(self)
3030
action_delete_deck = QtWidgets.QAction(self)
31-
menu_export_deck.addAction(action_local_export)
32-
menu_export_deck.addAction(action_remote_export)
33-
menu_file.addAction(action_new_deck)
34-
menu_file.addAction(action_import_deck)
35-
menu_file.addAction(menu_export_deck.menuAction())
31+
# menu_export_deck.addAction(action_local_export)
32+
# menu_export_deck.addAction(action_remote_export)
33+
menu_file.addAction(self.action_new_deck)
34+
# menu_file.addAction(action_import_deck)
35+
# menu_file.addAction(menu_export_deck.menuAction())
3636
menu_file.addAction(action_delete_deck)
3737
menu_file.addAction(action_quit)
3838
menubar.addAction(menu_file.menuAction())
39-
menu_help = QtWidgets.QMenu(menubar)
40-
action_about = QtWidgets.QAction(self)
41-
menu_help.addAction(action_about)
42-
menubar.addAction(menu_help.menuAction())
39+
# menu_help = QtWidgets.QMenu(menubar)
40+
# action_about = QtWidgets.QAction(self)
41+
# menu_help.addAction(action_about)
42+
# menubar.addAction(menu_help.menuAction())
4343

4444
menu_file.setTitle(QtCore.QCoreApplication.translate(
4545
'Study and Repeat', 'File'))
46-
menu_export_deck.setTitle(QtCore.QCoreApplication.translate(
47-
'Study and Repeat', 'Export deck'))
48-
menu_help.setTitle(QtCore.QCoreApplication.translate(
49-
'Study and Repeat', 'Help'))
50-
action_new_deck.setText(QtCore.QCoreApplication.translate(
46+
# menu_export_deck.setTitle(QtCore.QCoreApplication.translate(
47+
# 'Study and Repeat', 'Export deck'))
48+
# menu_help.setTitle(QtCore.QCoreApplication.translate(
49+
# 'Study and Repeat', 'Help'))
50+
self.action_new_deck.setText(QtCore.QCoreApplication.translate(
5151
'Study and Repeat', 'New deck'))
52-
action_about.setText(QtCore.QCoreApplication.translate(
53-
'Study and Repeat', 'About'))
52+
# action_about.setText(QtCore.QCoreApplication.translate(
53+
# 'Study and Repeat', 'About'))
5454
action_quit.setText(QtCore.QCoreApplication.translate(
5555
'Study and Repeat', 'Quit'))
56-
action_import_deck.setText(QtCore.QCoreApplication.translate(
57-
'Study and Repeat', 'Import deck'))
58-
action_local_export.setText(QtCore.QCoreApplication.translate(
59-
'Study and Repeat', 'Local export'))
60-
action_remote_export.setText(QtCore.QCoreApplication.translate(
61-
'Study and Repeat', 'Remote export'))
56+
# action_import_deck.setText(QtCore.QCoreApplication.translate(
57+
# 'Study and Repeat', 'Import deck'))
58+
# action_local_export.setText(QtCore.QCoreApplication.translate(
59+
# 'Study and Repeat', 'Local export'))
60+
# action_remote_export.setText(QtCore.QCoreApplication.translate(
61+
# 'Study and Repeat', 'Remote export'))
6262
action_delete_deck.setText(QtCore.QCoreApplication.translate(
6363
'Study and Repeat', 'Delete deck'))
6464

65-
action_new_deck.triggered.connect(self.create_deck)
65+
self.action_new_deck.triggered.connect(self.create_deck)
66+
action_quit.triggered.connect(self.close)
67+
action_delete_deck.triggered.connect(
68+
lambda: self.centralWidget().delete_deck())
6669

6770
def create_deck(self) -> None:
68-
dlg = CustomDialog(self)
71+
dlg = NewDeckDialog(self)
6972
if dlg.exec():
7073
editor_widget.EditorWidget(dlg.deck, parent=self)
7174

@@ -74,7 +77,7 @@ def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
7477
return super().closeEvent(a0)
7578

7679

77-
class CustomDialog(QtWidgets.QDialog):
80+
class NewDeckDialog(QtWidgets.QDialog):
7881

7982
def __init__(self, *args, **kwargs) -> None:
8083
super().__init__(*args, **kwargs)
@@ -85,7 +88,7 @@ def __init__(self, *args, **kwargs) -> None:
8588
self.setLayout(layout)
8689

8790
self._error_label = QtWidgets.QLabel('The only permitted characters are '
88-
+ 'a..z, A..Z, 0..9 and _')
91+
+ 'a-z, A-Z, 0-9 and _')
8992
self._error_label.setStyleSheet("color: #ff0000")
9093
layout.addWidget(self._error_label)
9194
self._error_label.hide()

src/view/secondary_widget.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,38 @@
1-
2-
31
from PyQt5 import QtWidgets
42
from PyQt5 import QtWidgets, QtGui
53

64
from view import home_widget
5+
from model import deck
76
import config
87

98

109
class SecondaryWidget(QtWidgets.QWidget):
1110

12-
def __init__(self, *args, **kwargs) -> None:
11+
def __init__(self, d: deck.Deck, *args, **kwargs) -> None:
1312
super().__init__(*args, **kwargs)
13+
self._deck = d
14+
self.window().setWindowTitle(f'Study and Repeat - {self._deck.name}')
1415

1516
self._layout = QtWidgets.QVBoxLayout()
1617
self.setLayout(self._layout)
1718
back_btn = QtWidgets.QPushButton(QtGui.QIcon(
18-
f'{config.ICONS_DIR}home.png'), '')
19+
f'{config.ICONS_DIR}home.png'), '')
1920
back_btn.setFixedWidth(32)
2021
self._layout.addWidget(back_btn)
2122
back_btn.released.connect(self.back_home)
2223
self._central_widget = QtWidgets.QWidget()
2324
self._layout.addWidget(self._central_widget)
24-
self.window().setCentralWidget(self)
25+
self.window().setCentralWidget(self)
26+
self.window().action_new_deck.setVisible(False)
2527

2628
def back_home(self) -> None:
29+
self.window().action_new_deck.setVisible(True)
30+
self.window().setCentralWidget(home_widget.HomeWidget())
31+
self.window().setWindowTitle('Study and Repeat')
32+
self.exit()
33+
34+
def delete_deck(self) -> None:
35+
self._deck.delete()
36+
self.window().action_new_deck.setVisible(True)
2737
self.window().setCentralWidget(home_widget.HomeWidget())
2838
self.window().setWindowTitle('Study and Repeat')
29-
self.exit()

src/view/study_widget.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,9 @@
77

88
class StudyWidget(secondary_widget.SecondaryWidget):
99

10-
def __init__(self, d: deck.Deck, *args, **kwargs) -> None:
10+
def __init__(self, *args, **kwargs) -> None:
1111
super().__init__(*args, **kwargs)
1212

13-
self.window().setWindowTitle(f'Study and Repeat - {d.name}')
14-
15-
self._deck = d
1613
v_layout = QtWidgets.QVBoxLayout()
1714
self._question_text = QtWidgets.QLineEdit()
1815
self._question_text.setReadOnly(True)

0 commit comments

Comments
 (0)