Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWalter 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)
commit2b19b6cc8751f0977f1d21741f5f43ac5f53e9e9 (patch)
tree1e868a43312684947fdf8289eb77fb6c464e7ac3
parent21840a5462088699367da6d4a6fb946e02dda124 (diff)
.NI features
-rw-r--r--IKnowMyABCs.py19
-rw-r--r--NEWS10
-rw-r--r--activity/activity.info2
-rwxr-xr-xgenpieces.py12
-rw-r--r--images/correct.pngbin0 -> 41806 bytes
-rw-r--r--images/es/raton.pngbin31216 -> 27519 bytes
-rw-r--r--images/wrong.pngbin0 -> 42162 bytes
-rw-r--r--lessons/es/alphabet.csv2
-rw-r--r--page.py103
-rw-r--r--utils/play_audio.py4
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
diff --git a/NEWS b/NEWS
index d309ef6..4cf6787 100644
--- a/NEWS
+++ b/NEWS
@@ -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
new file mode 100644
index 0000000..95f5d5d
--- /dev/null
+++ b/images/correct.png
Binary files differ
diff --git a/images/es/raton.png b/images/es/raton.png
index f2e087d..4542274 100644
--- a/images/es/raton.png
+++ b/images/es/raton.png
Binary files differ
diff --git a/images/wrong.png b/images/wrong.png
new file mode 100644
index 0000000..63084d4
--- /dev/null
+++ b/images/wrong.png
Binary files differ
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
diff --git a/page.py b/page.py
index a5db3a4..31e226e 100644
--- a/page.py
+++ b/page.py
@@ -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