MIL-011 plan and design: menu bar
Milestone MIL-011 with stories US-001.09 to US-001.12, and the documents updated for the menu bar: BC-001, PP-001, US-001, UC-001, SSD-001, OC-001, SD-001, DCD-001, DICT-001 and the wireframe. Review records RC-056 to RC-065, all Go (autonomous mode, not independent). Task: MIL-011#1
This commit is contained in:
+115
-3
@@ -9,8 +9,8 @@
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [c3fbcbc] |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added chooseLevel; startStudySession returns the levels | [0b983b7] |
|
||||
| 2026-10-14 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added chooseLevel; startStudySession returns the levels | [0b983b7] |
|
||||
| 2026-10-15 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added the menu contracts | pending |
|
||||
|
||||
---
|
||||
|
||||
@@ -93,6 +93,119 @@ The turn-over of the card after 3000 ms is started by the system's own timer, no
|
||||
| --- | --- |
|
||||
| `current_card` is `None` (no card is shown) | Nothing is changed and nothing is stored |
|
||||
|
||||
## Contract: openWordList
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Operation | `openWordList(path: Path): tuple[Level, ...]` |
|
||||
| Traces to | `openWordList` in [SSD-001] |
|
||||
| Domain Model concepts | Word List, Study Session, Words To Learn ([DM-001]); IT terms `Vocabulary`, `StudySession`, `Deck` ([DICT-001]) |
|
||||
|
||||
**Preconditions**
|
||||
|
||||
- `path` names an existing file.
|
||||
|
||||
**Postconditions**
|
||||
|
||||
- The `Vocabulary` of `path` is the word list in use and its progress file (`words_to_learn.csv` for `ms-da.csv`, else `words_to_learn_<name>.csv` in the data folder) is the progress in use.
|
||||
- Any earlier `StudySession` was dropped and the levels are returned; no card is shown until a level is chosen.
|
||||
|
||||
**Exceptions**
|
||||
|
||||
| Condition (failing precondition) | Outcome |
|
||||
| --- | --- |
|
||||
| The file does not exist or is not a word list (no header of two language codes, a row that is not two cells, or no card) | `VocabularyNotFoundError` or `VocabularyFormatError` is raised; the earlier word list and session stay in use and no file is changed |
|
||||
|
||||
## Contract: changeLevel
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Operation | `changeLevel(): tuple[Level, ...]` |
|
||||
| Traces to | `changeLevel` in [SSD-001] |
|
||||
| Domain Model concepts | Level, Study Session ([DM-001]); IT terms `Level`, `StudySession` ([DICT-001]) |
|
||||
|
||||
**Preconditions**
|
||||
|
||||
- A word list is in use.
|
||||
|
||||
**Postconditions**
|
||||
|
||||
- The pending flip timer was cancelled, the `StudySession` was dropped and the levels are returned; the progress file was not changed.
|
||||
|
||||
**Exceptions**
|
||||
|
||||
| Condition (failing precondition) | Outcome |
|
||||
| --- | --- |
|
||||
| None | – |
|
||||
|
||||
## Contract: resetWordList
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Operation | `resetWordList(): tuple[Level, ...]` |
|
||||
| Traces to | `resetWordList` in [SSD-001] |
|
||||
| Domain Model concepts | Words To Learn, Word List ([DM-001]); IT terms `Deck`, `Vocabulary` ([DICT-001]) |
|
||||
|
||||
**Preconditions**
|
||||
|
||||
- A word list is in use and the Learner confirmed.
|
||||
|
||||
**Postconditions**
|
||||
|
||||
- The progress file of the word list in use does not exist; the word list file and the progress files of other word lists are unchanged.
|
||||
- The `StudySession` was dropped and the levels are returned; the next session starts from a `Deck` of the whole `Vocabulary`.
|
||||
|
||||
**Exceptions**
|
||||
|
||||
| Condition (failing precondition) | Outcome |
|
||||
| --- | --- |
|
||||
| The progress file does not exist | Nothing is deleted and no error is raised |
|
||||
| The progress file cannot be deleted (`OSError`) | The error is logged and shown to the Learner; the earlier session stays |
|
||||
|
||||
## Contract: showContact
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Operation | `showContact(): tuple[str, str, str]` |
|
||||
| Traces to | `showContact` in [SSD-001] |
|
||||
| Domain Model concepts | none (author information, outside the domain) |
|
||||
|
||||
**Preconditions**
|
||||
|
||||
- None.
|
||||
|
||||
**Postconditions**
|
||||
|
||||
- The name, the title and the link of the author are returned and the link was opened in the web browser.
|
||||
|
||||
**Exceptions**
|
||||
|
||||
| Condition (failing precondition) | Outcome |
|
||||
| --- | --- |
|
||||
| No web browser can be started | The failure is logged; nothing else changes |
|
||||
|
||||
## Contract: exit
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Operation | `exit(): None` |
|
||||
| Traces to | `exit` in [SSD-001] |
|
||||
| Domain Model concepts | Study Session ([DM-001]); IT term `StudySession` ([DICT-001]) |
|
||||
|
||||
**Preconditions**
|
||||
|
||||
- None.
|
||||
|
||||
**Postconditions**
|
||||
|
||||
- The pending flip timer was cancelled, the window was closed and the program ended with exit code 0; the progress file is as it was after the last `markKnown`.
|
||||
|
||||
**Exceptions**
|
||||
|
||||
| Condition (failing precondition) | Outcome |
|
||||
| --- | --- |
|
||||
| None | – |
|
||||
|
||||
## Contract: markUnknown
|
||||
|
||||
| Item | Value |
|
||||
@@ -124,5 +237,4 @@ The turn-over of the card after 3000 ms is started by the system's own timer, no
|
||||
[DM-001]: ../domain-model.md
|
||||
[DICT-001]: ../dictionary.md
|
||||
[SD-001]: ./sd.md
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
[0b983b7]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/0b983b7fdadf6958717c1d0227d0f2ebe037f7b1
|
||||
|
||||
+88
-3
@@ -9,8 +9,8 @@
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [c3fbcbc] |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added the sequences startStudySession (levels) and chooseLevel (level filter) | [0b983b7] |
|
||||
| 2026-10-14 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added the sequences startStudySession (levels) and chooseLevel (level filter) | [0b983b7] |
|
||||
| 2026-10-15 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added the sequences openWordList and resetWordList | pending |
|
||||
|
||||
---
|
||||
|
||||
@@ -109,6 +109,92 @@ deactivate S
|
||||
|
||||
The composition root only wires; the level selects, the deck holds, the session coordinates; no object receives all messages.
|
||||
|
||||
## Sequence: openWordList
|
||||
|
||||
**Realizes:** `openWordList` in [OC-001]
|
||||
|
||||
### Diagram
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
participant ":MenuView" as V
|
||||
participant ":Application" as A
|
||||
participant ":CsvVocabularyRepository" as VR
|
||||
V -> A : open_word_list(path)
|
||||
activate A
|
||||
create VR
|
||||
A -> VR : create(path)
|
||||
A -> VR : load()
|
||||
alt file is a word list
|
||||
VR --> A : vocabulary
|
||||
A -> A : drop session, use progress file of path
|
||||
A --> V : levels
|
||||
else file is refused
|
||||
VR --> A : VocabularyError
|
||||
A --> V : message, earlier list stays
|
||||
end
|
||||
deactivate A
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Pattern Annotations
|
||||
|
||||
| Pattern (GRASP / GoF) | Applied to | Rationale |
|
||||
| --- | --- | --- |
|
||||
| Controller | `Application` | Receives the menu command and coordinates the repositories and the session |
|
||||
| Repository | `CsvVocabularyRepository` | The file format stays in the adapter |
|
||||
|
||||
### Postcondition Coverage
|
||||
|
||||
| Postcondition (from contract) | Satisfied by message |
|
||||
| --- | --- |
|
||||
| The vocabulary and the progress file of `path` are in use | `load()`, `use progress file of path` |
|
||||
| The earlier session was dropped and the levels are returned | `drop session`, `levels` |
|
||||
| A refused file leaves everything as it was | the `else` branch |
|
||||
|
||||
### Responsibility Check
|
||||
|
||||
The view forwards the command; the application validates through the repository before it replaces anything.
|
||||
|
||||
## Sequence: resetWordList
|
||||
|
||||
**Realizes:** `resetWordList` in [OC-001]
|
||||
|
||||
### Diagram
|
||||
|
||||
```plantuml
|
||||
@startuml
|
||||
participant ":MenuView" as V
|
||||
participant ":Application" as A
|
||||
participant ":CsvProgressRepository" as PR
|
||||
V -> A : reset_word_list()
|
||||
activate A
|
||||
A -> PR : reset()
|
||||
PR --> A : done
|
||||
A -> A : drop session
|
||||
A --> V : levels
|
||||
deactivate A
|
||||
@enduml
|
||||
```
|
||||
|
||||
### Pattern Annotations
|
||||
|
||||
| Pattern (GRASP / GoF) | Applied to | Rationale |
|
||||
| --- | --- | --- |
|
||||
| Controller | `Application` | Sequences the reset and the return to the level screen |
|
||||
| Repository | `CsvProgressRepository` | Knows where the progress file is |
|
||||
|
||||
### Postcondition Coverage
|
||||
|
||||
| Postcondition (from contract) | Satisfied by message |
|
||||
| --- | --- |
|
||||
| The progress file of the word list in use does not exist | `reset()` |
|
||||
| The session was dropped and the levels are returned | `drop session`, `levels` |
|
||||
|
||||
### Responsibility Check
|
||||
|
||||
The confirmation is asked by the view before `reset_word_list` is called; the repository deletes only its own file.
|
||||
|
||||
## Sequence: markKnown
|
||||
|
||||
**Realizes:** `markKnown` in [OC-001]
|
||||
@@ -209,5 +295,4 @@ Same as `markKnown`; the session is the only object that speaks and draws.
|
||||
[OC-001]: ./oc.md
|
||||
[DCD-001]: ../dcd.md
|
||||
[DICT-001]: ../dictionary.md
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
[0b983b7]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/0b983b7fdadf6958717c1d0227d0f2ebe037f7b1
|
||||
|
||||
+16
-3
@@ -11,8 +11,8 @@
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [c3fbcbc] |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added chooseLevel; startStudySession returns the levels | [0b983b7] |
|
||||
| 2026-10-14 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added chooseLevel; startStudySession returns the levels | [0b983b7] |
|
||||
| 2026-10-15 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added the menu operations | pending |
|
||||
|
||||
---
|
||||
|
||||
@@ -36,6 +36,15 @@ L -> S : markKnown()
|
||||
S --> L : next card (word, language name)
|
||||
L -> S : markUnknown()
|
||||
S --> L : next card (word, language name)
|
||||
L -> S : openWordList(path)
|
||||
S --> L : levels, or the reason the file is refused
|
||||
L -> S : changeLevel()
|
||||
S --> L : levels
|
||||
L -> S : resetWordList()
|
||||
S --> L : levels
|
||||
L -> S : showContact()
|
||||
S --> L : name, title, link opened
|
||||
L -> S : exit()
|
||||
@enduml
|
||||
```
|
||||
|
||||
@@ -48,6 +57,11 @@ S --> L : next card (word, language name)
|
||||
| 3 | (timer) turn the card over | none | the same card, translation side | 6 |
|
||||
| 4 | markKnown | none | next card, or "nothing left to learn" | 7, 8, 9 |
|
||||
| 5 | markUnknown | none | next card, or "nothing left to learn" | 7a, 9 |
|
||||
| 6 | openWordList | path of a CSV file | the levels, or the reason the file is refused | *a.1 |
|
||||
| 7 | changeLevel | none | the levels | *a.2 |
|
||||
| 8 | resetWordList | none (the Learner confirmed) | the levels | *a.3 |
|
||||
| 9 | showContact | none | the author's name and title; the link is opened | *a.4 |
|
||||
| 10 | exit | none | none; the program ends | *a.5 |
|
||||
|
||||
The turn-over in step 3 is started by the system's own timer, not by a message from the Learner; it is shown as a return without a call, which is the one deviation from "every return answers a message". When the level is given at start (extension 3a of [UC-001]) the Learner's first message is `chooseLevel` and `startStudySession` is not sent.
|
||||
|
||||
@@ -64,5 +78,4 @@ The system instance lives for one run of the program. The words to learn are cre
|
||||
[UC-001]: ./uc.md
|
||||
[DM-001]: ../domain-model.md
|
||||
[OC-001]: ./oc.md
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
[0b983b7]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/0b983b7fdadf6958717c1d0227d0f2ebe037f7b1
|
||||
|
||||
+9
-3
@@ -11,8 +11,8 @@
|
||||
## Version History
|
||||
| Date | Status | Author | Reviewer | Change | Commit |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| 2026-10-14 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Initial version | [c3fbcbc] |
|
||||
| 2026-10-14 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added the choice of level (US-001.06) | [0b983b7] |
|
||||
| 2026-10-14 | Deprecated | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added the choice of level (US-001.06) | [0b983b7] |
|
||||
| 2026-10-15 | Accepted | Jens Tirsvad Nielsen | AI as stand-in for S01 | Added the menu commands as an extension (US-001.09 to US-001.12) | pending |
|
||||
|
||||
---
|
||||
|
||||
@@ -59,6 +59,12 @@
|
||||
1. The system tells the Learner that there is nothing left to learn at this level, and further answers change nothing.
|
||||
- 4a. The kept progress or the word list is unreadable:
|
||||
1. The system reports the problem to the Learner and ends; it does not overwrite the kept progress.
|
||||
- *a. At any time the Learner uses a menu command:
|
||||
1. Open a word list: the system asks for a file and checks it; when it is a word list, the system replaces the word list in use and goes on at step 2; when it is not, the system tells the Learner why and keeps the word list in use. When the Learner cancels nothing changes.
|
||||
2. Change level: the system goes on at step 2 with the word list in use; the kept progress stays.
|
||||
3. Reset word list: the system asks the Learner to confirm; on yes it removes the kept progress of the word list in use and goes on at step 2, so all its words are to learn again; on no nothing changes.
|
||||
4. Contact: the system shows the author's name and title and opens the author's LinkedIn page in the web browser.
|
||||
5. Exit: the system ends the program.
|
||||
|
||||
### Special Requirements / Business Rules
|
||||
|
||||
@@ -70,6 +76,7 @@
|
||||
| 6 | The turn-over comes three seconds after the card appears |
|
||||
| 8 | A word is identified by its Malay and Danish text; the first equal word is removed; known words stay known at every level and words outside the level are kept |
|
||||
| 4 | The word list names its two languages and holds one word and one translation per card |
|
||||
| *a | The kept progress of each word list is separate; resetting one word list never changes another word list or the word list itself |
|
||||
|
||||
### Open Issues
|
||||
|
||||
@@ -83,5 +90,4 @@
|
||||
[SA-001]: ../stakeholder-analysis.md
|
||||
[DM-001]: ../domain-model.md
|
||||
[SSD-001]: ./ssd.md
|
||||
[c3fbcbc]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/c3fbcbcfaf799e0ae34aed7e14d3bc8a62f03db3
|
||||
[0b983b7]: https://git.tirsystem.com/Tirsvad-Udemy-100-days-of-code/031-flash-card/commit/0b983b7fdadf6958717c1d0227d0f2ebe037f7b1
|
||||
|
||||
@@ -60,3 +60,27 @@ The Product Owner gave this screen in the first prompt (the course's target scre
|
||||
| Front (first 3000 ms) | `card_front.png` | Malay | the Malay word | black |
|
||||
| Back (after 3000 ms) | `card_back.png` | Danish | the Danish translation | white |
|
||||
| Finished | `card_front.png` | (empty) | "Nothing left to learn" | black |
|
||||
|
||||
## Menu bar and dialogs (all screens)
|
||||
|
||||
```text
|
||||
+----------------------------------------------------------+
|
||||
| File About | classic menu bar of the window
|
||||
+----------------------------------------------------------+
|
||||
File About
|
||||
+------------------------+ +-----------------------------------------------+
|
||||
| Open... | | Contact > |
|
||||
| Change level... | | +-----------------------------------------+|
|
||||
| Reset word list... | | | Jens Tirsvad Nielsen, Software engineer ||
|
||||
| ---------------------- | | | (LinkedIn) ||
|
||||
| Exit | | +-----------------------------------------+|
|
||||
+------------------------+ +-----------------------------------------------+
|
||||
```
|
||||
|
||||
| Element | Behaviour |
|
||||
| --- | --- |
|
||||
| File, Open... | Standard file dialog for `*.csv` (all files allowed), starting in the data folder; a refused file shows an error message with the reason |
|
||||
| File, Change level... | Replaces the screen by Screen 1 |
|
||||
| File, Reset word list... | Question "Start `<name>` from the beginning? All words will be to learn again." with Yes and No; Yes replaces the screen by Screen 1 |
|
||||
| File, Exit | Closes the window |
|
||||
| About, Contact, the author entry | Opens https://www.linkedin.com/in/tirsvad74 in the web browser |
|
||||
|
||||
Reference in New Issue
Block a user