Skip to content

Instantly share code, notes, and snippets.

@OscarPuentee
Last active October 11, 2022 23:02
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save OscarPuentee/44cd15156ab2c839c5b4353cb0672552 to your computer and use it in GitHub Desktop.
Save OscarPuentee/44cd15156ab2c839c5b4353cb0672552 to your computer and use it in GitHub Desktop.
Scriptable code for the Pokemon shiny hunting iOS widget
// This script was created by Oscar Puente.
// Important notes:
// 1. Available colors are black, blue, brown, cyan, green, orange, purple, red, white and yellow.
// 2. The language used is the device language. Current languages available are spanish, english and german (added by pabumake).
// If your language is not any of those, it defaults to english.
// 3. The Pokemon list delimits which pokemon can appear based on their pokedex number.
// Support for the 8th generation in the API is currently limited and it may cause errors due to missing info.
// It is strongly advised to keep the pokemon list between the first 7 generations (1-807).
// 4. The shiny-chance parameter should be a number from 1 to any other number.
// The higher the number, the harder to get a shiny pokemon. Set to 1 if you want to see only shiny pokemon.
// 5. Any image used as a background must be placed in the iCloud Scriptable folder.
// Contact for any comments or doubts: u/Technoir12
var lang = Device.language();
var widgetArgs;
if (config.runsInApp) {
let alert = new Alert();
alert.title = (lang == "es") ? "Selecciona una acción" : "Choose an action";
alert.addAction((lang == "es") ? "Personalizar widget" : "Customize widget");
alert.addAction((lang == "es") ? "Ver ejemplo" : "View example");
alert.addCancelAction((lang == "es") ? "Cancelar" : "Cancel");
let option = await alert.presentAlert();
if (option == 0){
let imageAlert = new Alert();
imageAlert.title = (lang == "es") ? "Imagen de fondo" : "Background image";
imageAlert.message = (lang == "es") ? "Si no se provee una imagen se utilizarán los fondos default (deben descargarse primero y colocarse en la carpeta de Scriptable)." : "If no image is provided, default backgrounds will be used (must be downloaded first and placed inside the Scriptable folder).";
imageAlert.addAction((lang == "es") ? "Seleccionar de la galería" : "Choose from gallery");
imageAlert.addAction((lang == "es") ? "Utilizar fondos default" : "Use default backgrounds");
imageAlert.addAction((lang == "es") ? "Descargar fondos default" : "Download default backgrounds");
imageAlert.addCancelAction((lang == "es") ? "Cancelar" : "Cancel");
let imageOption = await imageAlert.presentAlert();
switch (imageOption){
case 0:
let imageSelected = await Photos.fromLibrary();
let dp = await DocumentPicker.exportImage(imageSelected);
var pathElements = dp[0].split("/");
break;
case 1:
break;
case 2:
Safari.open("https://mega.nz/folder/tZJXxSDR#gHBnSzCfSdpOR0jdMfhQAA");
break;
default:
return;
}
let paramsAlert = new Alert();
paramsAlert.title = (lang == "es") ? "Escribe tus preferencias" : "Write down your preferences";
paramsAlert.message = (lang == "es") ? "El contenido entre paréntesis representa ejemplos de posibles valores para ese parámetro." : "The content between parenthesis represent possible values for that parameter.";
paramsAlert.addTextField(((lang == "es") ? "Margen superior" : "Top margin") + " (20)");
paramsAlert.addTextField(((lang == "es") ? "Color del texto" : "Text color") + " (white, black, etc.)");
paramsAlert.addTextField(((lang == "es") ? "Tamaño del texto" : "Text size") + " (small, medium, big)");
paramsAlert.addTextField(((lang == "es") ? "Listado de Pokemon" : "Pokemon list") + " (1-151)");
paramsAlert.addTextField(((lang == "es") ? "Probabilidad Shiny" : "Shiny chance") + " (496)");
paramsAlert.addTextField(((lang == "es") ? "Tamaño del widget" : "Widget size") + " (small, medium)");
paramsAlert.addAction((lang == "es") ? "Listo" : "Done");
paramsAlert.addCancelAction((lang == "es") ? "Cancelar" : "Cancel");
let params = await paramsAlert.presentAlert();
if (params == -1)
return;
for (i=0; i<6; i++) {
if (paramsAlert.textFieldValue(i) == "")
throw Error("All parameters are required.");
}
widgetArgs = paramsAlert.textFieldValue(0) + "|" +
paramsAlert.textFieldValue(1) + "|" +
paramsAlert.textFieldValue(2) + "|" +
paramsAlert.textFieldValue(3) + "|" +
paramsAlert.textFieldValue(4) + "|" +
paramsAlert.textFieldValue(5);
if (pathElements !== undefined){
widgetArgs = widgetArgs + "|" + pathElements[pathElements.length - 1];
}
let finalAlert = new Alert();
finalAlert.title = (lang == "es") ? "Estos son tus parámetros" : "These are your parameters";
finalAlert.message = (lang == "es") ? "Agrega un widget de Scriptable en tu pantalla de inicio. En las opciones, agrega el nombre de tu script y pega estos parámetros." : "Add a Scriptable widget to your homescreen. On settings, add the name of your script and paste these parameters.";
finalAlert.addTextField("", widgetArgs);
finalAlert.addAction((lang == "es") ? "Ver resultado" : "View result");
finalAlert.addCancelAction((lang == "es") ? "Salir" : "Exit");
let final = await finalAlert.presentAlert();
if (final == 1)
return;
}
else if (option == -1){
return;
}
}
if (config.runsInWidget)
widgetArgs = args.widgetParameter;
//Default parameters for testing
if (widgetArgs === undefined)
widgetArgs = "25|black|medium|1-650|496|medium";
var argsArray = widgetArgs.split("|");
var argsCount = argsArray.length;
if (argsCount < 6 || argsCount > 7)
throw new Error("Number of parameters must be beween 6 and 7. " + argsCount + " given.");
/* --------------- */
/* Text settings */
/* --------------- */
// Set text color
var textColor = argsArray[1];
switch (textColor) {
case "black":
textColor = Color.black();
break;
case "blue":
textColor = Color.blue();
break;
case "brown":
textColor = Color.brown();
break;
case "cyan":
textColor = Color.cyan();
break;
case "green":
textColor = Color.green();
break;
case "orange":
textColor = Color.orange();
break;
case "purple":
textColor = Color.purple();
break;
case "red":
textColor = Color.red();
break;
case "white":
textColor = Color.white();
break;
case "yellow":
textColor = Color.yellow();
break;
default:
throw new Error("Invalid color.");
}
//Set date
var today = new Date();
var days, months = [];
if (lang == "es") {
days = ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'Viernes', 'Sábado'];
months = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre'];
}
else if (lang == "de"){
days = ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'];
months = ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'July', 'August', 'September', 'Oktober', 'November', 'Dezember'];
}
else {
days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
}
var currentWeekday = days[today.getDay()];
var currentMonth = months[today.getMonth()];
var currentDay = today.getDate();
var hour = today.getHours();
var fullDate = currentMonth + " " + currentDay;
/* --------------- */
/* Pokemon code */
/* --------------- */
var pokemonLimits = argsArray[3].split("-");
var randomPoke = Math.floor(Math.random() * (parseInt(pokemonLimits[1]) - parseInt(pokemonLimits[0]))) + parseInt(pokemonLimits[0]);
var shinyChance = argsArray[4];
var shinyResult = Math.floor(Math.random() * shinyChance);
var isShiny = false;
if (shinyResult == 0)
isShiny = true;
const r = new Request("https://pokeapi.co/api/v2/pokemon/" + randomPoke);
var apiResult = await r.loadJSON();
var pokemon = [];
pokemon.name = apiResult.name.charAt(0).toUpperCase() + apiResult.name.slice(1);
pokemon.sprite = (apiResult.sprites.versions["generation-v"]["black-white"].front_default != null)
? apiResult.sprites.versions["generation-v"]["black-white"].front_default
: apiResult.sprites.versions["generation-vii"]["ultra-sun-ultra-moon"].front_default;
pokemon.type = apiResult.types[0].type.name;
if (isShiny)
pokemon.sprite = apiResult.sprites.front_shiny;
var sprRequest = new Request(pokemon.sprite);
pokemon.sprite = await sprRequest.loadImage();
/* ---------------- */
/* Background image */
/* ---------------- */
var scriptablePath = "/var/mobile/Library/Mobile Documents/iCloud~dk~simonbs~Scriptable/Documents/";
var imageName, imageFullPath;
var widgetSize = argsArray[5];
if (argsCount == 7)
imageName = argsArray[6];
else {
if (widgetSize == "small") {
if (hour >= 6 && hour < 18)
imageName = "poke_small_day.JPG";
else
imageName = "poke_small_night.JPG";
} else {
if (hour >= 6 && hour < 18) {
switch(pokemon.type) {
case "rock":
imageName = "rock_day.JPG";
break;
case "ground":
imageName = "rock_day.JPG";
break;
case "bug":
imageName = "bug_day.JPG";
break;
case "ice":
imageName = "ice_day.JPG";
break;
case "water":
imageName = "water_day.JPG";
break;
case "ghost":
imageName = "ghost_day.JPG";
break;
case "dark":
imageName = "ghost_day.JPG";
break;
case "steel":
imageName = "rock_day.JPG";
break;
default:
imageName = "poke_day.JPG";
break;
}
}
else {
switch(pokemon.type) {
case "rock":
imageName = "rock_night.JPG";
break;
case "ground":
imageName = "rock_night.JPG";
break;
case "bug":
imageName = "bug_night.JPG";
break;
case "ice":
imageName = "ice_night.JPG";
break;
case "water":
imageName = "water_night.JPG";
break;
case "ghost":
imageName = "ghost_night.JPG";
break;
case "dark":
imageName = "ghost_night.JPG";
break;
case "steel":
imageName = "rock_night.JPG";
break;
default:
imageName = "poke_night.JPG";
break;
}
}
}
}
imagePath = scriptablePath + imageName;
var fm = FileManager.iCloud();
if (fm.fileExists(imagePath)) {
//Download image from iCloud if it exists but it's not downloaded
if (!fm.isFileDownloaded(imagePath)) {
fm.downloadFileFromiCloud(imagePath);
}
} else {
throw new Error("Image not found. Remember that file name AND format are case-sensitive.");
}
/* --------------- */
/* Widget Creation */
/* --------------- */
var pokemonWidget = new ListWidget();
//Top margin
var spacing = parseInt(argsArray[0]);
pokemonWidget.addSpacer(spacing);
var fontSize = argsArray[2];
var fontSizeValues = [10,14];
if (fontSize == "medium")
fontSizeValues = [12, 16];
else if (fontSize == "big")
fontSizesValues = [14, 24];
// Add shiny icon to text
if (isShiny)
fullDate = fullDate + " \u2728";
// Weekday label
var weekdayLabel = pokemonWidget.addText(currentWeekday);
weekdayLabel.font = Font.systemFont(fontSizeValues[0]);
weekdayLabel.textColor = textColor;
// Date label
var dateLabel = pokemonWidget.addText(fullDate);
dateLabel.font = Font.boldSystemFont(fontSizeValues[1]);
dateLabel.textColor = textColor;
// Background image
pokemonWidget.backgroundImage = Image.fromFile(imagePath);
// Pokemon sprite
if (widgetSize == "small") {
pokemonWidget.addSpacer(20);
var widgetImg = pokemonWidget.addImage(pokemon.sprite);
widgetImg.centerAlignImage();
pokemonWidget.setPadding(0, 10, 0, 0);
}
else {
var widgetImg = pokemonWidget.addImage(pokemon.sprite);
widgetImg.rightAlignImage();
pokemonWidget.setPadding(0, 25, 0, 10);
}
widgetImg.imageSize = new Size(100, 100);
pokemonWidget.url = "https://pokemondb.net/pokedex/" + pokemon.name;
if (widgetSize == "small")
pokemonWidget.presentSmall();
else
pokemonWidget.presentMedium();
Script.setWidget(pokemonWidget);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment