Saltar al contenido principal

CUP=X

Widgets

iPhone iPad Mac

Tasas de cambio de CUP=X
directo en tu Home Screen.

Widgets gratuitos con las tasas del peso cubano. USD, EUR, CAD, MXN y MLC — siempre a la vista en tu iPhone, iPad o Mac.

info

Requiere Scriptable (gratis en la App Store) para ejecutar los widgets.

Ejemplo de Widget de Tasas de Cambio

Widgets para iOS

update

Tiempo Real

Las tasas se actualizan automáticamente durante todo el día.

palette

Personalizable

Elige entre diferentes tamaños y diseños de widget.

touch_app

Interactivo

Toca el widget para abrir CUP=X con información detallada.

Cómo Instalar tu Widget

1

Instalar Scriptable

Descarga e instala la aplicación Scriptable desde la App Store.

2

Copiar el Código del Widget


    /* --------------------------------------------------------------
    Description:
    iOS/iPad Scriptable widget - CUP=X Informal Currency Exchange Rates in Cuba
    Source: elToque: https://eltoque.com/tasas-de-cambio-cuba
    
    Version:
    1.0.0
    -------------------------------------------------------------- */
    const widgetUrl = 'https://peso-cubano.com';
    const apiUrl = `https://api.cambiocuba.money/api/v1/x-rates-by-date-range?trmi=true&period=7D`;
    const currencies = ['ECU', 'USD', 'MLC', 'CAD', 'MXN'];
    const images = [
    {
    name: 'eur',
    url: 'https://peso-cubano.com/img/eur.png'
    },
    {
    name: 'usd',
    url: 'https://peso-cubano.com/img/usd.png'
    },
    {
    name: 'cad',
    url: 'https://peso-cubano.com/img/cad.png'
    },
    {
    name: 'mxn',
    url: 'https://peso-cubano.com/img/mxn.png'
    },
    {
    name: 'mlc',
    url: 'https://peso-cubano.com/img/mlc.png'
    },
    ];
    
    const languages = {
    en: {
    shortTitle: 'CUP=X',
    subtitle: 'Exchange Rates',
    noData: 'No currency exchange rate data.',
    },
    es: {
    shortTitle: 'CUP=X',
    subtitle: 'Tasas de Cambio',
    noData: 'No hay datos de tasas de cambio de divisas.',
    }
    };
    
    async function init() {
    let widget;
    try {
    const data = await getData();
    const resources = await getImages();
    widget = createWidget(data, resources, widgetUrl);
    } catch (err) {
    console.error(`Error getting widget data. ${err}`);
    widget = createEmptyWidget();
    } finally {
    if (config.runsInWidget || config.runsInAccessoryWidget) {
    // create and show widget
    Script.setWidget(widget);
    Script.complete();
    }
    else {
    widget.presentMedium();
    }
    
    }
    }
    
    function createWidget(data, resources, widgetUrl) {
    if (config.runsInAccessoryWidget) {
    return createLockScreenWidget(data, widgetUrl);
    }
    else if (config.widgetFamily === 'small') {
    return createSmallWidget(data, resources, widgetUrl);
    }
    return createMediumWidget(data, resources, widgetUrl);
    }
    
    // assemble empty widget layout
    function createEmptyWidget() {
    const w = new ListWidget();
    w.backgroundColor = Color.white();
    w.url = widgetUrl;
    
    w.addSpacer();
    
    const infoText = w.addText(getNoDataText());
    infoText.textColor = Color.black();
    infoText.font = Font.boldMonospacedSystemFont(20);
    infoText.centerAlignText();
    
    const runsInSmallWidget = config.widgetFamily === 'small';
    
    if (runsInSmallWidget || config.runsInAccessoryWidget) {
    const fontSize = runsInSmallWidget ? 18 : 14;
    infoText.font = Font.boldMonospacedSystemFont(fontSize);
    infoText.leftAlignText();
    }
    
    w.addSpacer();
    
    return w;
    }
    
    // assemble medium widget layout
    function createMediumWidget(data, resources, widgetUrl) {
    const { USD, ECU, MLC, CAD, MXN } = data;
    
    const w = new ListWidget();
    w.backgroundColor = Color.white();
    w.url = widgetUrl;
    
    w.addSpacer(2);
    
    // header
    const headerStack = w.addStack();
    headerStack.layoutHorizontally();
    headerStack.centerAlignContent();
    headerStack.spacing = 8;
    
    // title
    const staticText = headerStack.addText(getTitleText());
    staticText.textColor = Color.black();
    staticText.font = Font.boldSystemFont(18);
    staticText.centerAlignText();
    
    w.addSpacer(4);
    
    // body
    const mainStack = w.addStack();
    mainStack.layoutHorizontally();
    mainStack.topAlignContent();
    mainStack.setPadding(0, 4, 0, 4);
    
    const leftStack = mainStack.addStack();
    leftStack.layoutVertically();
    leftStack.topAlignContent();
    
    // usd
    const usdStack = leftStack.addStack();
    usdStack.layoutHorizontally();
    usdStack.centerAlignContent();
    usdStack.spacing = 8;
    
    const usdImage = usdStack.addImage(getImage(resources, 'usd'));
    usdImage.imageSize = new Size(32, 32);
    
    const usdRateText = usdStack.addText(`= ${format(USD, 0)} CUP`);
    usdRateText.textColor = Color.black();
    usdRateText.font = Font.boldMonospacedSystemFont(16);
    
    // eur
    const eurStack = leftStack.addStack();
    eurStack.layoutHorizontally();
    eurStack.centerAlignContent();
    eurStack.spacing = 8;
    
    const eurImage = eurStack.addImage(getImage(resources, 'eur'));
    eurImage.imageSize = new Size(32, 32);
    
    const eurRateText = eurStack.addText(`= ${format(ECU, 0)} CUP`);
    eurRateText.textColor = Color.black();
    eurRateText.font = Font.boldMonospacedSystemFont(16);
    
    // cad
    const cadStack = leftStack.addStack();
    cadStack.layoutHorizontally();
    cadStack.centerAlignContent();
    cadStack.spacing = 8;
    
    const cadImage = cadStack.addImage(getImage(resources, 'cad'));
    cadImage.imageSize = new Size(32, 32);
    
    const cadRateText = cadStack.addText(`= ${format(CAD, 0)} CUP`);
    cadRateText.textColor = Color.black();
    cadRateText.font = Font.boldMonospacedSystemFont(16);
    
    
    mainStack.addSpacer();
    
    // right stack
    const rightStack = mainStack.addStack();
    rightStack.layoutVertically();
    rightStack.topAlignContent();
    
    // mlc
    const mlcStack = rightStack.addStack();
    mlcStack.layoutHorizontally();
    mlcStack.centerAlignContent();
    mlcStack.spacing = 8;
    
    const mlcImage = mlcStack.addImage(getImage(resources, 'mlc'));
    mlcImage.imageSize = new Size(32, 32);
    
    const mlcRateText = mlcStack.addText(`= ${format(MLC, 0)} CUP`);
    mlcRateText.textColor = Color.black();
    mlcRateText.font = Font.boldMonospacedSystemFont(16);
    
    // mxn
    const mxnStack = rightStack.addStack();
    mxnStack.layoutHorizontally();
    mxnStack.centerAlignContent();
    mxnStack.spacing = 8;
    
    const mxnImage = mxnStack.addImage(getImage(resources, 'mxn'));
    mxnImage.imageSize = new Size(32, 32);
    
    const mxnRateText = mxnStack.addText(`= ${format(MXN, 0)} CUP`);
    mxnRateText.textColor = Color.black();
    mxnRateText.font = Font.boldMonospacedSystemFont(16);
    
    // footer
    const date = new Date();
    const df = new DateFormatter();
    df.useFullDateStyle();
    
    const hf = new DateFormatter();
    hf.useShortTimeStyle();
    
    // add date and time
    const dateText = w.addText(`${df.string(date)} ${hf.string(date)}`);
    dateText.textColor = Color.black();
    dateText.font = Font.semiboldSystemFont(10);
    dateText.leftAlignText();
    
    return w;
    }
    
    // assemble small widget layout
    function createSmallWidget(data, resources, widgetUrl) {
    const { USD, ECU, MLC } = data;
    
    const w = new ListWidget();
    w.backgroundColor = Color.white();
    w.url = widgetUrl;
    
    // header
    w.addSpacer(8);
    
    const staticText = w.addText(getShortTitleText());
    staticText.textColor = Color.black();
    staticText.font = Font.boldSystemFont(12);
    staticText.leftAlignText();
    
    const exchangeText = w.addText(getSubtitleText());
    exchangeText.textColor = Color.black();
    exchangeText.font = Font.boldSystemFont(12);
    exchangeText.leftAlignText();
    
    // body
    const mainStack = w.addStack();
    mainStack.layoutVertically();
    mainStack.centerAlignContent();
    
    // usd
    const usdStack = mainStack.addStack();
    usdStack.layoutHorizontally();
    usdStack.centerAlignContent();
    usdStack.spacing = 4;
    
    const usdImage = usdStack.addImage(getImage(resources, 'usd'));
    usdImage.imageSize = new Size(32, 32);
    
    const usdRateText = usdStack.addText(`= ${format(USD, 0)} CUP`);
    usdRateText.textColor = Color.black();
    usdRateText.font = Font.boldMonospacedSystemFont(14);
    
    usdStack.addSpacer();
    
    // eur
    const eurStack = mainStack.addStack();
    eurStack.layoutHorizontally();
    eurStack.centerAlignContent();
    eurStack.spacing = 4;
    
    const eurImage = eurStack.addImage(getImage(resources, 'eur'));
    eurImage.imageSize = new Size(32, 32);
    
    const eurRateText = eurStack.addText(`= ${format(ECU, 0)} CUP`);
    eurRateText.textColor = Color.black();
    eurRateText.font = Font.boldMonospacedSystemFont(14);
    
    eurStack.addSpacer();
    
    // mlc
    const mlcStack = mainStack.addStack();
    mlcStack.layoutHorizontally();
    mlcStack.centerAlignContent();
    mlcStack.spacing = 4;
    
    const mlcImage = mlcStack.addImage(getImage(resources, 'mlc'));
    mlcImage.imageSize = new Size(32, 32);
    
    const mlcRateText = mlcStack.addText(`= ${format(MLC, 0)} CUP`);
    mlcRateText.textColor = Color.black();
    mlcRateText.font = Font.boldMonospacedSystemFont(14);
    
    mlcStack.addSpacer();
    
    // footer
    const date = new Date();
    const df = new DateFormatter();
    df.useShortDateStyle();
    
    const hf = new DateFormatter();
    hf.useShortTimeStyle();
    
    const dateText = w.addText(`${df.string(date)} ${hf.string(date)}`);
    dateText.textColor = Color.black();
    dateText.font = Font.semiboldSystemFont(8);
    dateText.centerAlignText();
    
    w.addSpacer(8);
    
    return w;
    }
    
    // assemble lock screen widget layout
    function createLockScreenWidget(data, widgetUrl) {
    const { USD, ECU, MLC } = data;
    
    const w = new ListWidget();
    w.url = widgetUrl;
    
    const mainStack = w.addStack();
    mainStack.layoutHorizontally();
    mainStack.centerAlignContent();
    
    // stack 1
    const stack1 = mainStack.addStack();
    stack1.layoutVertically();
    stack1.centerAlignContent();
    stack1.spacing = 4;
    
    const usdText = stack1.addText('USD');
    usdText.textColor = Color.white();
    usdText.font = Font.heavyMonospacedSystemFont(15);
    
    const eurText = stack1.addText('EUR');
    eurText.textColor = Color.white();
    eurText.font = Font.heavyMonospacedSystemFont(15);
    
    const mlcText = stack1.addText('MLC');
    mlcText.textColor = Color.white();
    mlcText.font = Font.heavyMonospacedSystemFont(15);
    
    mainStack.addSpacer(4);
    
    // stack 2
    const stack2 = mainStack.addStack();
    stack2.layoutVertically();
    stack2.centerAlignContent();
    stack2.spacing = 4;
    
    const usdRateText = stack2.addText(`= ${format(USD, 0)} CUP`);
    usdRateText.textColor = Color.white();
    usdRateText.font = Font.mediumMonospacedSystemFont(15);
    
    const eurRateText = stack2.addText(`= ${format(ECU, 0)} CUP`);
    eurRateText.textColor = Color.white();
    eurRateText.font = Font.mediumMonospacedSystemFont(15);
    
    const mlcRateText = stack2.addText(`= ${format(MLC, 0)} CUP`);
    mlcRateText.textColor = Color.white();
    mlcRateText.font = Font.mediumMonospacedSystemFont(15);
    
    return w;
    }
    
    function getTitleText() {
    const lang = Device.language();
    if (!languages[lang]) {
    return `${languages.en.shortTitle} ${languages.en.subtitle}`;
    }
    return `${languages[lang].shortTitle} ${languages[lang].subtitle}`;
    }
    
    function getShortTitleText() {
    const lang = Device.language();
    if (!languages[lang]) {
    return `${languages.en.shortTitle}`;
    }
    return `${languages[lang].shortTitle}`;
    }
    
    function getSubtitleText() {
    const lang = Device.language();
    if (!languages[lang]) {
    return `${languages.en.subtitle}`;
    }
    return `${languages[lang].subtitle}`;
    }
    
    function getNoDataText() {
    const lang = Device.language();
    if (!languages[lang]) {
    return languages.en.noData;
    }
    return languages[lang].noData;
    }
    
    async function getRate(currency) {
    const url = `${apiUrl}&cur=${currency}`;
    const req = new Request(url);
    const res = await req.loadJSON();
    const { min, max, avg, median } = res[res.length - 1];
    
    console.log(`${currency} - Min: ${min}, Max: ${max}, Avg: ${avg}, Median: ${median}`);
    
    return median;
    }
    
    async function getData() {
    const rates = {};
    const ratePromises = currencies.map(currency => getRate(currency));
    const results = await Promise.all(ratePromises);
    for (let i = 0; i < currencies.length; i++) { rates[currencies[i]]=results[i]; } return rates; } async function
        getImages() { const result={}; const imagePromises=images.map(image=> {
        const req = new Request(image.url);
        return req.loadImage().then(res => ({ name: image.name, image: res }));
        });
        const responses = await Promise.all(imagePromises);
        for (const r of responses) {
        const { name, image } = r;
        result[name] = image;
        }
        return result;
        }
    
        function getImage(resources, key) {
        return resources[key];
        }
    
        function format(value, fractionDigits = 2) {
        return Number.parseFloat(value).toFixed(fractionDigits);
        }
    
        //initialize
        await init();

Scriptable JS
3

Crear un Nuevo Script en Scriptable

Abre Scriptable, toca el botón + para crear un nuevo script y pega el código.

4

Agregar Widget a la Pantalla de Inicio

Mantén presionada tu pantalla de inicio, toca el botón +, busca Scriptable, selecciona un tamaño de widget, agrégalo, luego selecciona el script que creaste.