Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Empty file added backend/__init__.py
Empty file.
Empty file added backend/scripts/__init__.py
Empty file.
Empty file.
106 changes: 106 additions & 0 deletions backend/scripts/productivity/dashboard.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"""
PyEveryday Daily Dashboard

This script provides a centralized dashboard for productivity tools:
- Todos
- Reminders
- Pomodoro Timer
- Time Tracking
- Weather
- Motivational Quote
- Configurable section toggles
"""

import os
import json
try:
from quote_fetcher import QuoteFetcher
except ImportError:
try:
from productivity.quote_fetcher import QuoteFetcher
except ImportError:
try:
from backend.scripts.productivity.quote_fetcher import QuoteFetcher
except ImportError:
QuoteFetcher = None
from datetime import datetime
import requests

CONFIG_PATH = os.path.join(os.path.dirname(__file__), 'dashboard_config.json')
DEFAULT_CONFIG = {
"show_todos": True,
"show_reminders": True,
"show_pomodoro": True,
"show_time_tracking": True,
"show_quote": True,
# Weather removed
}

def load_config():
if os.path.exists(CONFIG_PATH):
try:
with open(CONFIG_PATH, 'r') as f:
return json.load(f)
except Exception:
pass
return DEFAULT_CONFIG.copy()

config = load_config()

def section_header(title):
return f"\n--- {title} ---"



# --- Motivational Quote ---
def get_motivational_quote():
if QuoteFetcher is None:
return "Quote: (not available)"
try:
fetcher = QuoteFetcher()
return fetcher.get_local_quote()
except Exception as e:
return f"Quote: ERROR: {type(e).__name__}: {e}"

# --- Dynamic Section Loader ---
def try_import_and_run(module_name, func_name, section_title):
try:
import importlib
mod = importlib.import_module(module_name)
func = getattr(mod, func_name)
result = func()
if result:
return section_header(section_title) + f"\n{result}"
except Exception as e:
return section_header(section_title) + f"\nERROR: {type(e).__name__}: {e}"
return ""

def main():
print("\n=== PyEveryday Daily Dashboard ===\n")
print(f"Date: {datetime.now().strftime('%Y-%m-%d %H:%M')}")

# Todos
if config.get("show_todos", True):
print(try_import_and_run('todo_manager', 'dashboard_summary', 'Todos'))

# Reminders
if config.get("show_reminders", True):
print(try_import_and_run('reminder_system', 'dashboard_summary', 'Reminders'))

# Pomodoro
if config.get("show_pomodoro", True):
print(try_import_and_run('pomodoro_timer', 'dashboard_summary', 'Pomodoro Timer'))

# Time Tracking
if config.get("show_time_tracking", True):
print(try_import_and_run('time_tracker', 'dashboard_summary', 'Time Tracking'))



# Motivational Quote
if config.get("show_quote", True):
print(section_header('Motivational Quote'))
print(get_motivational_quote())

if __name__ == "__main__":
main()
50 changes: 40 additions & 10 deletions backend/scripts/productivity/pomodoro_timer.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
def dashboard_summary():
# Show completed sessions today
try:
stats_file = "pomodoro_stats.json"
import json, datetime
today = datetime.date.today().isoformat()
if not os.path.exists(stats_file):
return "No pomodoro sessions yet."
with open(stats_file, 'r') as f:
data = json.load(f)
today_sessions = [s for s in data if s.get('date') == today]
return f"Sessions today: {len(today_sessions)}"
except Exception:
return "No pomodoro stats available."

import time
import datetime
import sys
import threading
import os
import argparse

class PomodoroTimer:
def __init__(self, work_duration=25, break_duration=5, long_break_duration=15):
Expand Down Expand Up @@ -146,28 +162,42 @@ def interactive_mode():
else:
print("Unknown command")


if __name__ == "__main__":
if len(sys.argv) > 1:
command = sys.argv[1].lower()
timer = PomodoroTimer()

if command == "work":
parser = argparse.ArgumentParser(description="Pomodoro Timer")
parser.add_argument('--work', type=int, help='Work session duration in minutes')
parser.add_argument('--break', dest='break_', type=int, help='Short break duration in minutes')
parser.add_argument('--long-break', type=int, help='Long break duration in minutes')
parser.add_argument('--session', choices=['work', 'break'], help='Start a work or break session immediately')
parser.add_argument('--stats', action='store_true', help='Show Pomodoro statistics')
parser.add_argument('--reset', action='store_true', help='Reset session count')
parser.add_argument('--interactive', action='store_true', help='Start in interactive mode')
args = parser.parse_args()

# If any CLI flag is used, run in CLI mode
if any([args.work, args.break_, args.long_break, args.session, args.stats, args.reset]) and not args.interactive:
timer = PomodoroTimer(
work_duration=args.work if args.work else 25,
break_duration=args.break_ if args.break_ else 5,
long_break_duration=args.long_break if args.long_break else 15
)
if args.session == 'work':
thread = timer.start_work_session()
if thread:
try:
thread.join()
except KeyboardInterrupt:
timer.stop()

elif command == "break":
elif args.session == 'break':
thread = timer.start_break()
if thread:
try:
thread.join()
except KeyboardInterrupt:
timer.stop()

else:
print("Usage: python pomodoro_timer.py [work|break]")
if args.stats:
timer.get_stats()
if args.reset:
timer.reset_sessions()
else:
interactive_mode()
69 changes: 33 additions & 36 deletions backend/scripts/productivity/reminder_system.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
def dashboard_summary():
mgr = ReminderManager()
active = [r for r in mgr.reminders if r.active]
if not active:
return "No active reminders."
msg = f"Active reminders: {len(active)}"
next_rem = min(active, key=lambda r: r.reminder_time, default=None)
if next_rem:
msg += f"\nNext: {next_rem.message} at {next_rem.reminder_time.strftime('%Y-%m-%d %H:%M')}"
return msg
import datetime
import time
import json
Expand Down Expand Up @@ -167,51 +177,38 @@ def create_quick_reminders():

print("Quick reminders created!")


if __name__ == "__main__":
import argparse
import sys

parser = argparse.ArgumentParser(description="Reminder System")
parser.add_argument('--add', nargs=2, metavar=('MESSAGE', 'TIME'), help='Add a new reminder. TIME format: HH:MM or YYYY-MM-DDTHH:MM')
parser.add_argument('--repeat', help='Repeat interval for the reminder (e.g., 30m, 1h)')
parser.add_argument('--list', action='store_true', help='List all reminders')
parser.add_argument('--remove', metavar='REMINDER_ID', help='Remove a reminder by ID')
parser.add_argument('--monitor', action='store_true', help='Start monitoring reminders')
parser.add_argument('--quick', action='store_true', help='Create quick reminders')
parser.add_argument('--interactive', action='store_true', help='Start in interactive mode')
args = parser.parse_args()

manager = ReminderManager()

if len(sys.argv) < 2:
print("Usage: python reminder_system.py <command> [args]")
print("Commands: add, list, remove, monitor, quick")
sys.exit(1)

command = sys.argv[1]

if command == "add":
if len(sys.argv) < 4:
print("Usage: add <message> <time> [repeat_interval]")
print("Time format: HH:MM or YYYY-MM-DDTHH:MM")
sys.exit(1)

message = sys.argv[2]
time_str = sys.argv[3]
repeat_interval = sys.argv[4] if len(sys.argv) > 4 else None


if args.add:
message, time_str = args.add
repeat_interval = args.repeat
reminder_time = manager.parse_time_string(time_str)
if reminder_time:
repeat = repeat_interval is not None
manager.add_reminder(message, reminder_time, repeat, repeat_interval)
else:
print("Invalid time format")

elif command == "list":
elif args.list:
manager.list_reminders()

elif command == "remove":
if len(sys.argv) < 3:
print("Usage: remove <reminder_id>")
sys.exit(1)

reminder_id = sys.argv[2]
manager.remove_reminder(reminder_id)

elif command == "monitor":
elif args.remove:
manager.remove_reminder(args.remove)
elif args.monitor:
manager.start_monitoring()

elif command == "quick":
elif args.quick:
create_quick_reminders()

else:
print("Unknown command")
elif args.interactive or len(sys.argv) == 1:
print("Usage: python reminder_system.py --add MESSAGE TIME [--repeat INTERVAL] | --list | --remove REMINDER_ID | --monitor | --quick | --interactive")
70 changes: 38 additions & 32 deletions backend/scripts/productivity/time_tracker.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
def dashboard_summary():
tracker = TimeTracker()
today = datetime.date.today().isoformat()
today_acts = [a for a in tracker.activities if a.date == today]
total_sec = sum(a.duration for a in today_acts)
if not today_acts:
return "No time tracked today."
last = max(today_acts, key=lambda a: a.end_time or 0)
h = int(total_sec // 3600)
m = int((total_sec % 3600) // 60)
msg = f"Total today: {h:02d}:{m:02d}"
msg += f"\nLast: {last.name} ({last.category})"
return msg
import time
import json
import datetime
Expand Down Expand Up @@ -207,43 +220,36 @@ def list_categories(self):
else:
print("No categories found")


if __name__ == "__main__":
import argparse
import sys

parser = argparse.ArgumentParser(description="Time Tracker")
parser.add_argument('--start', nargs='+', metavar=('ACTIVITY', 'CATEGORY'), help='Start a new activity. Usage: --start <activity> [category]')
parser.add_argument('--stop', action='store_true', help='Stop the current activity')
parser.add_argument('--summary', nargs='?', const='', metavar='DATE', help='Show daily summary for DATE (YYYY-MM-DD), or today if not provided')
parser.add_argument('--weekly', action='store_true', help='Show weekly summary')
parser.add_argument('--report', type=int, metavar='DAYS', help='Generate report for the last DAYS (default 7)')
parser.add_argument('--categories', action='store_true', help='List all categories')
parser.add_argument('--interactive', action='store_true', help='Start in interactive mode')
args = parser.parse_args()

tracker = TimeTracker()

if len(sys.argv) < 2:
print("Usage: python time_tracker.py <command> [args]")
print("Commands: start, stop, summary, weekly, report, categories")
sys.exit(1)

command = sys.argv[1]

if command == "start":
if len(sys.argv) < 3:
print("Usage: start <activity_name> [category]")
sys.exit(1)

name = sys.argv[2]
category = sys.argv[3] if len(sys.argv) > 3 else "General"

if args.start:
name = args.start[0]
category = args.start[1] if len(args.start) > 1 else "General"
tracker.start_activity(name, category)

elif command == "stop":
elif args.stop:
tracker.stop_current_activity()

elif command == "summary":
date = sys.argv[2] if len(sys.argv) > 2 else None
elif args.summary is not None:
date = args.summary if args.summary else None
tracker.get_daily_summary(date)

elif command == "weekly":
elif args.weekly:
tracker.get_weekly_summary()

elif command == "report":
days = int(sys.argv[2]) if len(sys.argv) > 2 else 7
tracker.generate_report(days)

elif command == "categories":
elif args.report is not None:
tracker.generate_report(args.report)
elif args.categories:
tracker.list_categories()

else:
print("Unknown command")
elif args.interactive or len(sys.argv) == 1:
print("Usage: python time_tracker.py --start ACTIVITY [CATEGORY] | --stop | --summary [DATE] | --weekly | --report DAYS | --categories | --interactive")
Loading