Skip to content
Open
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
110 changes: 84 additions & 26 deletions SMTplugins/Calendar/calendarWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,28 @@
# Falls back to a static calendar view if no credentials are provided

from widget import Widget
from datetime import datetime, date
from datetime import datetime, date, timedelta
import calendar
import json
import os
import time

class calendarWidget(Widget):

def __init__(self):
self._preferences = self.widgetDefaultPreferences
self._events = {} # date_str -> list of event names
self.file = "calendar_events.json"

if os.path.exists(self.file):
with open(self.file, "r") as f:
self._events = json.load(f)
else:
self._events = {}

self.current_date = date.today()
self.state_file = "calendar_state.json"

# -------- METADATA --------
@property
def widgetName(self):
return "Calendar Widget"
Expand All @@ -23,17 +35,16 @@ def widgetID(self):

@property
def widgetHTML(self):
"""Returns the HTML template name; Flask renders it via Jinja."""
return "calendar_widget.html"

# -------- MAIN DATA --------
@property
def widgetData(self):
"""Returns current calendar data as a JSON-serialisable dict."""
today = date.today()
year = today.year
month = today.month
year = self.current_date.year
month = self.current_date.month

cal = calendar.Calendar(firstweekday=6) # week starts Sunday
cal = calendar.Calendar(firstweekday=6)
weeks = cal.monthdatescalendar(year, month)

weeks_data = []
Expand All @@ -50,19 +61,17 @@ def widgetData(self):
weeks_data.append(days)

return {
"month_name": today.strftime("%B"),
"month_name": self.current_date.strftime("%B"),
"year": year,
"weeks": weeks_data,
"day_headers": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
}

# -------- PREFERENCES --------
@property
def widgetPreferences(self):
return self._preferences

@widgetPreferences.setter
def widgetPreferences(self, value):
self._preferences = value
return {}


@property
def widgetDefaultPreferences(self):
Expand All @@ -77,16 +86,28 @@ def updateTimer(self):
# Refresh every 10 minutes
return 600_000

# -------- SAVE HELPERS --------
def _save_state(self):
with open(self.state_file, "w") as f:
json.dump({
"current_date": self.current_date.isoformat()
}, f)

def _save_events(self):
with open(self.events_file, "w") as f:
json.dump(self._events, f)

# -------- OPTIONAL DEFAULT DATA --------
def update(self):
"""Called by the widget subsystem on a timer. Fetches events if enabled."""
if self._preferences.get("use_google_cal"):
self._fetch_google_events()
else:
# Placeholder: inject a couple of demo events so the UI isn't empty
today = date.today().isoformat()
self._events = {
today: ["Class 4PM – LC 22", "Gym 5PM"]
}
# Only add demo data if nothing exists yet
if not self._events:
today = date.today().isoformat()
self._events[today] = ["Class 4PM – LC 22", "Gym 5PM"]

print(f"Calendar Widget updated – {date.today().strftime('%B %Y')}")

def _fetch_google_events(self):
Expand All @@ -105,19 +126,56 @@ def _fetch_google_events(self):
print(f"[calendarWidget] Google Calendar fetch failed: {e}")

def handle_event(self, event, args):
"""
Supported events:
- "prev_month" : (future) navigate to previous month
- "next_month" : (future) navigate to next month
- "add_event" : args = {"date": "YYYY-MM-DD", "title": "..."}
"""

# -------- ADD TASK --------
if event == "add_event":
date_str = args.get("date")
title = args.get("title", "Event")

if date_str:
if date_str not in self._events:
self._events[date_str] = []
self._events[date_str].append(title)
print(f"[calendarWidget] Added event '{title}' on {date_str}")

self._events[date_str].append({
"id": int(time.time()*1000),
"title": title
})

self._save_events()

# -------- NEXT MONTH --------
elif event == "next_month":
print("NEXT MONTH TRIGGERED")

if self.current_date.month == 12:
self.current_date = self.current_date.replace(
year=self.current_date.year + 1,
month=1
)
else:
self.current_date = self.current_date.replace(
month=self.current_date.month + 1
)

self._save_state()
print("NEW MONTH:", self.current_date)

# -------- PREVIOUS MONTH --------
elif event == "prev_month":
print("PREV MONTH TRIGGERED")

if self.current_date.month == 1:
self.current_date = self.current_date.replace(
year=self.current_date.year - 1,
month=12
)
else:
self.current_date = self.current_date.replace(
month=self.current_date.month - 1
)

self._save_state()
print("NEW MONTH:", self.current_date)

else:
print(f"[calendarWidget] Unhandled event: {event} args={args}")
1 change: 1 addition & 0 deletions SMTplugins/Calendar/calendar_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

@calendar_bp.route("/widget/calendar")
def calendar_view():
print("RENDERING MONTH:", _widget.current_date) # debug
return render_template("calendar_widget.html", data=_widget.widgetData)

@calendar_bp.route("/api/calendar/data")
Expand Down
1 change: 1 addition & 0 deletions SMTplugins/Calendar/credentials.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"installed":{"client_id":"772172144197-ldo19j0f7s5m7s55jd6ndkadoj4c4ehd.apps.googleusercontent.com","project_id":"smt-tasks","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"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","redirect_uris":["http://localhost"]}}
1 change: 1 addition & 0 deletions SMTplugins/Calendar/token_cal.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"token": "ya29.a0AQvPyINm3-Umt-poLbkfSpf3sLXjFOYawOQnHssKmcD6iWd6qI8Vxog2HqhWPjDc4-Gwib_qHJB0JgbnWlVCZeoMCrkxipNogHWpkAVsD4rjQxllKDdjlO7lcHQiFEODBc05EtXZHSdpdkqp3ah9cWzQeOHi2QksUPudqv8QNapkJpvElGqKDljOyvnuJMENZ8bTXnEaCgYKAaMSARQSFQHGX2Mi1bah18Yfs0QmPf9s0gUP6A0206", "refresh_token": "1//05NlvPY06LAVrCgYIARAAGAUSNwF-L9IrBh5LQKCmxDpM-lbVWh3B_Grots1N2s4FdVmAsdTZQ3AeBEwIUmtCI3uZRvfDXKTb4V4", "token_uri": "https://oauth2.googleapis.com/token", "client_id": "772172144197-ldo19j0f7s5m7s55jd6ndkadoj4c4ehd.apps.googleusercontent.com", "client_secret": "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", "scopes": ["https://www.googleapis.com/auth/calendar.readonly"], "universe_domain": "googleapis.com", "account": "", "expiry": "2026-04-30T16:24:43Z"}
1 change: 1 addition & 0 deletions calendar_events.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"2026-05-24": [{"id": "8ifd00fvn8hqjf73o7o24he5os", "title": "Photography Session (Easha Mashud)", "google_event": true}]}
1 change: 1 addition & 0 deletions calendar_state.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"current_date": "2026-04-30"}
2 changes: 1 addition & 1 deletion flaskServer.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

#allows for easier starting of flask from start file
def run_flask():
app.run(debug=True, port=5000, use_reloader=False)
app.run(debug=True, port=8000, use_reloader=False)



Expand Down
8 changes: 4 additions & 4 deletions layout_client.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@
"col": 3
},
{
"id": "bj-container",
"name": "Blackjack",
"class": "blackjack-widget",
"css_name": "blackjack_widget.css",
"id": "calendar",
"name": "Calendar",
"class": "calendar-widget",
"css_name": "calendar_widget.css",
"row": 2,
"col": 2
},
Expand Down
Loading