Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#136] Add 'recent activities' to tracking screen #208

Open
wants to merge 25 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
54fcc75
Wrap 'make test' with 'xvfb-run'
elbenfreund Jul 8, 2017
975623e
Add inline comments
elbenfreund Jun 22, 2017
334753c
Add dedicated helper for fetching recent activities
elbenfreund Jun 22, 2017
4c5b85e
Add 'recent activities' to start-tracking view
elbenfreund Jun 22, 2017
5c17e7a
Sizing for recent activity widget
elbenfreund Jul 1, 2017
d941aab
Adjust existing tests
elbenfreund Jul 8, 2017
8593902
rename 'row_counter' parameter to 'row_index'
elbenfreund Sep 22, 2017
c08bd74
Fix typo
elbenfreund Sep 22, 2017
bec62d8
Change wording within preferences.
elbenfreund Sep 22, 2017
ddafbd1
fix ordering for 'get_recent_activities' helper
elbenfreund Sep 22, 2017
fa93742
Account for empty children when figuring out min_height
elbenfreund Sep 22, 2017
5b16ae9
Recent activities box uses last 24h
elbenfreund Sep 26, 2017
bd39965
Fix docstring
elbenfreund Sep 26, 2017
9ccdc80
Improve 'config' fixture
elbenfreund Sep 26, 2017
09aaac6
Fix 'app' fixture
elbenfreund Sep 26, 2017
95fc765
Fix test if 'HamsterGTK' instantiation
elbenfreund Sep 27, 2017
c0dd639
Rename 'tracking_recent_activities_items' to 'count'
elbenfreund Sep 27, 2017
2177d68
helpers: Refactor 'serialize_activity'
elbenfreund Nov 17, 2017
4b2819b
tracking: Improve categoryless fact serialization
elbenfreund May 4, 2018
90dbcc7
Fix typos
elbenfreund May 4, 2018
fa8057d
tracking: Add issue reference to ToDo comment
elbenfreund May 4, 2018
72af08c
helpers: Remove 'none_category' argument on serialize_activity
elbenfreund May 4, 2018
d685bf2
tests: Fix docker setup
elbenfreund May 4, 2018
c510594
Fix imports
elbenfreund May 6, 2018
1df269a
helpers: Add tests for 'serialize_activity'
elbenfreund May 6, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ lint:
flake8 hamster-dbus tests

test:
py.test $(TEST_ARGS) tests/
xvfb-run py.test $(TEST_ARGS) tests/

test-all:
tox
Expand Down
6 changes: 2 additions & 4 deletions ci/run_docker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@ xvfb=$!

export DISPLAY=:99

pip install --upgrade pip
pip install -r requirements/test.pip

python setup.py install
pip install .
make resources

make test-all

# See: https://docs.codecov.io/docs/testing-with-docker for details
bash <(curl -s https://codecov.io/bash)
test $err = 0
33 changes: 28 additions & 5 deletions hamster_gtk/hamster_gtk.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ class SignalHandler(GObject.GObject):
them via its class instances.
"""

# [TODO]
# Explain semantics of each signal
# [TODO]
# Add signals for all changed hamster-lib objects?

__gsignals__ = {
str('facts-changed'): (GObject.SIGNAL_RUN_LAST, None, ()),
str('daterange-changed'): (GObject.SIGNAL_RUN_LAST, None, (GObject.TYPE_PYOBJECT,)),
Expand Down Expand Up @@ -255,6 +260,7 @@ def _reload_config(self):
"""Reload configuration from designated store."""
config = self._get_config_from_file()
self._config = config
self.config = config
return config

def _config_changed(self, sender):
Expand All @@ -279,6 +285,8 @@ def _get_default_config(self):
# Frontend
'autocomplete_activities_range': 30,
'autocomplete_split_activity': False,
'tracking_show_recent_activities': True,
'tracking_recent_activities_count': 6,
}

def _config_to_configparser(self, config):
Expand Down Expand Up @@ -315,6 +323,12 @@ def get_autocomplete_activities_range():
def get_autocomplete_split_activity():
return text_type(config['autocomplete_split_activity'])

def get_tracking_show_recent_activities():
return text_type(config['tracking_show_recent_activities'])

def get_tracking_recent_activities_count():
return text_type(config['tracking_recent_activities_count'])

cp_instance = SafeConfigParser()
cp_instance.add_section('Backend')
cp_instance.set('Backend', 'store', get_store())
Expand All @@ -329,6 +343,10 @@ def get_autocomplete_split_activity():
get_autocomplete_activities_range())
cp_instance.set('Frontend', 'autocomplete_split_activity',
get_autocomplete_split_activity())
cp_instance.set('Frontend', 'tracking_show_recent_activities',
get_tracking_show_recent_activities())
cp_instance.set('Frontend', 'tracking_recent_activities_count',
get_tracking_recent_activities_count())

return cp_instance

Expand Down Expand Up @@ -385,13 +403,21 @@ def get_autocomplete_activities_range():
def get_autocomplete_split_activity():
return cp_instance.getboolean('Frontend', 'autocomplete_split_activity')

def get_tracking_show_recent_activities():
return cp_instance.getboolean('Frontend', 'tracking_show_recent_activities')

def get_tracking_recent_activities_count():
return int(cp_instance.get('Frontend', 'tracking_recent_activities_count'))

result = {
'store': get_store(),
'day_start': get_day_start(),
'fact_min_delta': get_fact_min_delta(),
'tmpfile_path': get_tmpfile_path(),
'autocomplete_activities_range': get_autocomplete_activities_range(),
'autocomplete_split_activity': get_autocomplete_split_activity(),
'tracking_show_recent_activities': get_tracking_show_recent_activities(),
'tracking_recent_activities_count': get_tracking_recent_activities_count(),
}
result.update(get_db_config())
return result
Expand All @@ -407,12 +433,9 @@ def _write_config_to_file(self, configparser_instance):

def _get_config_from_file(self):
"""
Return a config dictionary from acp_instanceg file.
Return a config dictionary from app_instance file.

If there is none create a default config file. This methods main job is
to convert strings from the loaded ConfigParser File to appropiate
instances suitable for our config dictionary. The actual data retrival
is provided by a hamster-lib helper function.
If there is none create a default config file.

Returns:
dict: Dictionary of config key/values.
Expand Down
49 changes: 49 additions & 0 deletions hamster_gtk/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@
from __future__ import absolute_import, unicode_literals

import datetime
import operator
import re
from gettext import gettext as _

import six
from orderedset import OrderedSet
from six import text_type


Expand Down Expand Up @@ -88,6 +91,8 @@ def clear_children(widget):
It seems GTK really does not have this build in. Iterating over all
seems a bit blunt, but seems to be the way to do this.
"""
# [TODO]
# Replace with Gtk.Container.foreach()?
for child in widget.get_children():
child.destroy()
return widget
Expand Down Expand Up @@ -177,6 +182,50 @@ def decompose_raw_fact_string(text, raw=False):
return result


# [TODO]
# Once LIB-251 has been fixed this should no longer be needed.
def get_recent_activities(controller, start, end):
"""Return a list of all activities logged in facts within the given timeframe."""
# [FIXME]
# This manual sorting within python is of course less than optimal. We stick
# with it for now as this is just a preliminary workaround helper anyway and
# effective sorting will need to be implemented by the storage backend in
# ``hamster-lib``.
facts = sorted(controller.facts.get_all(start=start, end=end),
key=operator.attrgetter('start'), reverse=True)
recent_activities = [fact.activity for fact in facts]
return OrderedSet(recent_activities)


def serialize_activity(activity, separator='@'):
"""
Provide a serialized string version of an activity.

Args:
activity (Activity): ``Activity`` instance to serialize.
separator (str, optional): ``string`` used to separate ``activity.name`` and
``category.name``. The separator will be omitted if
``activity.category=None``. Defaults to ``@``.

Returns:
str: A string representation of the passed activity.
"""
if not separator:
raise ValueError(_("No valid separator has been provided."))

category_text = None

if activity.category:
category_text = activity.category.name

if category_text:
result = '{activity_text}{separator}{category_text}'.format(activity_text=activity.name,
category_text=category_text, separator=separator)
else:
result = activity.name
return text_type(result)


def get_delta_string(delta):
"""
Return a human readable representation of ``datetime.timedelta`` instance.
Expand Down
13 changes: 2 additions & 11 deletions hamster_gtk/overview/widgets/fact_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,18 +201,9 @@ def __init__(self, fact):

def _get_activity_widget(self, fact):
"""Return widget to render the activity, including its related category."""
# [FIXME]
# Once 'preferences/config' is live, we can change this.
# Most likly we do not actually need to jump through extra hoops as
# legacy hamster did but just use a i18n'ed string and be done.
if not fact.category:
category = 'not categorised'
else:
category = str(fact.category)
activity_label = Gtk.Label()
activity_label.set_markup("{activity} - {category}".format(
activity=GObject.markup_escape_text(fact.activity.name),
category=GObject.markup_escape_text(category)))
label_text = helpers.serialize_activity(fact.activity)
activity_label.set_markup(GObject.markup_escape_text(label_text))
activity_label.props.halign = Gtk.Align.START
return activity_label

Expand Down
8 changes: 6 additions & 2 deletions hamster_gtk/preferences/preferences_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@

from hamster_gtk.misc.widgets import LabelledWidgetsGrid
from hamster_gtk.preferences.widgets import (ComboFileChooser,
HamsterSwitch,
HamsterComboBoxText,
HamsterSpinButton,
HamsterSpinButton, HamsterSwitch,
SimpleAdjustment, TimeEntry)


Expand Down Expand Up @@ -80,6 +79,11 @@ def __init__(self, parent, app, initial, *args, **kwargs):
('autocomplete_split_activity',
(_("Autocomplete activities and categories separately"),
HamsterSwitch())),
('tracking_show_recent_activities',
(_("Show recent activities for quickly starting tracking."),
HamsterSwitch())),
('tracking_recent_activities_count', (_('How many recent activities?'),
HamsterSpinButton(SimpleAdjustment(0, GObject.G_MAXDOUBLE, 1)))),
]))),
]

Expand Down
2 changes: 1 addition & 1 deletion hamster_gtk/preferences/widgets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

from .combo_file_chooser import ComboFileChooser # NOQA
from .config_widget import ConfigWidget # NOQA
from .hamster_switch import HamsterSwitch # NOQA
from .hamster_combo_box_text import HamsterComboBoxText # NOQA
from .hamster_spin_button import HamsterSpinButton, SimpleAdjustment # NOQA
from .hamster_switch import HamsterSwitch # NOQA
from .time_entry import TimeEntry # NOQA
Loading