def commit(args, modifier=None): from wunderlist.api import tasks from wunderlist.sync import background_sync task = _task(args) prefs = Preferences.current_prefs() prefs.last_list_id = task.list_id task_info = tasks.create_task(task.list_id, task.title, assignee_id=task.assignee_id, recurrence_type=task.recurrence_type, recurrence_count=task.recurrence_count, due_date=task.due_date, reminder_date=task.reminder_date, starred=task.starred, completed=task.completed, note=task.note) # Output must be a UTF-8 encoded string print ('The task was added to ' + task.list_title).encode('utf-8') if modifier == 'alt': import webbrowser webbrowser.open('wunderlist://tasks/%d' % task_info['id']) background_sync()
def commit(args, modifier=None): from wunderlist.api import lists from wunderlist.sync import background_sync list_name = _list_name(args) lists.create_list(list_name) print 'The new list was created' background_sync()
def filter(args): wf = workflow() prefs = Preferences.current_prefs() command = args[1] if len(args) > 1 else None # Show sort options if command == 'sort': for i, order_info in enumerate(_due_orders): wf.add_item(order_info['title'], order_info['subtitle'], arg='-due sort %d' % (i + 1), valid=True, icon=icons.RADIO_SELECTED if order_info['due_order'] == prefs.due_order else icons.RADIO) wf.add_item( 'Highlight skipped recurring tasks', 'Hoists recurring tasks that have been missed multiple times over to the top', arg='-due sort toggle-skipped', valid=True, icon=icons.CHECKBOX_SELECTED if prefs.hoist_skipped_tasks else icons.CHECKBOX) wf.add_item('Back', autocomplete='-due ', icon=icons.BACK) return # Force a sync if not done recently or wait on the current sync if not prefs.last_sync or \ datetime.now() - prefs.last_sync > timedelta(seconds=30) or \ is_running('sync'): sync() conditions = True # Build task title query based on the args for arg in args[1:]: if len(arg) > 1: conditions = conditions & (Task.title.contains(arg) | List.title.contains(arg)) if conditions is None: conditions = True tasks = Task.select().join( List).where(Task.completed_at.is_null() & (Task.due_date < date.today() + timedelta(days=1)) & Task.list.is_null(False) & conditions) # Sort the tasks according to user preference for key in prefs.due_order: order = 'asc' field = None if key[0] == '-': order = 'desc' key = key[1:] if key == 'due_date': field = Task.due_date elif key == 'list.order': field = List.order elif key == 'order': field = Task.order if field: if order == 'asc': tasks = tasks.order_by(field.asc()) else: tasks = tasks.order_by(field.desc()) try: if prefs.hoist_skipped_tasks: tasks = sorted(tasks, key=lambda t: -t.overdue_times) for t in tasks: wf.add_item( u'%s – %s' % (t.list_title, t.title), t.subtitle(), autocomplete='-task %s ' % t.id, icon=icons.TASK_COMPLETED if t.completed else icons.TASK) except OperationalError: background_sync() wf.add_item(u'Sort order', 'Change the display order of due tasks', autocomplete='-due sort', icon=icons.SORT) wf.add_item('Main menu', autocomplete='', icon=icons.BACK) # Make sure tasks stay up-to-date background_sync_if_necessary(seconds=2)
def filter(args): wf = workflow() prefs = Preferences.current_prefs() command = args[1] if len(args) > 1 else None duration_info = _duration_info(prefs.upcoming_duration) if command == 'duration': selected_duration = prefs.upcoming_duration # Apply selected duration option if len(args) > 2: try: selected_duration = int(args[2]) except: pass duration_info = _duration_info(selected_duration) if 'custom' in duration_info: wf.add_item(duration_info['label'], duration_info['subtitle'], arg='-upcoming duration %d' % (duration_info['days']), valid=True, icon=icons.RADIO_SELECTED if duration_info['days'] == selected_duration else icons.RADIO) for duration_info in _durations: wf.add_item(duration_info['label'], duration_info['subtitle'], arg='-upcoming duration %d' % (duration_info['days']), valid=True, icon=icons.RADIO_SELECTED if duration_info['days'] == selected_duration else icons.RADIO) wf.add_item('Back', autocomplete='-upcoming ', icon=icons.BACK) return # Force a sync if not done recently or join if already running if not prefs.last_sync or \ datetime.now() - prefs.last_sync > timedelta(seconds=30) or \ is_running('sync'): sync() wf.add_item(duration_info['label'], subtitle='Change the duration for upcoming tasks', autocomplete='-upcoming duration ', icon=icons.UPCOMING) conditions = True # Build task title query based on the args for arg in args[1:]: if len(arg) > 1: conditions = conditions & (Task.title.contains(arg) | List.title.contains(arg)) if conditions is None: conditions = True tasks = Task.select().join(List).where( Task.completed_at.is_null() & (Task.due_date < date.today() + timedelta(days=duration_info['days'] + 1)) & (Task.due_date > date.today() + timedelta(days=1)) & Task.list.is_null(False) & conditions )\ .join(Reminder, JOIN.LEFT_OUTER, on=Reminder.task == Task.id)\ .order_by(Task.due_date.asc(), Reminder.date.asc(), Task.order.asc()) try: for t in tasks: wf.add_item(u'%s – %s' % (t.list_title, t.title), t.subtitle(), autocomplete='-task %s ' % t.id, icon=icons.TASK_COMPLETED if t.completed else icons.TASK) except OperationalError: background_sync() wf.add_item('Main menu', autocomplete='', icon=icons.BACK) # Make sure tasks stay up-to-date background_sync_if_necessary(seconds=2)
def filter(args): query = ' '.join(args[1:]) wf = workflow() prefs = Preferences.current_prefs() matching_hashtags = [] if not query: wf.add_item('Begin typing to search tasks', '', icon=icons.SEARCH) hashtag_match = re.search(_hashtag_prompt_pattern, query) if hashtag_match: from wunderlist.models.hashtag import Hashtag hashtag_prompt = hashtag_match.group().lower() hashtags = Hashtag.select().where( Hashtag.id.contains(hashtag_prompt)).order_by( fn.Lower(Hashtag.tag).asc()) for hashtag in hashtags: # If there is an exact match, do not show hashtags if hashtag.id == hashtag_prompt: matching_hashtags = [] break matching_hashtags.append(hashtag) # Show hashtag prompt if there is more than one matching hashtag or the # hashtag being typed does not exactly match the single matching hashtag if len(matching_hashtags) > 0: for hashtag in matching_hashtags: wf.add_item(hashtag.tag[1:], '', autocomplete=u'-search %s%s ' % (query[:hashtag_match.start()], hashtag.tag), icon=icons.HASHTAG) else: conditions = True lists = workflow().stored_data('lists') matching_lists = None query = ' '.join(args[1:]).strip() list_query = None # Show all lists on the main search screen if not query: matching_lists = lists # Filter lists when colon is used if ':' in query: matching_lists = lists components = re.split(r':\s*', query, 1) list_query = components[0] if list_query: matching_lists = workflow().filter( list_query, lists if lists else [], lambda l: l['title'], # Ignore MATCH_ALLCHARS which is expensive and inaccurate match_on=MATCH_ALL ^ MATCH_ALLCHARS) # If no matching list search against all tasks if matching_lists: query = components[1] if len(components) > 1 else '' # If there is a list exactly matching the query ignore # anything else. This takes care of lists that are substrings # of other lists if len(matching_lists) > 1: for l in matching_lists: if l['title'].lower() == list_query.lower(): matching_lists = [l] break if matching_lists: if not list_query: wf.add_item('Browse by hashtag', autocomplete='-search #', icon=icons.HASHTAG) if len(matching_lists) > 1: for l in matching_lists: icon = icons.INBOX if l[ 'list_type'] == 'inbox' else icons.LIST wf.add_item(l['title'], autocomplete='-search %s: ' % l['title'], icon=icon) else: conditions = conditions & (Task.list == matching_lists[0]['id']) if not matching_lists or len(matching_lists) <= 1: for arg in query.split(' '): if len(arg) > 1: conditions = conditions & (Task.title.contains(arg) | List.title.contains(arg)) if conditions: if not prefs.show_completed_tasks: conditions = Task.completed_at.is_null() & conditions tasks = Task.select().where( Task.list.is_null(False) & conditions) # Default Wunderlist sort order reversed to show newest first tasks = tasks.join(List).order_by(Task.order.desc(), List.order.asc()) # Avoid excessive results tasks = tasks.limit(50) try: for t in tasks: wf.add_item(u'%s – %s' % (t.list_title, t.title), t.subtitle(), autocomplete='-task %s ' % t.id, icon=icons.TASK_COMPLETED if t.completed else icons.TASK) except OperationalError: background_sync() if prefs.show_completed_tasks: wf.add_item('Hide completed tasks', arg='-pref show_completed_tasks --alfred %s' % ' '.join(args), valid=True, icon=icons.HIDDEN) else: wf.add_item('Show completed tasks', arg='-pref show_completed_tasks --alfred %s' % ' '.join(args), valid=True, icon=icons.VISIBLE) wf.add_item('New search', autocomplete='-search ', icon=icons.CANCEL) wf.add_item('Main menu', autocomplete='', icon=icons.BACK) # Make sure tasks are up-to-date while searching background_sync()
def filter(args): prefs = Preferences.current_prefs() if 'reminder' in args: reminder_time = _parse_time(' '.join(args)) if reminder_time is not None: workflow().add_item('Change default reminder time', u'⏰ %s' % format_time(reminder_time, 'short'), arg=' '.join(args), valid=True, icon=icons.REMINDER) else: workflow().add_item( 'Type a new reminder time', 'Date offsets like the morning before the due date are not supported yet', valid=False, icon=icons.REMINDER) workflow().add_item('Cancel', autocomplete='-pref', icon=icons.BACK) elif 'reminder_today' in args: reminder_today_offset = _parse_time(' '.join(args)) if reminder_today_offset is not None: workflow().add_item('Set a custom reminder offset', u'⏰ now + %s' % _format_time_offset(reminder_today_offset), arg=' '.join(args), valid=True, icon=icons.REMINDER) else: workflow().add_item('Type a custom reminder offset', 'Use the formats hh:mm or 2h 5m', valid=False, icon=icons.REMINDER) workflow().add_item('30 minutes', arg='-pref reminder_today 30m', valid=True, icon=icons.REMINDER) workflow().add_item('1 hour', '(default)', arg='-pref reminder_today 1h', valid=True, icon=icons.REMINDER) workflow().add_item('90 minutes', arg='-pref reminder_today 90m', valid=True, icon=icons.REMINDER) workflow().add_item( 'Always use the default reminder time', 'Avoids adjusting the reminder based on the current date', arg='-pref reminder_today disabled', valid=True, icon=icons.CANCEL) workflow().add_item('Cancel', autocomplete='-pref', icon=icons.BACK) elif 'default_list' in args: lists = workflow().stored_data('lists') matching_lists = lists if len(args) > 2: list_query = ' '.join(args[2:]) if list_query: matching_lists = workflow().filter( list_query, lists, lambda l: l['title'], # Ignore MATCH_ALLCHARS which is expensive and inaccurate match_on=MATCH_ALL ^ MATCH_ALLCHARS) for i, l in enumerate(matching_lists): if i == 1: workflow().add_item( 'Most recently used list', 'Default to the last list to which a task was added', arg='-pref default_list %d' % DEFAULT_LIST_MOST_RECENT, valid=True, icon=icons.RECURRENCE) icon = icons.INBOX if l['list_type'] == 'inbox' else icons.LIST workflow().add_item(l['title'], arg='-pref default_list %s' % l['id'], valid=True, icon=icon) workflow().add_item('Cancel', autocomplete='-pref', icon=icons.BACK) else: current_user = None lists = workflow().stored_data('lists') default_list_name = 'Inbox' try: current_user = User.get() except User.DoesNotExist: pass except OperationalError: from wunderlist.sync import background_sync background_sync() if prefs.default_list_id == DEFAULT_LIST_MOST_RECENT: default_list_name = 'Most recent list' else: default_list_id = prefs.default_list_id default_list_name = next( (l['title'] for l in lists if l['id'] == default_list_id), 'Inbox') if current_user and current_user.name: workflow().add_item('Sign out', 'You are logged in as ' + current_user.name, autocomplete='-logout', icon=icons.CANCEL) workflow().add_item('Show completed tasks', 'Includes completed tasks in search results', arg='-pref show_completed_tasks', valid=True, icon=icons.TASK_COMPLETED if prefs.show_completed_tasks else icons.TASK) workflow().add_item( 'Default reminder time', u'⏰ %s Reminders without a specific time will be set to this time' % format_time(prefs.reminder_time, 'short'), autocomplete='-pref reminder ', icon=icons.REMINDER) workflow().add_item( 'Default reminder when due today', u'⏰ %s Default reminder time for tasks due today is %s' % (_format_time_offset(prefs.reminder_today_offset), 'relative to the current time' if prefs.reminder_today_offset else 'always %s' % format_time(prefs.reminder_time, 'short')), autocomplete='-pref reminder_today ', icon=icons.REMINDER) workflow().add_item( 'Default list', u'%s Change the default list when creating new tasks' % default_list_name, autocomplete='-pref default_list ', icon=icons.LIST) workflow().add_item( 'Automatically set a reminder on the due date', u'Sets a default reminder for tasks with a due date.', arg='-pref automatic_reminders', valid=True, icon=icons.TASK_COMPLETED if prefs.automatic_reminders else icons.TASK) workflow().add_item( 'Require explicit due keyword', 'Requires the due keyword to avoid accidental due date extraction', arg='-pref explicit_keywords', valid=True, icon=icons.TASK_COMPLETED if prefs.explicit_keywords else icons.TASK) workflow().add_item( 'Check for experimental updates to this workflow', 'The workflow automatically checks for updates; enable this to include pre-releases', arg=':pref prerelease_channel', valid=True, icon=icons.TASK_COMPLETED if prefs.prerelease_channel else icons.TASK) workflow().add_item( 'Force sync', 'The workflow syncs automatically, but feel free to be forcible.', arg='-pref sync', valid=True, icon=icons.SYNC) workflow().add_item('Switch theme', 'Toggle between light and dark icons', arg='-pref retheme', valid=True, icon=icons.PAINTBRUSH) workflow().add_item('Main menu', autocomplete='', icon=icons.BACK)
def filter(args): wf = workflow() prefs = Preferences.current_prefs() command = args[1] if len(args) > 1 else None duration_info = _duration_info(prefs.upcoming_duration) if command == 'duration': selected_duration = prefs.upcoming_duration # Apply selected duration option if len(args) > 2: try: selected_duration = int(args[2]) except: pass duration_info = _duration_info(selected_duration) if 'custom' in duration_info: wf.add_item(duration_info['label'], duration_info['subtitle'], arg='-upcoming duration %d' % (duration_info['days']), valid=True, icon=icons.RADIO_SELECTED if duration_info['days'] == selected_duration else icons.RADIO) for duration_info in _durations: wf.add_item(duration_info['label'], duration_info['subtitle'], arg='-upcoming duration %d' % (duration_info['days']), valid=True, icon=icons.RADIO_SELECTED if duration_info['days'] == selected_duration else icons.RADIO) wf.add_item('Back', autocomplete='-upcoming ', icon=icons.BACK) return # Force a sync if not done recently or join if already running if not prefs.last_sync or \ datetime.now() - prefs.last_sync > timedelta(seconds=30) or \ is_running('sync'): sync() wf.add_item(duration_info['label'], subtitle='Change the duration for upcoming tasks', autocomplete='-upcoming duration ', icon=icons.UPCOMING) conditions = True # Build task title query based on the args for arg in args[1:]: if len(arg) > 1: conditions = conditions & (Task.title.contains(arg) | List.title.contains(arg)) if conditions is None: conditions = True tasks = Task.select().join(List).where( Task.completed_at.is_null() & (Task.due_date < date.today() + timedelta(days=duration_info['days'] + 1)) & (Task.due_date > date.today() + timedelta(days=1)) & Task.list.is_null(False) & conditions )\ .join(Reminder, JOIN.LEFT_OUTER, on=Reminder.task == Task.id)\ .order_by(Task.due_date.asc(), Reminder.date.asc(), Task.order.asc()) try: for t in tasks: wf.add_item( u'%s – %s' % (t.list_title, t.title), t.subtitle(), autocomplete='-task %s ' % t.id, icon=icons.TASK_COMPLETED if t.completed else icons.TASK) except OperationalError: background_sync() wf.add_item('Main menu', autocomplete='', icon=icons.BACK) # Make sure tasks stay up-to-date background_sync_if_necessary(seconds=2)
def filter(args): wf = workflow() prefs = Preferences.current_prefs() command = args[1] if len(args) > 1 else None # Show sort options if command == 'sort': for i, order_info in enumerate(_due_orders): wf.add_item(order_info['title'], order_info['subtitle'], arg='-due sort %d' % (i + 1), valid=True, icon=icons.RADIO_SELECTED if order_info['due_order'] == prefs.due_order else icons.RADIO) wf.add_item('Highlight skipped recurring tasks', 'Hoists recurring tasks that have been missed multiple times over to the top', arg='-due sort toggle-skipped', valid=True, icon=icons.CHECKBOX_SELECTED if prefs.hoist_skipped_tasks else icons.CHECKBOX) wf.add_item('Back', autocomplete='-due ', icon=icons.BACK) return # Force a sync if not done recently or wait on the current sync if not prefs.last_sync or \ datetime.now() - prefs.last_sync > timedelta(seconds=30) or \ is_running('sync'): sync() conditions = True # Build task title query based on the args for arg in args[1:]: if len(arg) > 1: conditions = conditions & (Task.title.contains(arg) | List.title.contains(arg)) if conditions is None: conditions = True tasks = Task.select().join(List).where( Task.completed_at.is_null() & (Task.due_date < date.today() + timedelta(days=1)) & Task.list.is_null(False) & conditions ) # Sort the tasks according to user preference for key in prefs.due_order: order = 'asc' field = None if key[0] == '-': order = 'desc' key = key[1:] if key == 'due_date': field = Task.due_date elif key == 'list.order': field = List.order elif key == 'order': field = Task.order if field: if order == 'asc': tasks = tasks.order_by(field.asc()) else: tasks = tasks.order_by(field.desc()) try: if prefs.hoist_skipped_tasks: tasks = sorted(tasks, key=lambda t: -t.overdue_times) for t in tasks: wf.add_item(u'%s – %s' % (t.list_title, t.title), t.subtitle(), autocomplete='-task %s ' % t.id, icon=icons.TASK_COMPLETED if t.completed else icons.TASK) except OperationalError: background_sync() wf.add_item(u'Sort order', 'Change the display order of due tasks', autocomplete='-due sort', icon=icons.SORT) wf.add_item('Main menu', autocomplete='', icon=icons.BACK) # Make sure tasks stay up-to-date background_sync_if_necessary(seconds=2)
def filter(args): prefs = Preferences.current_prefs() if 'reminder' in args: reminder_time = _parse_time(' '.join(args)) if reminder_time is not None: workflow().add_item( 'Change default reminder time', u'⏰ %s' % format_time(reminder_time, 'short'), arg=' '.join(args), valid=True, icon=icons.REMINDER ) else: workflow().add_item( 'Type a new reminder time', 'Date offsets like the morning before the due date are not supported yet', valid=False, icon=icons.REMINDER ) workflow().add_item( 'Cancel', autocomplete='-pref', icon=icons.BACK ) elif 'reminder_today' in args: reminder_today_offset = _parse_time(' '.join(args)) if reminder_today_offset is not None: workflow().add_item( 'Set a custom reminder offset', u'⏰ now + %s' % _format_time_offset(reminder_today_offset), arg=' '.join(args), valid=True, icon=icons.REMINDER ) else: workflow().add_item( 'Type a custom reminder offset', 'Use the formats hh:mm or 2h 5m', valid=False, icon=icons.REMINDER ) workflow().add_item( '30 minutes', arg='-pref reminder_today 30m', valid=True, icon=icons.REMINDER ) workflow().add_item( '1 hour', '(default)', arg='-pref reminder_today 1h', valid=True, icon=icons.REMINDER ) workflow().add_item( '90 minutes', arg='-pref reminder_today 90m', valid=True, icon=icons.REMINDER ) workflow().add_item( 'Always use the default reminder time', 'Avoids adjusting the reminder based on the current date', arg='-pref reminder_today disabled', valid=True, icon=icons.CANCEL ) workflow().add_item( 'Cancel', autocomplete='-pref', icon=icons.BACK ) elif 'default_list' in args: lists = workflow().stored_data('lists') matching_lists = lists if len(args) > 2: list_query = ' '.join(args[2:]) if list_query: matching_lists = workflow().filter( list_query, lists, lambda l: l['title'], # Ignore MATCH_ALLCHARS which is expensive and inaccurate match_on=MATCH_ALL ^ MATCH_ALLCHARS ) for i, l in enumerate(matching_lists): if i == 1: workflow().add_item( 'Most recently used list', 'Default to the last list to which a task was added', arg='-pref default_list %d' % DEFAULT_LIST_MOST_RECENT, valid=True, icon=icons.RECURRENCE ) icon = icons.INBOX if l['list_type'] == 'inbox' else icons.LIST workflow().add_item( l['title'], arg='-pref default_list %s' % l['id'], valid=True, icon=icon ) workflow().add_item( 'Cancel', autocomplete='-pref', icon=icons.BACK ) else: current_user = None lists = workflow().stored_data('lists') loc = user_locale() default_list_name = 'Inbox' try: current_user = User.get() except User.DoesNotExist: pass except OperationalError: from wunderlist.sync import background_sync background_sync() if prefs.default_list_id == DEFAULT_LIST_MOST_RECENT: default_list_name = 'Most recent list' else: default_list_id = prefs.default_list_id default_list_name = next((l['title'] for l in lists if l['id'] == default_list_id), 'Inbox') if current_user and current_user.name: workflow().add_item( 'Sign out', 'You are logged in as ' + current_user.name, autocomplete='-logout', icon=icons.CANCEL ) workflow().add_item( 'Show completed tasks', 'Includes completed tasks in search results', arg='-pref show_completed_tasks', valid=True, icon=icons.TASK_COMPLETED if prefs.show_completed_tasks else icons.TASK ) workflow().add_item( 'Default reminder time', u'⏰ %s Reminders without a specific time will be set to this time' % format_time(prefs.reminder_time, 'short'), autocomplete='-pref reminder ', icon=icons.REMINDER ) workflow().add_item( 'Default reminder when due today', u'⏰ %s Default reminder time for tasks due today is %s' % (_format_time_offset(prefs.reminder_today_offset), 'relative to the current time' if prefs.reminder_today_offset else 'always %s' % format_time(prefs.reminder_time, 'short')), autocomplete='-pref reminder_today ', icon=icons.REMINDER ) workflow().add_item( 'Default list', u'%s Change the default list when creating new tasks' % default_list_name, autocomplete='-pref default_list ', icon=icons.LIST ) workflow().add_item( 'Automatically set a reminder on the due date', u'Sets a default reminder for tasks with a due date.', arg='-pref automatic_reminders', valid=True, icon=icons.TASK_COMPLETED if prefs.automatic_reminders else icons.TASK ) if loc != 'en_US' or prefs.date_locale: workflow().add_item( 'Force US English for dates', 'Rather than the current locale (%s)' % loc, arg='-pref force_en_US', valid=True, icon=icons.TASK_COMPLETED if prefs.date_locale == 'en_US' else icons.TASK ) workflow().add_item( 'Require explicit due keyword', 'Requires the due keyword to avoid accidental due date extraction', arg='-pref explicit_keywords', valid=True, icon=icons.TASK_COMPLETED if prefs.explicit_keywords else icons.TASK ) workflow().add_item( 'Check for experimental updates to this workflow', 'The workflow automatically checks for updates; enable this to include pre-releases', arg=':pref prerelease_channel', valid=True, icon=icons.TASK_COMPLETED if prefs.prerelease_channel else icons.TASK ) workflow().add_item( 'Force sync', 'The workflow syncs automatically, but feel free to be forcible.', arg='-pref sync', valid=True, icon=icons.SYNC ) workflow().add_item( 'Switch theme', 'Toggle between light and dark icons', arg='-pref retheme', valid=True, icon=icons.PAINTBRUSH ) workflow().add_item( 'Main menu', autocomplete='', icon=icons.BACK )