Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--TODO3
-rw-r--r--lessons/en_US/homerow_intro.lesson63
-rw-r--r--lessons/en_US/long.lesson13
-rwxr-xr-xtypingturtle.py266
4 files changed, 210 insertions, 135 deletions
diff --git a/TODO b/TODO
index bc5d087..ac4fcc7 100644
--- a/TODO
+++ b/TODO
@@ -1,7 +1,8 @@
Typing Turtle
First Release
-- Write to Loser, Wes about developing artwork.
+- Write tLoser, Wes about developing artwork.
++ Blinking key hilite in 'key' mode.
+ WPM meter updated in 1sec timer.
- Draw incorrect characters in red.
- Support backspace, backspace to previous lines.
diff --git a/lessons/en_US/homerow_intro.lesson b/lessons/en_US/homerow_intro.lesson
index 774a148..2320a46 100644
--- a/lessons/en_US/homerow_intro.lesson
+++ b/lessons/en_US/homerow_intro.lesson
@@ -1,81 +1,90 @@
{
"name": "Home Row",
"description": "Teaches the middle row of keys on the keyboard.",
- "medals": {
- "bronze": { "wpm": 0, "accuracy": 60 },
- "silver": { "wpm": 0, "accuracy": 60 },
- "gold": { "wpm": 0, "accuracy": 90 }
- },
"steps": [
{
- "type": "key",
- "instructions": "Welcome to the first Typing Turtle lesson! Please place your fingers on the keyboard.\n\nWhen you are ready to begin, press the f key with your left index finger.",
+ "instructions": "Welcome to the first Typing Turtle lesson! Place your fingers on the keyboard as shown below.\n\nWhen you are ready to begin, press the f key with your left index finger.",
"text": "f"
},
{
- "type": "key",
"instructions": "Good job! Now press the d key with your left middle finger.",
"text": "d"
},
{
- "type": "key",
"instructions": "Now the s key with your left ring finger.",
"text": "s"
},
{
- "type": "key",
"instructions": "And the a key with your left pinky finger.",
"text": "a"
},
{
- "type": "key",
"instructions": "Great work! We will now move on to the right hand. As shown in the picture below, press the j key with your right index finger.",
"text": "j"
},
{
- "type": "key",
"instructions": "The k key with your right middle finger.",
"text": "k"
},
{
- "type": "key",
"instructions": "The l key with your right ring finger.",
"text": "l"
},
{
- "type": "key",
"instructions": "The ; (semicolon) key with your right pinky finger.",
"text": ";"
},
{
- "type": "key",
- "instructions": "Excellent! These keys are known as the home row. Your fingers should always return to them after typing each letter.\n\nType all of the letters below. Press down with your fingertips, but do not move your hands.",
+ "instructions": "Excellent! These keys are known as the home row. Your fingers should always return to rest lightly on them.\n\nType all of the letters below. Press down quickly and lightly with your fingertips, but do not move your hands.",
"text": "fdsajkl;"
},
{
- "type": "key",
"instructions": "Again, from left to right!",
"text": "asdfjkl;"
},
{
- "type": "key",
"instructions": "Keep it up, you are doing great! Now, from right to left!",
"text": ";lkjfdsa"
},
{
- "type": "key",
- "instructions": "Okay, you are done with that. Now to begin moving your fingers. Without moving any other fingers, move your left index finger over and press the g key.",
- "text": "g"
+ "instructions": "Okay, now to learn the Enter reach. Without moving your hands, move your right pinky over and press the Enter key.",
+ "text": "\n"
},
{
- "type": "key",
- "instructions": "Now do the same with your right hand. Move your right index finger only and press the h key.",
- "text": "h"
+ "instructions": "Good. Now type the next two lines, using the Enter key to move from one line to the next.",
+ "text": "asdf\njkl;"
},
{
- "type": "key",
- "instructions": "Now for the final two keys of the home row. Move your right pinky finger over and press the ' key.",
- "text": "'"
+ "instructions": "Time to practice Enter and ;!",
+ "text": ";\n;\n;\n"
+ },
+ {
+ "instructions": "Time to practice letters. Now type in the following lines.",
+ "text": "asdf\njkl;\nasdfjkl;\njkl;asdf"
+ },
+ {
+ "instructions": "Now we will learn the Space bar. The space bar is used to leave a space between words. Use your right thumb to press it.",
+ "text": " "
+ },
+ {
+ "instructions": "Press it again!",
+ "text": " "
+ },
+ {
+ "instructions": "One more time!",
+ "text": " "
+ },
+ {
+ "instructions": "Good job. Let's put it all together now with some practice lines.",
+ "text": "ff f jj j dd d kk k ss s ll l aa a ;; ;\nfdsa jkl;\nff f jj j dd d kk k ss s ll l aa a ;; ;\nfdsa jkl;\n; ;; a aa l ll s ss k kk d dd j jj f ff\nasdf jkl;\n; ;; a aa l ll s ss k kk d dd j jj f ff\nasdf jkl;\n"
+ },
+ {
+ "instructions": "It's very important to master the home row before learning to reach for the other keys. Stick with it and you will be touch typing in no time at all!",
+ "text": "a; a; sl sl dk dk fj fj jf jf kd kd ls ls ;a ;a\na; a; sl sl dk dk fj fj jf jf kd kd ls ls ;a ;a\n;ajf ;ajf ;alskdjf ;alskdjf ;alskdjf ;alskdjf ;alskdjf\n\n;ajf ;ajf ;alskdjf ;alskdjf ;alskdjf ;alskdjf ;alskdjf\nfja; fjsd j;kl lk;j sldk kdls ajf;dkls ajf;dkls jdfksl;a\n"
+ },
+ {
+ "instructions": "Try and speed up your typing a little.\n\nWhen your fingers are on the home row, they should be curved so that your thumbs rest on the space bar.",
+ "text": "a;sldkfj a;sldkfj a;sldkfj a;sldkfj\njj ff kk dd ll ss ;; aa\na; sl dk fj a; sl dk fj asdf ;lkj\njf kd ls ;a fj dk sl a; fdsa jkl; jfkdls;a\n;; ll kk kj lk ;l aa ss dd df sd as jd fl jd fl jj dd ff ll\na a as as sad sad lad lad fad fad ask ask\nadd add ask ask lass lass as as falls falls jaff\nask lass fall as daff lass ads ask add ask\na lass; all lads; a fall; fall a lad; a dall a lad; fall dad fad; a jad falls a fad;\nsalad lad; lass sad; a fad a dall; salad dad; salad fad;"
}
]
}
diff --git a/lessons/en_US/long.lesson b/lessons/en_US/long.lesson
index 512b3c0..c4379f1 100644
--- a/lessons/en_US/long.lesson
+++ b/lessons/en_US/long.lesson
@@ -1,16 +1,11 @@
{
- "name": "Long Lesson",
- "description": "Testing for lessons involving multiple pages of text.",
- "medals": {
- "bronze": { "wpm": 0, "accuracy": 60 },
- "silver": { "wpm": 0, "accuracy": 60 },
- "gold": { "wpm": 0, "accuracy": 90 }
- },
+ "name": "Punctuation Practice!",
+ "description": "Practice punctuation with a section of Pride and Prejudice.",
"steps": [
{
"type": "text",
- "instructions": "Please copy out the following text.",
- "text": "It is a truth universally acknowledged, that a single man in posession of a good fortune, must be in want of a wife.\n\nHowever little known the feelings or views of such a man may be on his first entering a neighbourhood, this truth is so well fixed in the minds of the surrounding families, that he is considered the rightful property of some one or other of their daughters.\n\n\"My dear Mr. Bennet,\" said his lady to him one day, \"have you heard that\nNetherfield Park is let at last?\"\n\nMr. Bennet replied that he had not.\n\n\"But it is,\" returned she; \"for Mrs. Long has just been here, and she told me all about it.\"\n\nMr. Bennet made no answer.\n\n\"Do you not want to know who has taken it?\" cried his wife impatiently.\n\n\"You want to tell me, and I have no objection to hearing it.\"\n\nThis was invitation enough."
+ "instructions": "Pride and Prejudice\nby Jane Austen",
+ "text": "It is a truth universally acknowledged, that a single man in posession of a good fortune, must be in want of a wife.\n\nHowever little known the feelings or views of such a man may be on his first entering a neighbourhood, this truth is so well fixed in the minds of the surrounding families, that he is considered the rightful property of some one or other of their daughters.\n\n\"My dear Mr. Bennet,\" said his lady to him one day, \"have you heard that Netherfield Park is let at last?\"\n\nMr. Bennet replied that he had not.\n\n\"But it is,\" returned she; \"for Mrs. Long has just been here, and she told me all about it.\"\n\nMr. Bennet made no answer.\n\n\"Do you not want to know who has taken it?\" cried his wife impatiently.\n\n\"You want to tell me, and I have no objection to hearing it.\"\n\nThis was invitation enough."
}
]
}
diff --git a/typingturtle.py b/typingturtle.py
index 10c88f2..3459e7a 100755
--- a/typingturtle.py
+++ b/typingturtle.py
@@ -17,7 +17,7 @@
"""Typing Turtle - Interactive typing tutor for the OLPC XO."""
# Import standard Python modules.
-import logging, os, math, time, copy, json, locale, datetime
+import logging, os, math, time, copy, json, locale, datetime, random
from gettext import gettext as _
# Set up localization.
@@ -43,53 +43,64 @@ import keyboard
# Paragraph symbol unicode character.
PARAGRAPH_CODE = u'\xb6'
+# Maximium width of a text line in text lesson mode.
+LINE_LENGTH = 80
+
+# Requirements for earning medals.
+# Words per minute goals came from http://en.wikipedia.org/wiki/Words_per_minute.
+MEDALS = [
+ { 'name': 'bronze', 'wpm': 25, 'accuracy': 75 },
+ { 'name': 'silver', 'wpm': 35, 'accuracy': 85 },
+ { 'name': 'gold', 'wpm': 45, 'accuracy': 95 }
+]
+
class MedalScreen(gtk.EventBox):
def __init__(self, medal, activity):
gtk.EventBox.__init__(self)
-
+
self.modify_bg(gtk.STATE_NORMAL, self.get_colormap().alloc_color('#ffffff'))
-
+
self.medal = medal
self.activity = activity
-
+
cert0 = gtk.Label()
cert0.set_markup("<span size='35000'><b><i>" + _('Certificate of\nAchievement') + "</i></b></span>")
-
+
cert1 = gtk.Label()
cert1.set_markup("<span size='18000'>" +
(_('This certifies that on <i><b><u>%(date)s</u></b></i>,\n<i><b><u>%(nick)s</u></b></i> earned a %(type)s medal\nin Typing Turtle lesson <i><b><u>%(lesson)s</u></b></i>.') % medal) +
"</span>")
-
+
wpmlabel = gtk.Label()
wpmlabel.set_markup("<span size='18000'>" + (_('<b>Words Per Minute:</b> %(wpm)d') % medal) + "</span>" )
-
+
accuracylabel = gtk.Label()
accuracylabel.set_markup("<span size='15000'>" + (_('<b>Accuracy:</b> %(accuracy)d%%') % medal) + "</span>" )
-
+
statbox = gtk.HBox()
statbox.pack_start(wpmlabel, True)
statbox.pack_start(accuracylabel, True)
-
+
oklabel = gtk.Label()
oklabel.set_markup("<span size='10000'>" + _('Go Back') + '</span>')
okbtn = gtk.Button()
okbtn.add(oklabel)
okbtn.connect('clicked', self.ok_cb)
-
+
btnbox = gtk.HBox()
btnbox.pack_start(okbtn, True, False)
-
+
vbox = gtk.VBox()
-
+
vbox.pack_start(cert0, True, False, 0)
vbox.pack_start(cert1, False, False, 0)
vbox.pack_start(gtk.HSeparator(), False, False, 20)
vbox.pack_start(statbox, False, False, 0)
vbox.pack_start(gtk.HSeparator(), False, False, 20)
vbox.pack_start(btnbox, False, False, 40)
-
+
self.add(vbox)
-
+
self.show_all()
def ok_cb(self, widget):
@@ -98,55 +109,56 @@ class MedalScreen(gtk.EventBox):
class LessonScreen(gtk.VBox):
def __init__(self, lesson, activity):
gtk.VBox.__init__(self)
-
+
self.lesson = lesson
self.activity = activity
-
+
# Build the user interface.
title = gtk.Label()
title.set_markup("<span size='20000'><b>" + lesson['name'] + "</b></span>")
title.set_alignment(1.0, 0.0)
-
+
stoplabel = gtk.Label(_('Go Back'))
stopbtn = gtk.Button()
stopbtn.add(stoplabel)
stopbtn.connect('clicked', self.stop_cb)
-
+
# TODO- These will be replaced by graphical displays using gtk.DrawingArea.
self.wpmlabel = gtk.Label()
self.accuracylabel = gtk.Label()
-
+
#self.wpmarea = gtk.DrawingArea()
#self.wpmarea.connect('expose-event', self.wpm_expose_cb)
#self.accuracyarea = gtk.DrawingArea()
#self.accuracyarea.connect('expose-event', self.accuracy_expose_cb)
-
+
hbox = gtk.HBox()
hbox.pack_start(stopbtn, False, False, 10)
hbox.pack_start(self.wpmlabel, True, False, 10)
hbox.pack_start(self.accuracylabel, True, False, 10)
hbox.pack_end(title, False, False, 10)
-
+
# Set up font styles.
self.tagtable = gtk.TextTagTable()
instructions_tag = gtk.TextTag('instructions')
- instructions_tag.props.size = 10000
-
+ #instructions_tag.props.size = 10000
+ instructions_tag.props.justification = gtk.JUSTIFY_CENTER
+
self.tagtable.add(instructions_tag)
text_tag = gtk.TextTag('text')
text_tag.props.family = 'Monospace'
self.tagtable.add(text_tag)
-
+
correct_copy_tag = gtk.TextTag('correct-copy')
correct_copy_tag.props.family = 'Monospace'
correct_copy_tag.props.foreground = '#0000ff'
self.tagtable.add(correct_copy_tag)
-
+
incorrect_copy_tag = gtk.TextTag('incorrect-copy')
incorrect_copy_tag.props.family = 'Monospace'
incorrect_copy_tag.props.foreground = '#ff0000'
self.tagtable.add(incorrect_copy_tag)
-
+
# Set up the scrolling lesson text view.
self.lessonbuffer = gtk.TextBuffer(self.tagtable)
self.lessontext = gtk.TextView(self.lessonbuffer)
@@ -158,48 +170,50 @@ class LessonScreen(gtk.VBox):
self.lessonscroll = gtk.ScrolledWindow()
self.lessonscroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
self.lessonscroll.add(self.lessontext)
-
+
frame = gtk.Frame()
frame.add(self.lessonscroll)
-
+
self.keyboard = keyboard.Keyboard(self.activity)
self.keyboard.set_layout(keyboard.DEFAULT_LAYOUT)
-
+
activity.add_events(gtk.gdk.KEY_PRESS_MASK)
activity.connect('key-press-event', self.key_press_cb)
-
+
self.pack_start(hbox, False, False, 10)
self.pack_start(frame, True, True)
self.pack_start(self.keyboard, True)
-
+
self.show_all()
-
+
self.begin_lesson()
- def begin_lesson(self):
- self.total_keys = 0
- self.correct_keys = 0
- self.incorrect_keys = 0
-
- self.start_time = None
-
- self.next_step_idx = 0
- self.advance_step()
-
def update_stats(self):
self.total_time = time.time() - self.start_time
if self.total_time >= 1.0:
- self.wpm = 60 * (self.correct_keys / 10) / self.total_time
+ self.wpm = 60 * (self.correct_keys / 5) / self.total_time
else:
self.wpm = 1.0
self.accuracy = 100.0 * self.correct_keys / self.total_keys
-
+
self.accuracylabel.set_markup(_('<b>Accuracy:</b> %(accuracy)d%%') % { 'accuracy' : int(self.accuracy) } )
self.wpmlabel.set_markup(_('<b>WPM:</b> %(wpm)d') % { 'wpm': int(self.wpm) } )
- def wrap_line(self, line):
- LINE_LENGTH = 80
+ def begin_lesson(self):
+ self.lesson_finished = False
+
+ self.medal = None
+
+ self.total_keys = 0
+ self.correct_keys = 0
+ self.incorrect_keys = 0
+
+ self.start_time = None
+
+ self.next_step_idx = 0
+ self.advance_step()
+ def wrap_line(self, line):
words = line.split(' ')
new_lines = []
cur_line = ''
@@ -229,41 +243,44 @@ class LessonScreen(gtk.VBox):
# Clear step related variables.
self.step = None
self.step_type = None
-
+
self.text = None
self.line = None
self.line_marks = None
-
+
self.key_expected = None
-
+
# End lesson if this is the last step.
if self.next_step_idx >= len(self.lesson['steps']):
- self.finish_lesson()
+ self.lesson_finished = True
+ self.show_lesson_report()
return
# TODO - Play 'step finished' sound here.
self.step = self.lesson['steps'][self.next_step_idx]
self.next_step_idx = self.next_step_idx + 1
-
- self.step_type = self.step['type']
+
+ if len(self.step['text']) == 1:
+ self.step_type = 'key'
+ else:
+ self.step_type = 'text'
if self.step_type == 'text':
# Clear the text buffer and output the instructions.
self.lessonbuffer.set_text('')
self.lessonbuffer.insert_with_tags_by_name(
- self.lessonbuffer.get_end_iter(), self.step['instructions'] + '\n\n', 'instructions')
+ self.lessonbuffer.get_end_iter(), '\n' + self.step['instructions'] + '\n\n', 'instructions')
- # Replace newlines with paragraph marks.
self.text = unicode(self.step['text'])
# Split text into lines.
- self.lines = self.text.split('\n')
+ self.lines = self.text.splitlines(True)
- # Append paragraph codes.
- self.lines = [l + PARAGRAPH_CODE for l in self.lines]
+ # Substitute paragraph codes.
+ self.lines = [l.replace('\n', PARAGRAPH_CODE) for l in self.lines]
- # TODO: Split by line length in addition to by paragraphs.
+ # Split by line length in addition to by paragraphs.
for i in range(0, len(self.lines)):
line = self.lines[i]
if len(line) > 30:
@@ -288,11 +305,11 @@ class LessonScreen(gtk.VBox):
# Clear the text buffer and output the instructions.
self.lessonbuffer.set_text('')
self.lessonbuffer.insert_with_tags_by_name(
- self.lessonbuffer.get_end_iter(), self.step['instructions'] + '\n\n', 'instructions')
-
+ self.lessonbuffer.get_end_iter(), '\n' + self.step['instructions'] + '\n\n', 'instructions')
+
# Prepare the key.
- self.key_expected = unicode(self.step['text'][0])
-
+ self.key_expected = unicode(self.step['text'][0]).replace('\n', PARAGRAPH_CODE)
+
# Hilite the key on the virtual keyboard.
self.keyboard.clear_hilite()
key = self.keyboard.find_key_by_letter(self.key_expected)
@@ -302,7 +319,7 @@ class LessonScreen(gtk.VBox):
def begin_line(self):
self.line = self.lines[self.line_idx]
self.line_mark = self.line_marks[self.line_idx]
-
+
self.char_idx = 0
self.hilite_next_key()
@@ -311,22 +328,28 @@ class LessonScreen(gtk.VBox):
# Ignore hotkeys.
if event.state & (gtk.gdk.CONTROL_MASK | gtk.gdk.MOD1_MASK):
return
-
+
# Extract information about the key pressed.
key = gtk.gdk.keyval_to_unicode(event.keyval)
if key != 0: key = chr(key)
key_name = gtk.gdk.keyval_name(event.keyval)
-
+
+ # Simply wait for a return keypress on the lesson finished screen.
+ if self.lesson_finished:
+ if key_name == 'Return':
+ self.end_lesson()
+ return
+
# Convert Return keys to paragraph symbols.
if key_name == 'Return':
key = PARAGRAPH_CODE
-
+
print "key_press_cb: key=%s key_name=%s event.keyval=%d" % (key, key_name, event.keyval)
-
+
# Timer starts with first keypress.
if not self.start_time:
self.start_time = time.time()
-
+
# Handle backspace by deleting text and optionally moving up lines.
if self.step_type == 'text':
if key_name == 'BackSpace':
@@ -334,43 +357,43 @@ class LessonScreen(gtk.VBox):
if self.char_idx == 0 and self.line_idx > 0:
self.line_idx -= 1
self.begin_line()
-
+
self.char_idx = len(self.line)
-
+
# Then delete the current character.
if self.char_idx > 0:
self.char_idx -= 1
-
+
iter = self.lessonbuffer.get_iter_at_mark(self.line_mark)
iter.forward_chars(self.char_idx)
-
+
iter_end = iter.copy()
iter_end.forward_char()
-
+
self.lessonbuffer.delete(iter, iter_end)
# Process normal key presses.
elif key != 0:
-
+
# Check to see if they pressed the correct key.
if key == self.line[self.char_idx]:
tag_name = 'correct-copy'
self.correct_keys += 1
self.total_keys += 1
-
+
else:
# TODO - Play 'incorrect key' sound here.
-
+
tag_name = 'incorrect-copy'
self.incorrect_keys += 1
self.total_keys += 1
-
+
# Insert the key into the bufffer.
iter = self.lessonbuffer.get_iter_at_mark(self.line_mark)
iter.forward_chars(self.char_idx)
-
+
self.lessonbuffer.insert_with_tags_by_name(iter, key, tag_name)
-
+
# Advance to the next character (or else).
self.char_idx += 1
if self.char_idx >= len(self.line):
@@ -381,9 +404,9 @@ class LessonScreen(gtk.VBox):
self.begin_line()
self.update_stats()
-
+
self.hilite_next_key()
-
+
elif self.step_type == 'key':
# Check to see if they pressed the correct key.
@@ -422,16 +445,11 @@ class LessonScreen(gtk.VBox):
self.lessontext.grab_focus()
# Scroll the TextView so the cursor is on screen.
- mark = self.lessonbuffer.get_insert()
- self.lessontext.scroll_to_mark(mark, 0.1)
+ self.lessontext.scroll_to_mark(self.lessonbuffer.get_insert(), 0.1)
- def finish_lesson(self):
- self.activity.pop_screen()
-
+ def show_lesson_report(self):
self.update_stats()
- #self.add_text(_('Congratulations! You finished the lesson in %(time)d seconds.\n\n') %
- # { 'time': int(self.total_time) } )
-
+
lesson_name = self.lesson['name']
# Add to the lesson history.
@@ -445,28 +463,30 @@ class LessonScreen(gtk.VBox):
# Show the medal screen, if one should be given.
got_medal = None
- for medal_name in ['bronze', 'silver', 'gold']:
- medal = self.lesson['medals'][medal_name]
+ for medal in MEDALS:
if self.wpm >= medal['wpm'] and self.accuracy >= medal['accuracy']:
- got_medal = medal_name
+ got_medal = medal['name']
if got_medal:
# Award the medal.
medal = {
'lesson': lesson_name,
- 'type': medal_name,
+ 'type': got_medal,
'date': datetime.date.today().strftime('%B %d, %Y'),
'nick': self.activity.owner.props.nick,
'time': self.total_time,
'wpm': report['wpm'],
'accuracy': report['accuracy']
}
+ self.medal = medal
+ # Compare this medal with any existing medals for this lesson.
+ # Only record the best one.
add_medal = True
if self.activity.data['medals'].has_key(lesson_name):
old_medal = self.activity.data['medals'][lesson_name]
- order = 'bronze silver gold'
+ order = ' '.join([m['name'] for m in MEDALS])
add_idx = order.index(medal['type'])
old_idx = order.index(old_medal['type'])
@@ -478,13 +498,63 @@ class LessonScreen(gtk.VBox):
elif medal['accuracy'] == old_medal['accuracy']:
if medal['wpm'] < old_medal['wpm']:
add_medal = False
-
+
if add_medal:
self.activity.data['medals'][lesson_name] = medal
self.activity.mainscreen.update_medals()
-
- # Show the new medal (regardless of whether it was recorded).
- self.activity.push_screen(MedalScreen(medal, self.activity))
+
+ # Display results to the user.
+ text = '\n'
+
+ congrats = [
+ _('Good job!'),
+ _('Well done!'),
+ _('Nice work!'),
+ _('Way to go!')
+ ]
+ text += random.choice(congrats) + '\n\n'
+
+ text += _('You finished the lesson in %(time)d seconds, with %(errors)d errors.\n\n') % \
+ { 'time': int(self.total_time), 'errors': self.incorrect_keys }
+ text += _('Your words per minute (WPM) was %(wpm)d, and your accuracy was %(accuracy)d%%.\n\n') % \
+ report
+
+ if self.medal:
+ # TODO: Play medal sound here.
+
+ text += _('Congratulations! You earned a %(type)s medal!\n\nPress Enter to see your certificate.') % \
+ medal
+
+ else:
+ # Comment on what the user needs to do better.
+ need_wpm = report['wpm'] < self.lesson['medals']['bronze']['wpm']
+ need_accuracy = report['accuracy'] < self.lesson['medals']['bronze']['accuracy']
+
+ if need_accuracy and need_wpm:
+ text += _('You need to practice this lesson more before moving on. If you are having a hard time, '
+ 'repeat the earlier lessons until you have mastered them completely before trying this one '
+ 'again.\n\n')
+
+ elif need_accuracy:
+ text += _('You almost got a medal! Next time, try not to make as many errors!\n\n')
+
+ elif need_wpm:
+ text += _('You almost got a medal! Next time, try to type a little faster!\n\n')
+
+ text += _('Press Enter to return to the main screen.')
+
+ self.lessonbuffer.set_text('')
+ self.lessonbuffer.insert_with_tags_by_name(
+ self.lessonbuffer.get_end_iter(),
+ text,
+ 'instructions')
+
+ def end_lesson(self):
+ self.activity.pop_screen()
+
+ # Show the new medal if there was one.
+ if self.medal:
+ self.activity.push_screen(MedalScreen(self.medal, self.activity))
def stop_cb(self, widget):
self.activity.pop_screen()