Skip to content

Instantly share code, notes, and snippets.

@aashrith825
Created October 11, 2020 17:31
Show Gist options
  • Save aashrith825/867d6eaf091e22355a6316a543a51102 to your computer and use it in GitHub Desktop.
Save aashrith825/867d6eaf091e22355a6316a543a51102 to your computer and use it in GitHub Desktop.
Scriptable widget with custom font, greetings, calendar events, football api, Fitbit api and Unsplash images
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: deep-purple; icon-glyph: image;
// download harrypotter font from fontspace.com/phoenix-phonts and install it using fontcase app
/*
* Change the widget values and test out the widget in this section.
* ===================================================================
*/
const IMAGE_SOURCE = "Unsplash"
const TERMS = "Harry-Potter-Dark"
// Change to true to update widget background image
const FORCE_IMAGE_UPDATE = false
// Change to true to see a preview of your widget.
const testMode = true
// Optionally specify the size of your widget preview.
const widgetSize = "large"
// Change to false to show the date only.
const showEvents = true
// Specify how many events to show.
const numberOfEvents = 2
// Can be top, middle, or bottom.
const verticalAlignment = "top"
// Can be left, center, or right.
const horizontalAlignment = "left"
// Use iosfonts.com, or change to "" for the system font.
const GreetingFont = "Harryp"
const fontName = "futura-Medium"
// Find colors on htmlcolorcodes.com
const fontColor = new Color("#ffffff")
const greetingColor = new Color ("#daa520")
const stepsColor = new Color ("#e1af33")
// Change the font sizes for elements.
const GreetingFontSize = 42
const DateSize = 24
const footballFontSize = 20
const stepsFontSize = 20
const eventTitleSize = 18
const eventTimeSize = 12
// football variables
const footballAuthToken = <insert your api auth token from football-data.org>;
const myTeamName = 'FC Barcelona';
const myTeamId = 81;
// fitbit steps variables
const stepsGoal = 10000
const userId = <insert fitbit userid here>;
const fitbitAuthToken = <insert your api oauth2 token generated from fitbit api here>;
// greeting wiget initializations
let widgetHello = new ListWidget();
var today = new Date();
let df = new DateFormatter()
df.dateFormat = "yyyy-MM-dd"
// fitbit date variable
let activityDate = df.string(today)
// Long-form days and months
var days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
var months = ['January','February','March','April','May','June','July','August','September','October','November','December'];
// Greetings arrays per time period.
var greetingsMorning = [
'Good Morning Muggle.'
];
var greetingsAfternoon = [
'Good Afternoon.'
];
var greetingsEvening = [
'Good Evening Muggle.'
];
var greetingsNight = [
'Bedtime.'
];
var greetingsLateNight = [
'Go to sleep Muggle!'
];
// Holiday customization
var holidaysByKey = {
// month,week,day: datetext
"11,4,4": "Happy Thanksgiving!"
}
var holidaysByDate = {
// month,date: greeting
"1,1": "Happy " + (today.getFullYear()).toString() + "!",
"10,31": "Happy Halloween!",
"12,12": "Happy Birthday!",
"12,25": "Merry Christmas!"
}
var holidayKey = (today.getMonth() + 1).toString() + "," + (Math.ceil(today.getDate() / 7)).toString() + "," + (today.getDay()).toString();
var holidayKeyDate = (today.getMonth() + 1).toString() + "," + (today.getDate()).toString();
// Date Calculations
var g_weekday = days[ today.getDay() ];
var g_month = months[ today.getMonth() ];
var g_date = today.getDate();
var g_hour = today.getHours();
// Append ordinal suffix to date
function ordinalSuffix(input) {
if (input % 10 == 1 && g_date != 11) {
return input.toString() + "st";
} else if (input % 10 == 2 && g_date != 12) {
return input.toString() + "nd";
} else if (input % 10 == 3 && g_date != 13) {
return input.toString() + "rd";
} else {
return input.toString() + "th";
}
}
// Generate date string
var datefull = g_weekday + ", " + g_month + " " + ordinalSuffix(g_date);
function randomGreeting(greetingArray) {
return Math.floor(Math.random() * greetingArray.length);
}
var greeting = new String("Howdy.")
if (g_hour < 5 && g_hour >= 1) { // 1am - 5am
greeting = greetingsLateNight[randomGreeting(greetingsLateNight)];
} else if (g_hour >= 23 || g_hour < 1) { // 11pm - 1am
greeting = greetingsNight[randomGreeting(greetingsNight)];
} else if (g_hour < 12) { // Before noon (5am - 12pm)
greeting = greetingsMorning[randomGreeting(greetingsMorning)];
} else if (g_hour >= 12 && g_hour < 16) { // 12pm - 5pm
greeting = greetingsAfternoon[randomGreeting(greetingsAfternoon)];
} else if (g_hour >= 16 && g_hour < 23) { // 5pm - 11pm
greeting = greetingsEvening[randomGreeting(greetingsEvening)];
}
// Overwrite greeting if calculated holiday
if (holidaysByKey[holidayKey]) {
greeting = holidaysByKey[holidayKey];
}
// Overwrite all greetings if specific holiday
if (holidaysByDate[holidayKeyDate]) {
greeting = holidaysByDate[holidayKeyDate];
}
// creates fitbit data
let activities = await loadActivities(userId,fitbitAuthToken)
async function createSteps(activities) {
let summary = activities
var monLoc = [
'Gryffindor House.'
];
var tueLoc = [
'Quidditch Grounds.'
];
var wedLoc = [
'Hagrids hut.'
];
var thuLoc = [
'Room of Requirement.'
];
var friLoc = [
'Hogsmeade!',
'Three Broomsticks!',
'honey dukes!'
];
var weekendLoc = [
'Forbidden Forest!'
];
function randomLoc(LocArray) {
return Math.floor(Math.random() * LocArray.length);
}
var locGoal = new String("Howdy.")
if (g_weekday == 'Monday') {
locGoal = monLoc[randomLoc(monLoc)];
} else if (g_weekday == 'Tuesday') {
locGoal = tueLoc[randomLoc(tueLoc)];
} else if (g_weekday == 'Wednesday') {
locGoal = wedLoc[randomLoc(wedLoc)];
} else if (g_weekday == 'Thursday') {
locGoal = thuLoc[randomLoc(thuLoc)];
} else if (g_weekday == 'Friday') {
locGoal = friLoc[randomLoc(friLoc)];
} else if (g_weekday == 'Saturday'||g_weekday == 'Sunday') {
locGoal = weekendLoc[randomLoc(weekendLoc)];
}
let steps1 = summary["steps"]
let stepsLeft = stepsGoal-steps1
let stepsText = "..."+stepsLeft+" paces to "+locGoal
return stepsText
}
// function creates match data
let matches = await loadMatches(myTeamId,footballAuthToken)
if (matches.length > 0) {
async function createWidget(matches) {
let match = matches[0]
let rawDate = match["utcDate"]
let date = new Date(Date.parse(rawDate))
let justDate = date.getDate();
let dateFormatter = new DateFormatter()
dateFormatter.dateFormat = "h:mm a"
let strTime = dateFormatter.string(date)
function ordinalSuffix(input) {
if (input % 10 == 1 && justDate != 11) {
return input.toString() + "st";
} else if (input % 10 == 2 && justDate != 12) {
return input.toString() + "nd";
} else if (input % 10 == 3 && justDate != 13) {
return input.toString() + "rd";
} else {
return input.toString() + "th";
}
}
let homeTeam = match.homeTeam.name
let awayTeam = match.awayTeam.name
let OtherTeam = new String("Howdy.")
if(homeTeam = myTeamName){
OtherTeam = awayTeam;
}
else {
OtherTeam = homeTeam;
}
let nextmatchtext = "Plays "+OtherTeam+ " on " + ordinalSuffix(justDate) + " at " +strTime
return nextmatchtext
}
}
// Store current datetime
const date = new Date()
// If we're in the widget or testing, build the widget.
if (config.runsInWidget || testMode){
let widget = new ListWidget()
let files = FileManager.local()
const path = files.documentsDirectory() + "/calendar_widget.jpg"
const modificationDate = files.modificationDate(path)
// Download image if it doesn't exist, wasn't created today, or update is forced
if (!modificationDate || !sameDay(modificationDate,date) || FORCE_IMAGE_UPDATE) {
try {
let img = await provideImage(IMAGE_SOURCE,TERMS)
files.writeImage(path,img)
widget.backgroundImage = img
} catch {
widget.backgroundImage = files.readImage(path)
}
} else
{
widget.backgroundImage = files.readImage(path)
}
let gradient = new LinearGradient()
gradient.colors = [new Color("#000000",0.5), new Color("#000000",0.4)]
gradient.locations = [0,0.9]
widget.backgroundGradient = gradient
// Add text to widget
if (verticalAlignment == "middle" || verticalAlignment == "bottom") { widget.addSpacer() }
// Store all of the events in widgettext.
let widgetText = []
widget.addSpacer(4)
// push greetings to widget
let hello = widget.addText(greeting);
hello.font = provideFont(GreetingFont,GreetingFontSize)
hello.textColor = greetingColor;
widget.addSpacer(2)
// push Date to widget
let datetext = widget.addText(datefull);
datetext.font = provideFont(GreetingFont,DateSize);
datetext.textColor = fontColor;
widget.addSpacer(10)
// push Match info to widget
if(matches.length > 0) {
let gametime = await createWidget(matches);
let imgURL = "https://i.ibb.co/BGtkZWZ/fc-barcelona-png-logo-5903.png"
let imgReq = new Request(imgURL)
let img = await imgReq.loadImage()
let stack1 = widget.addStack()
stack1.centerAlignContent()
stack1.setPadding(0, -8, 0, 0)
let logo = stack1.addImage(img)
logo.imageSize = new Size(40,40)
stack1.url = "https://onefootball.com/en/team/barcelona-5/fixtures"
let matchstyle = stack1.addText(gametime)
matchstyle.font = provideFont(GreetingFont,footballFontSize);
matchstyle.textColor = fontColor;
matchstyle.centerAlignText()
widget.addSpacer(12)
}
// create and push events data to widget
// Format the date info
let df = new DateFormatter()
df.dateFormat = "EEEE"
// Add events if we're supposed to.
if (showEvents) {
// Only show events that aren't all day or canceled.
const events = await CalendarEvent.today([])
let shownEvents = []
for (const event of events) {
if (shownEvents.length == numberOfEvents) { break }
if (event.startDate.getTime() > date.getTime() && !event.isAllDay && !event.title.startsWith("Canceled:")) {
shownEvents.push(event)
}
}
// Format the text for each event.
for (const shownEvent of shownEvents) {
widget.addSpacer(12)
let title = widget.addText(shownEvent.title)
title.font = provideFont(GreetingFont,eventTitleSize)
widgetText.push(title)
widget.addSpacer(7)
let time = widget.addText(formatTime(shownEvent.startDate))
time.font = provideFont(fontName,eventTimeSize)
widgetText.push(time)
}
}
// Format the text for all events text.
for (const textItem of widgetText) {
textItem.textColor = fontColor
textItem.url = "calshow://"
if (horizontalAlignment == "right") { textItem.rightAlignText() }
else if (horizontalAlignment == "center") { textItem.centerAlignText() }
else { textItem.leftAlignText() }
}
if (verticalAlignment == "top" || verticalAlignment == "middle") { widget.addSpacer() }
// Add fitbit text to widget
let stack2 = widget.addStack()
stack2.bottomAlignContent()
stack2.addSpacer()
let stepsWidget = await createSteps(activities);
let stepsLeft = stack2.addText(stepsWidget)
stepsLeft.url = "fitbit://"
stepsLeft.font = provideFont(GreetingFont,stepsFontSize);
stepsLeft.textColor = stepsColor;
stepsLeft.rightAlignText()
Script.setWidget(widget)
if (testMode) {
let widgetSizeFormat = widgetSize.toLowerCase()
if (widgetSizeFormat == "small") {widget.presentSmall()}
if (widgetSizeFormat == "medium") {widget.presentMedium()}
if (widgetSizeFormat == "large") {widget.presentLarge()}
}
Script.complete()
}
else {
Script.complete()
}
/*
* Helper functions
* ================
*/
// Retieve football data
async function loadMatches(TEAMID,TOKEN) {
let url = 'http://api.football-data.org/v2/teams/'+TEAMID+'/matches?status=SCHEDULED'
let req = new Request(url);
req.headers = { 'X-Auth-Token': TOKEN};
let json = await req.loadJSON();
return json.matches;
}
// Retieve fitbit data
async function loadActivities(USERID,TOKEN) {
let url = 'https://api.fitbit.com/1/user/'+USERID+'/activities/date/'+activityDate+'.json'
let req = new Request(url);
req.headers = { 'Authorization': TOKEN};
let json = await req.loadJSON();
return json.summary;
}
// Retrieve Unsplash or bing image
async function provideImage(source,terms) {
if (source == "Bing") {
const url = "http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=en-US"
const req = new Request(url)
const json = await req.loadJSON()
const imgURL = "http://bing.com" + json.images[0].url
const img = await downloadImage(imgURL)
const rect = new Rect(-78,0,356,200)
return cropImage(img, rect)
} else if (source == "Unsplash") {
const img = await downloadImage("https://source.unsplash.com/featured/500x500/?"+terms)
return img
}
}
// Helper function to download images
async function downloadImage(url) {
const req = new Request(url)
return await req.loadImage()
}
// Crop an image into a rect
function cropImage(img,rect) {
let draw = new DrawContext()
draw.respectScreenScale = true
draw.drawImageInRect(img,rect)
return draw.getImage()
}
function cropImage(img,rect) {
let draw = new DrawContext()
draw.size = new Size(rect.width, rect.height)
draw.drawImageAtPoint(img,new Point(-rect.x, -rect.y))
return draw.getImage()
}
// Provide the specified font.
function provideFont(fontName,fontSize) {
if (fontName == "" || fontName == null) {
return Font.regularSystemFont(fontSize)
} else {
return new Font(fontName,fontSize)
}
}
// Formats the times under each event
function formatTime(date) {
let df = new DateFormatter()
df.useNoDateStyle()
df.useShortTimeStyle()
return df.string(date)
}
// Determines if two dates occur on the same day
function sameDay(d1, d2) {
return d1.getFullYear() === d2.getFullYear() &&
d1.getMonth() === d2.getMonth() &&
d1.getDate() === d2.getDate()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment