Widget Examples

2 posts were split to a new topic: Sonos Now Playing & Controls

Is there any way to specify a widget refresh frequency or rate?

1 Like

Is there a way to use Location from a widget?
When running from the app, I can get the location, but from a widget, I see this error:

I noticed that apps like Maps and Weather now have new permission under privacy: While using the App or Widgets. Maybe Scriptable is missing this permission?

Update: Using non-beta versions of iOS 14.0 and Scriptable 1.5 (161)

Update 2: Here is a minimal script to demonstrate the issue:

let widget = await createWidget()
if (!config.runsInWidget) {
  await widget.presentSmall()
}
Script.setWidget(widget)
Script.complete()

async function createWidget(items) {
  let w = new ListWidget()
  const latLong = await Location.current()
  const loc = `${latLong.latitude}/${latLong.longitude}`
  w.addText(loc)
  return w
}

will there be a way to define multiple tap targets for the medium and large widgets?
maybe something like WidgetText.url property (for consistency with the ListWidget.url property)?

Unfortunately not. iOS decides the update cycle. It seems to update less frequently if your iPhone is in energy saving mode.

3 posts were split to a new topic: Random Trello Card

Widgets update based on a number of things, usually every 5-10 minutes
However it changes based on the battery and that sort of thing.

1 Like

Hi, I was wondering if someone could help me. I have made a widget and I want to add a red border around it. I typed in

w.borderColor = Color.red()
w.borderWidth = 10

And nothing happened. Can anyone help?

Showing the next game of your favorite soccer team (when, opponent, competition) using the football-data.org API (using Ajax as an example):

1 Like

I love widgets !

I’ve created three widgets

One that shows the amount of traffic, accidents,…
Another one that shows people who are missing


The last one is K POP news

1 Like

I was thinking it would be a fun project to create a widget that rotated through a Photo folder. Does scriptable allow for getting images from a folder in Photos?

HI,

I am trying to create a widget that displays my reminders for today (and tomorrow if there is space left) I have based it on a previous post from here. Everything is working fine except: I want the widget to change appearance the i am in dark mode. It works when running the script inside the app, but it dose not work outside of scriptable, when it is used as a widget.

The code I am using to switch between dark and light looks something like this:

if ( Device.isUsingDarkAppearance() ) {
  // dark mode appearance settings
  } else {
  // normal settings
  };

I have also included the full code which looks like this:

var MAX_TASKS_SHOWN = 8;
const NOW = new Date();


const TITLE_FONT = Font.boldSystemFont(11);
const BODY_FONT = Font.semiboldRoundedSystemFont(12);



if ( Device.isUsingDarkAppearance() ) {
  var BG_COLOR = new Color("#1C1C1E");
  var TITLE_COLOR = new Color("#9E9E9E");
  var OVERDUE_COLOR = new Color("#FE4639");
  var TASK_COLOR = new Color("#FFFFFF");
  var NO_OVERDUE_COLOR = new Color("#2FD15D");
  } else {
  var BG_COLOR = Color.white();
  var TITLE_COLOR = new Color("#8C8C8C");
  var OVERDUE_COLOR = new Color("#FD3F32");
  var TASK_COLOR = new Color("#000000");
  var NO_OVERDUE_COLOR = new Color("#13C759");
  };



const today = new Date()
const tomorrow = new Date(today)
  tomorrow.setDate(tomorrow.getDate() + 1)
  tomorrow.setHours(0,0,0,0)
const tomorrow2 = new Date(today)
  tomorrow2.setDate(tomorrow2.getDate() + 2)
  tomorrow2.setHours(0,0,0,0)

//
// Utils
//

const compareReminderDuedates = (reminderA, reminderB) =>
  reminderA.dueDate - reminderB.dueDate;
const sortRemindersByDuedateAsc = reminders =>
  reminders.sort(compareReminderDuedates);

/** Round date down to 00:00 */
const stripTime = date => new Date(new Date(date).setHours(0, 0, 0, 0));

/** d1 - d2: will be negative if d2 > d1 */
const daysBetween = (d1, d2) => {
  const differenceMs = stripTime(d1).getTime() - stripTime(d2).getTime();
  return Math.floor(differenceMs / 86400000);
};

const getOverdueTasks = async () => {
  const all = await Reminder.allIncomplete();
  return sortRemindersByDuedateAsc(
    all.filter(task => task.dueDate && task.dueDate < today)
  );
};

const getTodayTasks = async () => {
  const all = await Reminder.allIncomplete();
  return sortRemindersByDuedateAsc(
    all.filter(task => today <= task.dueDate && task.dueDate < tomorrow)
  );
};

const getTomorrowTasks = async () => {
  const all = await Reminder.allIncomplete();
  return sortRemindersByDuedateAsc(
    all.filter(task => tomorrow <= task.dueDate && task.dueDate < tomorrow2)
  );
};

// overdue tasks

const getWidget = async () => {
  const overdueTasks = await getOverdueTasks();
  const todayTasks = await getTodayTasks();
  const tomorrowTasks = await getTomorrowTasks();
  
  const widget = new ListWidget();
  widget.backgroundColor = BG_COLOR;
  
  
  widget.addSpacer(0);
  
  const dueNum = overdueTasks.length + todayTasks.length
  if (dueNum) {
    var title = widget.addText(`HEUTE   ${dueNum}`);
  }else{
    var title = widget.addText(`HEUTE`);
  }
  title.textColor = TITLE_COLOR;
  title.font = TITLE_FONT;
  



  if (overdueTasks.length) {
    overdueTasks.slice(0, MAX_TASKS_SHOWN).forEach(({ title, dueDate }) => {
      const task = widget.addText(`| ${title}`);
      task.textColor = OVERDUE_COLOR;
      task.font = BODY_FONT;
      task.lineLimit = 1;
    });
  } else {
    
  }
  
  MAX_TASKS_SHOWN = MAX_TASKS_SHOWN - overdueTasks.length 
  
  if (MAX_TASKS_SHOWN > 0) {
    if (todayTasks.length) {
      todayTasks.slice(0, MAX_TASKS_SHOWN).forEach(({ title, dueDate }) => {
        const task = widget.addText(`| ${title}`);
        task.textColor = TASK_COLOR;
        task.font = BODY_FONT;
        task.lineLimit = 1;
      });
    } else {}
  } else {}
  
  if (dueNum) {
    
  } else {
    const noTasks = widget.addText("Alles erledigt.");
    noTasks.textColor = NO_OVERDUE_COLOR;
    noTasks.font = BODY_FONT;
  }

// tomorrow

//  const tomorrowTasks = Reminder.allDueTomorrow();
  
  widget.addSpacer(5);

  MAX_TASKS_SHOWN = MAX_TASKS_SHOWN - todayTasks.length - 2
  
  if (MAX_TASKS_SHOWN > 0){
    if (tomorrowTasks.length) {
      const title = widget.addText(`MORGEN   ${tomorrowTasks.length}`);
      title.textColor = TITLE_COLOR;
      title.font = TITLE_FONT;
      tomorrowTasks.slice(0, MAX_TASKS_SHOWN).forEach(({ title, dueDate }) => {
        const task = widget.addText(`| ${title}`);
        task.textColor = TASK_COLOR;
        task.font = BODY_FONT;
        task.lineLimit = 1;
      });
    } else {}
  } else {}
  
  widget.addSpacer();

  return widget;
};

(async () => {
  const widget = await getWidget();
  if (config.runsInWidget) {
    Script.setWidget(widget);
    Script.complete();
  } else await widget.presentSmall();
})();

IMG_6880

Watching - this is a great idea - hope it’s implementable!

I’ve been a bit obsessed with this on the Mac

Would you mind sharing your script?

A combination script and couple of shortcuts to check on CitiBike docks in particular locations (where I am, where I am going). This is the bike share system in New York City. Would probably work for other systems that use the GBFS standard. Will probably add some more interesting functionality for on-tap.

21 posts were split to a new topic: Custom Calendar Widget

I would like to see an example of the tapping functionality. Also I have a question, is the (+ Note) button tappable?

I had the same issue with my xkcd widget. I made a separate function to solve it. it’s an async function though but not too much of an issue.

async function isUsingDarkAppearance() {
  const wv = new WebView()
  let js ="(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches)"
  let r = await wv.evaluateJavaScript(js)
  return r
}
1 Like

A widget showing a random painting from the Metropolitan Museum of Art.
If you click on it you see the details in your browser.

Code here

//Department ID = 11 is paintings ; use other if you wish

const url = 'https://collectionapi.metmuseum.org/public/collection/v1/search?hasImages=true&departmentId=11&q=Painting'
const req = new Request(url)
const res = await req.loadJSON()
const max = res.total-1
console.log("Max: "+max);
const min = 0
const random = Math.floor(Math.random() * (max - min + 1)) + min
console.log("Random: "+random);
const picked = res.objectIDs[random]
console.log("Picked: "+picked);
const req2 = new Request('https://collectionapi.metmuseum.org/public/collection/v1/objects/'+picked)
const res2 = await req2.loadJSON()
const i = new Request(res2.primaryImageSmall);
const img = await i.loadImage();

let widget = createWidget(img, res2.objectURL)
if (config.runsInWidget) {
  // create and show widget
  Script.setWidget(widget)
  Script.complete()
}
else {
  widget.presentMedium()
}


function createWidget(img, widgeturl) {
  let w = new ListWidget()
  w.backgroundColor = new Color("#1A1A1A")
  w.backgroundImage = img
  w.url = widgeturl
  return w
}
3 Likes

Can you please share your script?