Fix widget aspect update bug
[pedometerwidget] / src / usr / lib / hildon-desktop / pedometer_widget_home.py
index 57f1c98..8ba5053 100644 (file)
@@ -35,8 +35,10 @@ import hildon
 PATH = "/apps/pedometerhomewidget"
 MODE = PATH + "/mode"
 HEIGHT = PATH + "/height"
+STEP_LENGTH = PATH + "/step_length"
 WEIGHT = PATH + "/weight"
 UNIT = PATH + "/unit"
+SENSITIVITY = PATH + "/sensitivity"
 ASPECT = PATH + "/aspect"
 SECONDVIEW = PATH + "/secondview"
 GRAPHVIEW = PATH + "/graphview"
@@ -55,7 +57,9 @@ unit = 0
 
 class Singleton(object):
     _instance = None
+    _references = 0
     def __new__(cls, *args, **kwargs):
+        cls._references+=1
         if not cls._instance:
             cls._instance = super(Singleton, cls).__new__(
                                 cls, *args, **kwargs)
@@ -64,6 +68,8 @@ class Singleton(object):
 class PedoIntervalCounter(Singleton):
     MIN_THRESHOLD = 500
     MIN_TIME_STEPS = 0.5
+    sensitivity = 100
+    mode = 0
     x = []
     y = []
     z = []
@@ -81,13 +87,17 @@ class PedoIntervalCounter(Singleton):
         #runnig, higher threshold to prevent fake steps
         self.mode = mode
         if mode == 1:
-            self.MIN_THRESHOLD = 650
+            self.MIN_THRESHOLD = 650.0 * (200 - self.sensitivity) / 100
             self.MIN_TIME_STEPS = 0.35
         #walking
         else:
-            self.MIN_THRESHOLD = 500
+            self.MIN_THRESHOLD = 500.0 * (200 - self.sensitivity) / 100
             self.MIN_TIME_STEPS = 0.5
 
+    def set_sensitivity(self, value):
+        self.sensitivity = value
+        self.set_mode(self.mode)
+
     def calc_mean(self, vals):
         sum = 0
         for i in vals:
@@ -150,7 +160,6 @@ class PedoValues():
         self.steps = steps
         self.calories = calories
         self.dist = dist
-        self.unit = unit
 
     def __add__(self, other):
         return PedoValues(self.time + other.time,
@@ -175,20 +184,22 @@ class PedoValues():
         return strtime
 
     def get_print_distance(self):
+        global unit
         if self.dist > 1000:
-            if self.unit == 0:
+            if unit == 0:
                 return "%.2f km" % (self.dist / 1000)
             else:
                 return "%.2f mi" % (self.dist / 1609.344)
         else:
-            if self.unit == 0:
+            if unit == 0:
                 return "%d m" % self.dist
             else:
                 return "%d ft" % int(self.dist * 3.2808)
 
     def get_avg_speed(self):
+        global unit
         conv = 0
-        if self.unit:
+        if unit:
             conv = 2.23693629
         else:
             conv = 3.6
@@ -199,9 +210,10 @@ class PedoValues():
         return speed * conv
 
     def get_print_avg_speed(self):
+        global unit
         suffix = ""
         conv = 0
-        if self.unit:
+        if unit:
             suffix = "mi/h"
             conv = 2.23693629
         else:
@@ -388,15 +400,21 @@ class PedoRepositoryPickle(PedoRepository):
 class PedoController(Singleton):
     mode = 0
     unit = 0
+    weight = 70
     height_interval = 0
+    sensitivity = 100
     #what to display in second view - 0 - alltime, 1 - today, 2 - week
     second_view = 0
     callback_update_ui = None
     no_idle_time = False
 
     STEP_LENGTH = 0.7
+
+    #The interval(number of steps) between two file updates
+    BUFFER_STEPS_INTERVAL = 100
     #values for the two views in the widget ( current and day/week/alltime)
-    v = [PedoValues(), PedoValues()]
+    #third value to count the steps that were not yet written to file
+    v = [PedoValues(), PedoValues(), PedoValues()]
 
     last_time = 0
     is_running = False
@@ -405,8 +423,10 @@ class PedoController(Singleton):
 
     midnight_set = False
     midnight_source_id = None
+    midnight_before_source_id = None
 
     def __init__(self):
+
         self.pedometer = PedoCounter(self.steps_detected)
         self.pedometerInterval = PedoIntervalCounter()
         self.pedometerInterval.set_mode(self.mode)
@@ -419,17 +439,36 @@ class PedoController(Singleton):
             self.update_at_midnight()
             self.midnight_set = True
 
+        self.config = Config()
+        self.config.add_observer(self.load_config)
+
     def update_at_midnight(self):
         next_day = date.today() + timedelta(days=1)
-        diff = time.mktime(next_day.timetuple()) - time.time()
-        diff = int(diff+5)
-        self.midnight_source_id = gobject.timeout_add_seconds(diff, self.midnight_callback, True)
+        diff = int(time.mktime(next_day.timetuple()) - time.time())
+        diff_before = diff - 5
+        diff_after = diff + 5
+        self.midnight_source_id = gobject.timeout_add_seconds(diff_after, self.midnight_callback, True)
+        self.midnight_before_source_id = gobject.timeout_add_seconds(diff_before, self.midnight_before_callback, True)
 
     def stop_midnight_callback(self):
         if self.midnight_source_id is not None:
             gobject.source_remove(self.midnight_source_id)
+        if self.midnight_before_source_id is not None:
+            gobject.source_remove(self.midnight_before_source_id)
+
+    def midnight_before_callback(self, first=False):
+        logger.info("Before midnight callback")
+        if self.is_running:
+            self.stop_pedometer()
+            self.start_pedometer()
+        if first:
+            self.midnight_before_source_id = gobject.timeout_add_seconds(24*3600, self.midnight_before_callback)
+            return False
+        else:
+            return True
 
     def midnight_callback(self, first=False):
+        logger.info("Midnight callback")
         self.load_values()
         self.notify()
         if first:
@@ -438,6 +477,15 @@ class PedoController(Singleton):
         else:
             return True
 
+    def load_config(self):
+        self.set_height(self.config.get_height(), self.config.get_step_length())
+        self.set_mode(self.config.get_mode())
+        self.set_unit(self.config.get_unit())
+        self.set_weight(self.config.get_weight())
+        self.set_second_view(self.config.get_secondview())
+        self.set_no_idle_time(self.config.get_noidletime())
+        self.set_sensitivity(self.config.get_sensitivity())
+
     def load_values(self):
         if self.second_view == 0:
             self.v[1] = self.repository.get_alltime_values()
@@ -447,12 +495,14 @@ class PedoController(Singleton):
             self.v[1] = self.repository.get_this_week_values()
 
     def save_values(self):
-        self.repository.add_values(self.v[0])
+        logger.info("Saving values to file")
+        self.repository.add_values(self.v[2])
         self.repository.save()
         self.load_values()
 
     def start_pedometer(self):
         self.v[0] = PedoValues()
+        self.v[2] = PedoValues()
         self.last_time = time.time()
         self.is_running = True
         self.pedometer.start()
@@ -460,6 +510,9 @@ class PedoController(Singleton):
 
     def reset_all_values(self):
         self.repository.reset_values()
+        self.v[0] = PedoValues()
+        self.v[1] = PedoValues()
+        self.v[2] = PedoValues()
         self.notify()
 
     def stop_pedometer(self):
@@ -471,7 +524,7 @@ class PedoController(Singleton):
 
     def get_second(self):
         if self.is_running:
-            return self.v[0] + self.v[1]
+            return self.v[2] + self.v[1]
         else:
             return self.v[1]
 
@@ -490,6 +543,17 @@ class PedoController(Singleton):
             self.v[0].dist += self.get_distance(cnt)
             self.v[0].calories += self.get_calories(self.get_distance(cnt))
             self.v[0].time += time.time() - self.last_time
+
+            self.v[2].steps += cnt
+            self.v[2].dist += self.get_distance(cnt)
+            self.v[2].calories += self.get_calories(self.get_distance(cnt))
+            self.v[2].time += time.time() - self.last_time
+
+            if not last_steps and self.v[2].steps > self.BUFFER_STEPS_INTERVAL:
+                self.save_values()
+                self.notify()
+                self.v[2] = PedoValues()
+
             if last_steps:
                 self.save_values()
                 self.notify()
@@ -518,14 +582,19 @@ class PedoController(Singleton):
     def set_mode(self, mode):
         self.mode = mode
         self.set_height(self.height_interval)
+        self.pedometerInterval.set_mode(self.mode)
         self.notify()
 
     def set_unit(self, new_unit):
         self.unit = new_unit
+        global unit
         unit = new_unit
+        self.notify()
 
-    def get_str_weight_unit(self):
-        if self.unit == 0:
+    def get_str_weight_unit(self, unit=None):
+        if unit is None:
+            unit = self.unit
+        if unit == 0:
             return "kg"
         else:
             return "lb"
@@ -537,6 +606,13 @@ class PedoController(Singleton):
     def get_weight(self):
         return self.weight
 
+    def set_sensitivity(self, value):
+        self.sensitivity = value
+        self.pedometerInterval.set_sensitivity(value)
+
+    def get_sensitivity(self):
+        return self.sensitivity
+
     def set_second_view(self, second_view):
         self.second_view = second_view
         self.load_values()
@@ -545,8 +621,11 @@ class PedoController(Singleton):
     def set_callback_ui(self, func):
         self.callback_update_ui = func
 
-    def set_height(self, height_interval):
-        self.height_inteval = height_interval
+    def set_height(self, height_interval, step_length=None):
+        self.height_interval = height_interval
+
+        if step_length is None:
+            step_length = self.STEP_LENGTH
         #set height, will affect the distance
         if height_interval == 0:
             self.STEP_LENGTH = 0.59
@@ -558,6 +637,8 @@ class PedoController(Singleton):
             self.STEP_LENGTH = 0.77
         elif height_interval == 4:
             self.STEP_LENGTH = 0.83
+        elif height_interval == 5:
+            self.STEP_LENGTH = step_length
         #increase step length if RUNNING
         if self.mode == 1:
             self.STEP_LENGTH *= 1.45
@@ -599,11 +680,8 @@ class AlarmController(Singleton):
 
     def __init__(self):
         self.client = gconf.client_get_default()
-
-        self.enable = self.client.get_bool(ALARM_ENABLE)
-        self.fname = self.client.get_string(ALARM_FNAME)
-        self.interval = self.client.get_int(ALARM_INTERVAL)
-        self.type = self.client.get_int(ALARM_TYPE)
+        self.config = Config()
+        self.config.add_observer(self.load_config)
 
         self.pedo_controller = PedoController()
         if self.enable:
@@ -654,11 +732,17 @@ class AlarmController(Singleton):
             self.is_playing = True
 
     def stop(self):
-        self.player.set_state(gst.STATE_NULL)
+        if self.player is not None:
+            self.player.set_state(gst.STATE_NULL)
+
+    def load_config(self):
+        self.enable  = self.config.get_alarm_enable()
+        self.set_alarm_file(self.config.get_alarm_fname())
+        self.set_interval(self.config.get_alarm_interval())
+        self.set_type(self.config.get_alarm_type())
 
     def set_enable(self, value):
        self.enable = value
-       self.client.set_bool(ALARM_ENABLE, value)
        if self.enable:
            self.init_player()
            self.pedo_controller.add_observer(self.update)
@@ -673,7 +757,6 @@ class AlarmController(Singleton):
 
     def set_alarm_file(self, fname):
         self.fname = fname
-        self.client.set_string(ALARM_FNAME, fname)
 
     def get_alarm_file(self):
         if self.fname == None:
@@ -682,14 +765,12 @@ class AlarmController(Singleton):
 
     def set_interval(self, interval):
         self.interval = interval
-        self.client.set_int(ALARM_INTERVAL, interval)
 
     def get_interval(self):
         return self.interval
 
     def set_type(self, type):
         self.type = type
-        self.client.set_int(ALARM_TYPE, type)
 
     def get_type(self):
         return self.type
@@ -852,10 +933,18 @@ class GraphController(Singleton):
     ytitles = ["Steps", "Average Speed", "Distance", "Calories"]
     xtitles = ["Day", "Week"] # "Today"]
     widget = None
+
+    config = None
+
     def __init__(self):
         self.repository = PedoRepositoryXML()
         self.last_update = 0
         PedoController().add_observer(self.update_ui)
+        self.config = Config()
+        self.config.add_observer(self.load_config)
+
+    def load_config(self):
+        self.set_current_view(self.config.get_graphview())
 
     def set_graph(self, widget):
         self.widget = widget
@@ -866,17 +955,15 @@ class GraphController(Singleton):
         current_view % len(ytitles) - gives the ytitle
         current_view / len(ytitles) - gives the xtitle
         """
-        self.current_view = view
-
-        if self.current_view == len(self.ytitles) * len(self.xtitles):
-            self.current_view = 0
-        self.x_id = self.current_view / len(self.ytitles)
-        self.y_id = self.current_view % len(self.ytitles)
+        self.x_id = view / len(self.ytitles)
+        self.y_id = view % len(self.ytitles)
+        self.update_ui()
 
     def next_view(self):
-        self.set_current_view(self.current_view+1)
-        self.update_ui()
-        return self.current_view
+        current_view = self.config.get_graphview() + 1
+        if current_view == len(self.ytitles) * len(self.xtitles):
+            current_view = 0
+        self.config.set_graphview(current_view)
 
     def last_weeks_labels(self):
         d = date.today()
@@ -1068,6 +1155,149 @@ class GraphWidget(gtk.DrawingArea):
             cr.move_to(-xx, yy + bar_width*1.25 / 2)
             cr.show_text(self.xtext[i])
 
+class Config(Singleton):
+    mode = 0
+    height = 0
+    step_length = 0.7
+    weight = 70
+    sensitivity = 100
+    unit = 0
+    aspect = 0
+    sensitivity = 100
+    second_view = 0
+    graph_view = 0
+    no_idle_time = False
+    logging = False
+
+    alarm_enable = False
+    alarm_fname = "/home/user/MyDocs/.sounds/Ringtones/Bicycle.aac"
+    alarm_interval = 5
+    alarm_type = 0
+
+    observers = []
+
+    def __init__(self):
+        if self._references > 1:
+            return
+        self.client = gconf.client_get_default()
+        self.client.add_dir('/apps/pedometerhomewidget', gconf.CLIENT_PRELOAD_RECURSIVE)
+        self.notify_id = self.client.notify_add('/apps/pedometerhomewidget', self.gconf_changed)
+
+    def add_observer(self, func):
+        try:
+            self.observers.index(func)
+        except:
+            self.observers.append(func)
+            func()
+
+    def remove_observer(self, func):
+        self.observers.remove(func)
+
+    def gconf_changed(self, client, *args, **kargs):
+        self.notify()
+
+    def notify(self):
+        t1 = time.time()
+        for func in self.observers:
+            func()
+        t2 = time.time()
+        logger.info("Update took: %f seconds" % (t2-t1))
+
+    def get_mode(self):
+        return self.client.get_int(MODE)
+
+    def set_mode(self, value):
+        self.client.set_int(MODE, value)
+
+    def get_height(self):
+        return self.client.get_int(HEIGHT)
+
+    def set_height(self, value):
+        self.client.set_int(HEIGHT, value)
+
+    def get_step_length(self):
+        return self.client.get_float(STEP_LENGTH)
+
+    def set_step_length(self, value):
+        self.client.set_float(STEP_LENGTH, value)
+
+    def get_weight(self):
+        return self.client.get_int(WEIGHT)
+
+    def set_weight(self, value):
+        self.client.set_int(WEIGHT, value)
+
+    def get_sensitivity(self):
+        return self.client.get_int(SENSITIVITY)
+
+    def set_sensitivity(self, value):
+        self.client.set_int(SENSITIVITY, value)
+
+    def get_unit(self):
+        return self.client.get_int(UNIT)
+
+    def set_unit(self, value):
+        self.client.set_int(UNIT, value)
+
+    def get_aspect(self):
+        return self.client.get_int(ASPECT)
+
+    def set_aspect(self, value):
+        self.client.set_int(ASPECT, value)
+
+    def get_secondview(self):
+        value = self.client.get_int(SECONDVIEW)
+        if value < 0 or value > 2:
+            value = 0
+            logger.error("Invalid secondview value read from Gconf. Using default value")
+
+        return value
+
+    def set_secondview(self, value):
+        self.client.set_int(SECONDVIEW, value)
+
+    def get_graphview(self):
+        return self.client.get_int(GRAPHVIEW)
+
+    def set_graphview(self, value):
+        self.client.set_int(GRAPHVIEW, value)
+
+    def get_noidletime(self):
+        return self.client.get_bool(NOIDLETIME)
+
+    def set_noidletime(self, value):
+        self.client.set_bool(NOIDLETIME, value)
+
+    def get_logging(self):
+        return self.client.get_bool(LOGGING)
+
+    def set_logging(self, value):
+        self.client.set_bool(LOGGING, value)
+
+    def get_alarm_enable(self):
+        return self.client.get_bool(ALARM_ENABLE)
+
+    def set_alarm_enable(self, value):
+        self.client.set_bool(ALARM_ENABLE, value)
+
+    def get_alarm_fname(self):
+        return self.client.get_string(ALARM_FNAME)
+
+    def set_alarm_fname(self, value):
+        self.client.set_string(ALARM_FNAME, value)
+
+    def get_alarm_interval(self):
+        return self.client.get_int(ALARM_INTERVAL)
+
+    def set_alarrm_interval(self, value):
+        self.client.set_int(ALARM_INTERVAL, value)
+
+    def get_alarm_type(self):
+        return self.client.get_int(ALARM_TYPE)
+
+    def set_alarm_type(self, value):
+        self.client.set_int(ALARM_TYPE, value)
+
 class PedometerHomePlugin(hildondesktop.HomePluginItem):
     button = None
 
@@ -1085,15 +1315,7 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
     controller = None
     graph_controller = None
 
-    mode = 0
-    height = 0
-    weight = 70
-    unit = 0
-    aspect = 0
-    second_view = 0
-    graph_view = 0
-    no_idle_time = False
-    logging = False
+    config = None
 
     def __init__(self):
         hildondesktop.HomePluginItem.__init__(self)
@@ -1101,39 +1323,21 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
         gobject.type_register(CustomEventBox)
         gobject.type_register(GraphWidget)
 
-        self.client = gconf.client_get_default()
+        self.config = Config()
 
-        self.mode = self.client.get_int(MODE)
-        self.height = self.client.get_int(HEIGHT)
-        self.weight = self.client.get_int(WEIGHT)
-        self.unit = self.client.get_int(UNIT)
-        self.aspect = self.client.get_int(ASPECT)
-        self.second_view = self.client.get_int(SECONDVIEW)
-        self.graph_view = self.client.get_int(GRAPHVIEW)
-        self.no_idle_time = self.client.get_bool(NOIDLETIME)
-        self.logging = self.client.get_bool(LOGGING)
+        self.button = CustomButton(ICONSPATH + "play.png")
+        self.button.connect("clicked", self.button_clicked)
+
+        self.create_labels(self.labelsC)
+        self.create_labels(self.labelsT)
+        self.label_second_view = self.new_label_heading(self.second_view_labels[self.config.get_secondview()])
 
         self.controller = PedoController()
-        self.controller.set_height(self.height)
-        self.controller.set_weight(self.weight)
-        self.controller.set_mode(self.mode)
-        self.controller.set_unit(self.unit)
-        self.controller.set_second_view(self.second_view)
         self.controller.set_callback_ui(self.update_values)
-        self.controller.set_no_idle_time(self.no_idle_time)
 
         self.graph_controller = GraphController()
-        self.graph_controller.set_current_view(self.graph_view)
-
         self.alarm_controller = AlarmController()
 
-        self.button = CustomButton(ICONSPATH + "play.png")
-        self.button.connect("clicked", self.button_clicked)
-
-        self.create_labels(self.labelsC)
-        self.create_labels(self.labelsT)
-        self.label_second_view = self.new_label_heading(self.second_view_labels[self.second_view])
-
         self.update_current()
         self.update_total()
 
@@ -1200,19 +1404,18 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
 
         self.mainvbox.show_all()
         self.add(self.mainvbox)
-        self.update_aspect()
 
         self.connect("unrealize", self.close_requested)
         self.set_settings(True)
         self.connect("show-settings", self.show_settings)
 
+        self.config.add_observer(self.update_aspect)
+
     def eventBoxGraph_clicked(self, widget, data=None):
         widget.set_state(gtk.STATE_ACTIVE)
 
     def eventBoxGraph_clicked_release(self, widget, data=None):
-        self.graph_view = self.graph_controller.next_view()
-        self.client.set_int(GRAPHVIEW, self.graph_view)
-
+        self.graph_controller.next_view()
         widget.set_state(gtk.STATE_NORMAL)
 
     def eventBox_clicked(self, widget, data=None):
@@ -1221,9 +1424,9 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
     def eventBox_clicked_release(self, widget, data=None):
         widget.set_state(gtk.STATE_NORMAL)
 
-        self.second_view = (self.second_view + 1) % 3
-        self.controller.set_second_view(self.second_view)
-        self.client.set_int(SECONDVIEW, self.second_view)
+        second_view = self.config.get_secondview()
+        second_view = (second_view + 1) % 3
+        self.config.set_secondview(second_view)
 
     def new_label_heading(self, title=""):
         l = gtk.Label(title)
@@ -1238,16 +1441,16 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
             new_labels[label] = l
 
     def update_aspect(self):
-
-        if self.aspect > 0:
+        aspect = self.config.get_aspect()
+        if aspect > 0:
             self.graphBox.hide_all()
         else:
             self.graphBox.show_all()
 
-        if self.aspect == 0 or self.aspect == 1:
+        if aspect == 0 or aspect == 1:
             self.currentBox.show_all()
             self.totalBox.show_all()
-        elif self.aspect == 2:
+        elif aspect == 2:
             self.currentBox.show_all()
             self.totalBox.hide_all()
         else:
@@ -1277,7 +1480,7 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
             if ( file.run() == gtk.RESPONSE_OK):
                 fname = file.get_filename()
                 widget.set_value(fname)
-                self.alarm_controller.set_alarm_file(fname)
+                self.config.set_alarm_fname(fname)
             file.destroy()
 
         def test_sound(button):
@@ -1289,15 +1492,16 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
 
         def enableButton_changed(button):
             value = button.get_active()
-            self.alarm_controller.set_enable(value)
+            self.config.set_alarm_enable(value)
             if value:
                 main_button.set_value("Enabled")
             else:
                 main_button.set_value("Disabled")
 
         def selectorType_changed(selector, data, labelEntry2):
-            self.alarm_controller.set_type(selector.get_active(0))
-            labelEntry2.set_label(suffix[self.alarm_controller.get_type()])
+            type = selector.get_active(0)
+            self.config.set_alarm_type(type)
+            labelEntry2.set_label(suffix[type])
 
         dialog = gtk.Dialog()
         dialog.set_title("Alarm settings")
@@ -1356,7 +1560,7 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
                 break
             try:
                 value = int(intervalEntry.get_text())
-                self.alarm_controller.set_interval(value)
+                self.config.set_alarrm_interval(value)
                 break
             except:
                 hildon.hildon_banner_show_information(self, "None", "Invalid interval")
@@ -1376,33 +1580,31 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
             self.show_alarm_settings(widget)
 
         def selector_changed(selector, data):
-            widget.mode = selector.get_active(0)
-            widget.client.set_int(MODE, widget.mode)
-            widget.controller.set_mode(widget.mode)
-
-        def selectorH_changed(selector, data):
-            widget.height = selectorH.get_active(0)
-            widget.client.set_int(HEIGHT, widget.height)
-            widget.controller.set_height(widget.height)
+            mode = selector.get_active(0)
+            self.config.set_mode(mode)
 
         def selectorUnit_changed(selector, data):
-            widget.unit = selectorUnit.get_active(0)
-            widget.client.set_int(UNIT, widget.unit)
-            widget.controller.set_unit(widget.unit)
+            unit = selector.get_active(0)
+            self.config.set_unit(unit)
+
+            update_weight_button()
+            stepLengthButton_value_update()
 
         def selectorUI_changed(selector, data):
-            widget.aspect = selectorUI.get_active(0)
-            widget.client.set_int(ASPECT, widget.aspect)
-            widget.update_aspect()
+            aspect = selectorUI.get_active(0)
+            self.config.set_aspect(aspect)
 
         def logButton_changed(checkButton):
-            widget.logging = checkButton.get_active()
-            widget.client.set_bool(LOGGING, widget.logging)
+            logging = checkButton.get_active()
+            self.config.set_logging(logging)
 
         def idleButton_changed(idleButton):
-            widget.no_idle_time = idleButton.get_active()
-            widget.client.set_bool(NOIDLETIME, widget.no_idle_time)
-            widget.controller.set_no_idle_time(widget.no_idle_time)
+            no_idle_time = idleButton.get_active()
+            self.config.set_noidletime(no_idle_time)
+
+        def update_weight_button():
+            weightButton.set_value(str(self.config.get_weight()) + \
+                                           " " + self.controller.get_str_weight_unit(self.config.get_unit()) )
 
         def weight_dialog(button):
             dialog = gtk.Dialog("Weight", self.dialog)
@@ -1410,9 +1612,9 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
 
             label = gtk.Label("Weight:")
             entry = gtk.Entry()
-            entry.set_text(str(self.controller.get_weight()))
+            entry.set_text(str(self.config.get_weight()))
 
-            suffixLabel = gtk.Label(self.controller.get_str_weight_unit())
+            suffixLabel = gtk.Label(self.controller.get_str_weight_unit(self.config.get_unit()))
 
             hbox = gtk.HBox()
             hbox.add(label)
@@ -1429,28 +1631,174 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
                     value = int(entry.get_text())
                     if value <= 0:
                         raise ValueError
-                    self.controller.set_weight(value)
-                    self.client.set_int(WEIGHT, value)
-                    weightButton.set_value(str(self.controller.get_weight()) + \
-                                           " " + self.controller.get_str_weight_unit() )
+                    self.config.set_weight(value)
+                    update_weight_button()
                     break
                 except:
                     hildon.hildon_banner_show_information(self, "None", "Invalid weight")
             dialog.destroy()
 
+        def sensitivity_dialog(button):
+            def seekbar_changed(seekbar):
+                label.set_text(str(seekbar.get_position()) + " %")
+
+            dialog = gtk.Dialog("Sensitivity", self.dialog)
+            dialog.add_button("OK", gtk.RESPONSE_OK)
+            seekbar = hildon.Seekbar()
+            seekbar.set_size_request(400, -1)
+            seekbar.set_total_time(200)
+            seekbar.set_position(self.config.get_sensitivity())
+            seekbar.connect("value-changed", seekbar_changed)
+
+            hbox = gtk.HBox()
+            hbox.add(seekbar)
+            label = gtk.Label(str(self.config.get_sensitivity()) + " %")
+            label.set_size_request(30, -1)
+            hbox.add(label)
+
+            dialog.vbox.add(hbox)
+            dialog.show_all()
+
+            if dialog.run() == gtk.RESPONSE_OK:
+                value = seekbar.get_position()
+                self.config.set_sensitivity(value)
+                button.set_value(str(value) + " %")
+
+            dialog.destroy()
+
+        def stepLengthButton_value_update():
+            if self.config.get_height() == 5:
+                l_unit = ["m", "ft"]
+                stepLengthButton.set_value("Custom value: %.2f %s" % (self.config.get_step_length(), l_unit[self.config.get_unit()]))
+            else:
+                h = [ ["< 1.50 m", "1.50 - 1.65 m", "1.66 - 1.80 m", "1.81 - 1.95 m", " > 1.95 m"],
+                      ["< 5 ft", "5 - 5.5 ft", "5.5 - 6 ft", "6 - 6.5 ft", "> 6.5 ft"]]
+                str = "Using predefined value for height: %s" % h[self.config.get_unit()][self.config.get_height()]
+                stepLengthButton.set_value(str)
+
+        def stepLength_dialog(button):
+            def selectorH_changed(selector, data, dialog):
+                height = selector.get_active(0)
+                self.config.set_height(height)
+                stepLengthButton_value_update()
+
+            def manualButton_clicked(button, dialog):
+                dlg = gtk.Dialog()
+                dlg.set_title("Custom step length")
+                dlg.add_button("OK", gtk.RESPONSE_OK)
+
+                label = gtk.Label("Length")
+
+                entry = hildon.Entry(gtk.HILDON_SIZE_AUTO_WIDTH)
+                if self.config.get_height() == 5:
+                    entry.set_text(str(self.config.get_step_length()))
+
+                labelSuffix = gtk.Label()
+                if self.config.get_unit() == 0:
+                    labelSuffix.set_label("m")
+                else:
+                    labelSuffix.set_label("ft")
+                hbox = gtk.HBox()
+                hbox.add(label)
+                hbox.add(entry)
+                hbox.add(labelSuffix)
+                dlg.vbox.add(hbox)
+                dlg.show_all()
+
+                while 1:
+                    response = dlg.run()
+                    if response != gtk.RESPONSE_OK:
+                        break
+                    try:
+                        value = float(entry.get_text())
+                        if value <= 0:
+                            raise ValueError
+                        self.config.set_step_length(value)
+                        self.config.set_height(5)
+                        stepLengthButton_value_update()
+                        break
+                    except ValueError:
+                        hildon.hildon_banner_show_information(self, "None", "Invalid length")
+                dlg.destroy()
+                dialog.destroy()
+
+            def heightButton_clicked(button, dialog):
+                dialog.destroy()
+
+            dialog = gtk.Dialog()
+            dialog.set_title("Step length")
+
+            manualButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+            manualButton.set_title("Enter custom value")
+            manualButton.set_alignment(0, 0.8, 1, 1)
+            manualButton.connect("clicked", manualButton_clicked, dialog)
+
+            selectorH = hildon.TouchSelector(text=True)
+            selectorH.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
+            selectorH.append_text("< 1.50 m")
+            selectorH.append_text("1.50 - 1.65 m")
+            selectorH.append_text("1.66 - 1.80 m")
+            selectorH.append_text("1.81 - 1.95 m")
+            selectorH.append_text(" > 1.95 m")
+
+            selectorH_English = hildon.TouchSelector(text=True)
+            selectorH_English.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
+            selectorH_English.append_text("< 5 ft")
+            selectorH_English.append_text("5 - 5.5 ft")
+            selectorH_English.append_text("5.5 - 6 ft")
+            selectorH_English.append_text("6 - 6.5 ft")
+            selectorH_English.append_text("> 6.5 ft")
+
+            heightPicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+            heightPicker.set_alignment(0.0, 0.5, 1.0, 1.0)
+            heightPicker.set_title("Use predefined values for height")
+
+
+            unit = self.config.get_unit()
+            if unit == 0:
+                heightPicker.set_selector(selectorH)
+            else:
+                heightPicker.set_selector(selectorH_English)
+
+            height = self.config.get_height()
+            if height < 5:
+                heightPicker.set_active(height)
+
+            heightPicker.get_selector().connect("changed", selectorH_changed, dialog)
+            heightPicker.connect("value-changed", heightButton_clicked, dialog)
+
+            dialog.vbox.add(heightPicker)
+            dialog.vbox.add(manualButton)
+            dialog.show_all()
+
+            if  dialog.run() == gtk.RESPONSE_DELETE_EVENT:
+                dialog.destroy()
+
+        def donateButton_clicked(button, dialog):
+            url = "https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=BKE6E9SLK7NP4&lc=RO&item_name=Pedometer%20Widget&currency_code=EUR&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted"
+            command = "dbus-send --system --type=method_call --dest=\"com.nokia.osso_browser\"  --print-reply /com/nokia/osso_browser/request com.nokia.osso_browser.load_url string:\"%s\"" % url
+            os.system(command)
+
         dialog = gtk.Dialog()
         dialog.set_title("Settings")
         dialog.add_button("OK", gtk.RESPONSE_OK)
         self.dialog = dialog
 
+        stepLengthButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+        stepLengthButton.set_title("Step length")
+        stepLengthButton.set_alignment(0, 0.8, 1, 1)
+        stepLengthButton.connect("clicked", stepLength_dialog)
+        stepLengthButton_value_update()
+
         resetButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
-        resetButton.set_title("Reset total counter")
+        resetButton.set_title("Reset")
+        resetButton.set_value("All the stored values will be erased")
         resetButton.set_alignment(0, 0.8, 1, 1)
         resetButton.connect("clicked", reset_total_counter)
 
         alarmButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
         alarmButton.set_title("Alarm")
-        if self.alarm_controller.get_enable():
+        if self.config.get_alarm_enable():
             alarmButton.set_value("Enabled")
         else:
             alarmButton.set_value("Disabled")
@@ -1467,27 +1815,12 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
         modePicker.set_alignment(0.0, 0.5, 1.0, 1.0)
         modePicker.set_title("Mode")
         modePicker.set_selector(selector)
-        modePicker.set_active(widget.mode)
-
-        selectorH = hildon.TouchSelector(text=True)
-        selectorH.set_column_selection_mode(hildon.TOUCH_SELECTOR_SELECTION_MODE_SINGLE)
-        selectorH.append_text("< 1.50 m")
-        selectorH.append_text("1.50 - 1.65 m")
-        selectorH.append_text("1.66 - 1.80 m")
-        selectorH.append_text("1.81 - 1.95 m")
-        selectorH.append_text(" > 1.95 m")
-        selectorH.connect("changed", selectorH_changed)
-
-        heightPicker = hildon.PickerButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
-        heightPicker.set_alignment(0.0, 0.5, 1.0, 1.0)
-        heightPicker.set_title("Height")
-        heightPicker.set_selector(selectorH)
-        heightPicker.set_active(widget.height)
+        modePicker.set_active(self.config.get_mode())
 
         weightButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
         weightButton.set_title("Weight")
         weightButton.set_alignment(0, 0.8, 1, 1)
-        weightButton.set_value(str(self.controller.get_weight()) + " " + self.controller.get_str_weight_unit() )
+        update_weight_button()
         weightButton.connect("clicked", weight_dialog)
 
         selectorUnit = hildon.TouchSelector(text=True)
@@ -1500,7 +1833,7 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
         unitPicker.set_alignment(0.0, 0.5, 1.0, 1.0)
         unitPicker.set_title("Unit")
         unitPicker.set_selector(selectorUnit)
-        unitPicker.set_active(widget.unit)
+        unitPicker.set_active(self.config.get_unit())
 
         selectorUI = hildon.TouchSelector(text=True)
         selectorUI = hildon.TouchSelector(text=True)
@@ -1515,28 +1848,42 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
         UIPicker.set_alignment(0.0, 0.5, 1.0, 1.0)
         UIPicker.set_title("Widget aspect")
         UIPicker.set_selector(selectorUI)
-        UIPicker.set_active(widget.aspect)
+        UIPicker.set_active(self.config.get_aspect())
+
+        sensitivityButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+        sensitivityButton.set_title("Sensitivity")
+        sensitivityButton.set_alignment(0, 0.8, 1, 1)
+        sensitivityButton.set_value(str(self.config.get_sensitivity()) + " %")
+        sensitivityButton.connect("clicked", sensitivity_dialog)
+
+        donateButton = hildon.Button(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT, hildon.BUTTON_ARRANGEMENT_VERTICAL)
+        donateButton.set_title("Donate")
+        donateButton.set_value("Please support the development of this opensource widget!")
+        donateButton.set_alignment(0, 0.8, 1, 1)
+        donateButton.connect("clicked", donateButton_clicked, dialog)
 
         logButton = hildon.CheckButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT)
         logButton.set_label("Log data")
-        logButton.set_active(widget.logging)
+        logButton.set_active(self.config.get_logging())
         logButton.connect("toggled", logButton_changed)
 
         idleButton = hildon.CheckButton(gtk.HILDON_SIZE_AUTO_WIDTH | gtk.HILDON_SIZE_FINGER_HEIGHT)
         idleButton.set_label("Pause time when not walking")
-        idleButton.set_active(widget.no_idle_time)
+        idleButton.set_active(self.config.get_noidletime())
         idleButton.connect("toggled", idleButton_changed)
 
         pan_area = hildon.PannableArea()
         vbox = gtk.VBox()
         vbox.add(alarmButton)
         vbox.add(modePicker)
-        vbox.add(heightPicker)
+        vbox.add(stepLengthButton)
         vbox.add(weightButton)
         vbox.add(unitPicker)
+        vbox.add(sensitivityButton)
         vbox.add(UIPicker)
         vbox.add(idleButton)
         vbox.add(resetButton)
+        vbox.add(donateButton)
         #vbox.add(logButton)
 
         pan_area.add_with_viewport(vbox)
@@ -1544,8 +1891,8 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
 
         dialog.vbox.add(pan_area)
         dialog.show_all()
+
         response = dialog.run()
-        #hildon.hildon_banner_show_information(self, "None", "You have to Stop/Start the counter to apply the new settings")
         dialog.destroy()
 
     def close_requested(self, widget):
@@ -1555,7 +1902,7 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
 
     def update_values(self):
         #TODO: do not update if the widget is not on the active desktop
-        self.label_second_view.set_label(self.second_view_labels[self.second_view])
+        self.label_second_view.set_label(self.second_view_labels[self.config.get_secondview()])
         self.update_current()
         self.update_total()
 
@@ -1566,6 +1913,7 @@ class PedometerHomePlugin(hildondesktop.HomePluginItem):
         else:
             self.controller.start_pedometer()
             self.button.set_icon(ICONSPATH + "stop.png")
+            hildon.hildon_banner_show_information(self, "None", "Keep the N900 in a pocket close to your hip for best results")
 
     def do_expose_event(self, event):
         cr = self.window.cairo_create()