diff options
author | Walter Bender <walter.bender@gmail.com> | 2013-02-02 00:12:33 (GMT) |
---|---|---|
committer | Walter Bender <walter.bender@gmail.com> | 2013-02-02 00:12:33 (GMT) |
commit | 2b19b6cc8751f0977f1d21741f5f43ac5f53e9e9 (patch) | |
tree | 1e868a43312684947fdf8289eb77fb6c464e7ac3 | |
parent | 21840a5462088699367da6d4a6fb946e02dda124 (diff) |
.NI features
-rw-r--r-- | IKnowMyABCs.py | 19 | ||||
-rw-r--r-- | NEWS | 10 | ||||
-rw-r--r-- | activity/activity.info | 2 | ||||
-rwxr-xr-x | genpieces.py | 12 | ||||
-rw-r--r-- | images/correct.png | bin | 0 -> 41806 bytes | |||
-rw-r--r-- | images/es/raton.png | bin | 31216 -> 27519 bytes | |||
-rw-r--r-- | images/wrong.png | bin | 0 -> 42162 bytes | |||
-rw-r--r-- | lessons/es/alphabet.csv | 2 | ||||
-rw-r--r-- | page.py | 103 | ||||
-rw-r--r-- | utils/play_audio.py | 4 |
10 files changed, 121 insertions, 31 deletions
diff --git a/IKnowMyABCs.py b/IKnowMyABCs.py index 1ab0f2e..2598771 100644 --- a/IKnowMyABCs.py +++ b/IKnowMyABCs.py @@ -69,16 +69,21 @@ class IKnowMyABCs(activity.Activity): # FIXME: find some reasonable default situation language = 'es' - if os.path.exists(os.path.join('~', 'Activities', + home_path = os.path.expanduser('~') + if os.path.exists(os.path.join(home_path, 'Activities', 'IKnowMyABCs.activity')): - self._lessons_path = os.path.join('~', 'Activities', - 'IKnowMyABCs.activity', - 'lessons', language) + self.activity_path = os.path.join(home_path, 'Activities', + 'IKnowMyABCs.activity') else: - self._lessons_path = os.path.join('.', 'lessons', language) + self.activity_path = os.path.abspath('.') + + self._lessons_path = os.path.join(self.activity_path, + 'lessons', language) + self._images_path = os.path.join(self.activity_path, + 'images', language) + self._sounds_path = os.path.join(self.activity_path, + 'sounds', language) - self._images_path = self._lessons_path.replace('lessons', 'images') - self._sounds_path = self._lessons_path.replace('lessons', 'sounds') self._setup_toolbars() # Create a canvas @@ -1,3 +1,13 @@ +4 + +Enhancements based on feedback from .NI: +* Level 1: add the uppercase and lowercase letters +* Level 2: link the name of the letter and its image; + or example: The XO says: "A" de "Ave", "E" de Elefante +* Change the background color to one of the XO colors +* Add visual to feedback for Levels 3 and 4 +* Don't repeat letters until all letters have been seen + 2 * Fix play audio so it works more places diff --git a/activity/activity.info b/activity/activity.info index efdc2b2..6ce3ed6 100644 --- a/activity/activity.info +++ b/activity/activity.info @@ -1,6 +1,6 @@ [Activity] name = I Know My ABCs -activity_version = 2 +activity_version = 4 license = GPLv3 bundle_id = org.sugarlabs.IKnowMyABCs exec = sugar-activity IKnowMyABCs.IKnowMyABCs diff --git a/genpieces.py b/genpieces.py index f4d8485..bf9232d 100755 --- a/genpieces.py +++ b/genpieces.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -#Copyright (c) 2009-11 Walter Bender +#Copyright (c) 2009-13 Walter Bender # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -146,6 +146,16 @@ def generator(datapath): close_file(f) +def genblank(w, h, colors, stroke_width=1.0): + svg = SVG() + svg.set_scale(1) + svg.set_colors(colors) + svg.set_stroke_width(stroke_width) + svg_string = svg.header(int(w / 80), int(h / 60)) + svg_string += svg.footer() + return svg_string + + def main(): return 0 diff --git a/images/correct.png b/images/correct.png Binary files differnew file mode 100644 index 0000000..95f5d5d --- /dev/null +++ b/images/correct.png diff --git a/images/es/raton.png b/images/es/raton.png Binary files differindex f2e087d..4542274 100644 --- a/images/es/raton.png +++ b/images/es/raton.png diff --git a/images/wrong.png b/images/wrong.png Binary files differnew file mode 100644 index 0000000..63084d4 --- /dev/null +++ b/images/wrong.png diff --git a/lessons/es/alphabet.csv b/lessons/es/alphabet.csv index 4dced1d..348dadd 100644 --- a/lessons/es/alphabet.csv +++ b/lessons/es/alphabet.csv @@ -18,7 +18,7 @@ K, (k)ilo, #FFC040, kilo.png, kilo.ogg, k.ogg L, (l)oro, #00A0FF, loro.png, loro.ogg, l.ogg M, (m)esa, #C72020, mesa.png, mesa.ogg, m.ogg N, (n)ube, #7A6BBD, nube.png, nube.ogg, n.ogg -Ñ, (ñ)andú, #80C040/#C93C7E, nandu.png, nandu.ogg, ny.ogg +Ññ, (ñ)andú, #80C040/#C93C7E, nandu.png, nandu.ogg, ny.ogg O, (o)s(o), #A4221E, oso.png, oso.ogg, o.ogg P, (p)ato, #A4221E, pato.png, pato.ogg, p.ogg Q, (q)ueso, #FFC040, queso.png, queso.ogg, q.ogg @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -#Copyright (c) 2012 Walter Bender +#Copyright (c) 2012-13 Walter Bender # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -14,7 +14,6 @@ import gtk import gobject import os -import codecs from random import uniform from gettext import gettext as _ @@ -24,13 +23,11 @@ from utils.play_audio import play_audio_from_file import logging _logger = logging.getLogger('iknowmyabcs-activity') -try: - from sugar.graphics import style - GRID_CELL_SIZE = style.GRID_CELL_SIZE -except ImportError: - GRID_CELL_SIZE = 0 +from sugar import profile +from sugar.graphics import style +GRID_CELL_SIZE = style.GRID_CELL_SIZE -from genpieces import generate_card +from genpieces import generate_card, genblank from utils.sprites import Sprites, Sprite @@ -50,11 +47,14 @@ class Page(): self._images_path = images_path self._sounds_path = sounds_path + self._colors = profile.get_color().to_string().split(',') + self._card_data = [] self._color_data = [] self._image_data = [] self._media_data = [] # (image sound, letter sound) self._word_data = [] + self._deja_vu = [] # Starting from command line if self._activity is None: @@ -80,7 +80,6 @@ class Page(): self._grid_x_offset = int( (self._width - XDIM * (self._card_width + GUTTER * 2)) / 2) self._grid_y_offset = 0 - # self._scale = self._width / 240. self._scale = self._card_width / 80 self._sprites = Sprites(self._canvas) self.current_card = 0 @@ -90,17 +89,48 @@ class Page(): self._release = None self.timeout = None + self._my_canvas = Sprite( + self._sprites, 0, 0, svg_str_to_pixbuf(genblank( + self._width, self._height, (self._colors[0], + self._colors[0])))) + self._my_canvas.type = 'background' + + self._smile = Sprite(self._sprites, + int(self._width / 4), + int(self._height / 4), + gtk.gdk.pixbuf_new_from_file_at_size( + os.path.join(self._activity.activity_path, + 'images', 'correct.png'), + int(self._width / 2), + int(self._height / 2))) + + self._frown = Sprite(self._sprites, + int(self._width / 4), + int(self._height / 4), + gtk.gdk.pixbuf_new_from_file_at_size( + os.path.join(self._activity.activity_path, + 'images', 'wrong.png'), + int(self._width / 2), + int(self._height / 2))) + self.load_level(os.path.join(self._lessons_path, 'alphabet' + '.csv')) self.new_page() + def _hide_feedback(self): + if hasattr(self, '_smile'): + self._smile.hide() + self._frown.hide() + def new_page(self, cardtype='alpha'): ''' Load a page of cards ''' if self.timeout is not None: gobject.source_remove(self.timeout) self._hide_cards() + self._hide_feedback() if cardtype == 'alpha': self._alpha_cards() else: + self._image_cards() # Kludge to get around display bug self._image_cards() def _hide_cards(self): @@ -143,13 +173,13 @@ class Page(): if type(self._color_data[self.current_card][0]) == type([]): stroke = self._test_for_stroke() top = svg_str_to_pixbuf(generate_card( - string=card[0].lower(), + string=card[0], colors=[self._color_data[self.current_card][0][0], '#FFFFFF'], scale=self._scale, center=True)) bot = svg_str_to_pixbuf(generate_card( - string=card[0].lower(), + string=card[0], colors=[self._color_data[self.current_card][0][1], '#FFFFFF'], scale=self._scale, @@ -165,7 +195,8 @@ class Page(): stroke = self._test_for_stroke() self._cards.append(Sprite(self._sprites, x, y, svg_str_to_pixbuf(generate_card( - string=card[0].lower(), + string='%s%s' % ( + card[0].upper(), card[0].lower()), colors=[self._color_data[self.current_card][0], '#FFFFFF'], stroke=stroke, @@ -186,15 +217,28 @@ class Page(): self._activity.status.set_text( _('Click on the card that corresponds to the sound.')) self.target = int(uniform(0, len(self._cards))) + # Don't repeat + while self.target in self._deja_vu: + self.target = int(uniform(0, len(self._cards))) + self._deja_vu.append(self.target) + if len(self._deja_vu) == len(self._cards): + self._deja_vu = [] if self.timeout is not None: gobject.source_remove(self.timeout) self.timeout = gobject.timeout_add(1000, self._play_target_sound) def _play_target_sound(self): - if self._activity.mode == 'find by letter': + if self._activity.mode in ['letter', 'find by letter']: play_audio_from_file(os.path.join( self._sounds_path, self._media_data[self.target][1])) + elif self._activity.mode == 'picture': + play_audio_from_file(os.path.join( + self._sounds_path, + self._media_data[self.target][1])) + gobject.timeout_add(1000, play_audio_from_file, os.path.join( + self._sounds_path, + self._media_data[self.target][0])) else: play_audio_from_file(os.path.join( self._sounds_path, @@ -217,23 +261,44 @@ class Page(): x, y = map(int, event.get_coords()) spr = self._sprites.find_sprite((x, y)) + if spr is None: + return + if spr.type == 'background': + return if spr in self._cards: self.current_card = self._cards.index(spr) elif spr in self._pictures: self.current_card = self._pictures.index(spr) if self._activity.mode in ['letter', 'picture']: - play_audio_from_file(os.path.join( - self._sounds_path, - self._media_data[self.current_card][1])) + self.target = self.current_card + self._play_target_sound() elif self._activity.mode in ['find by letter', 'find by word']: if self.current_card == self.target: self._activity.status.set_text(_('Very good!')) + self._play(True) if self.timeout is not None: gobject.source_remove(self.timeout) - self.timeout = gobject.timeout_add(1000, self.new_target) + self.timeout = gobject.timeout_add(1000, self._correct_feedback) else: self._activity.status.set_text(_('Please try again.')) - self._play_target_sound() + self._play(False) + if self.timeout is not None: + gobject.source_remove(self.timeout) + self.timeout = gobject.timeout_add(1000, self._wrong_feedback) + + def _correct_feedback(self): + self._hide_feedback() + self.new_target() + + def _wrong_feedback(self): + self._hide_feedback() + self._play_target_sound() + + def _play(self, great): + if great: + self._smile.set_layer(1000) + else: + self._frown.set_layer(1000) def _keypress_cb(self, area, event): ''' No keyboard shortcuts at the moment. Perhaps jump to the page @@ -275,7 +340,7 @@ class Page(): self._color_data = [] self._image_data = [] self._media_data = [] # (image sound, letter sound) - f = codecs.open(path, encoding='utf-8') + f = open(path) for line in f: if len(line) > 0 and line[0] not in '#\n': words = line.split(', ') diff --git a/utils/play_audio.py b/utils/play_audio.py index f5c1030..581f5cf 100644 --- a/utils/play_audio.py +++ b/utils/play_audio.py @@ -4,7 +4,7 @@ Copyright (C) 2007 Andy Wingo <wingo@pobox.com> Copyright (C) 2007 Red Hat, Inc. Copyright (C) 2008-2010 Kushal Das <kushal@fedoraproject.org> - Copyright (C) 2010-11 Walter Bender + Copyright (C) 2010-13 Walter Bender """ # This program is free software; you can redistribute it and/or @@ -63,7 +63,7 @@ def check_output(command, warning): try: output = subprocess.check_output(command) except subprocess.CalledProcessError: - log.warning(warning) + _logger.warning(warning) return None else: import commands |