├── README.md └── index.js /README.md: -------------------------------------------------------------------------------- 1 | # iOS14 widget with scriptable 2 | 3 | ### Useage 4 | 1. Download [scriptable](https://scriptable.app/) from App Store 5 | 2. Create a new script (replace the api token with your own) 6 | 3. Add to your homescreen scriptable widget 7 | 8 | *Inspired by [Spencer Woo](https://gist.github.com/spencerwooo/7955aefc4ffa5bc8ae7c83d85d05e7a4)* 9 | 10 | ### Preview 11 | ![preview](https://ww1.sinaimg.cn/large/883f4200ly1gj2qdyl8v8j20v90odjup.jpg) 12 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Variables used by Scriptable. 2 | // These must be at the very top of the file. Do not edit. 3 | // icon-color: orange icon-glyph: quote-right 4 | 5 | const User = 'USER' 6 | const City = 'beijing' 7 | const WeatherKey = '' // you can get it from https://dev.heweather.com/ 8 | const AQIToken = '' // you can get it from https://aqicn.org/data-platform/token/#/ 9 | 10 | const aqi = await getAQI() 11 | const lunarData = await getLunarData() 12 | const weatherData = await getWeather() 13 | 14 | const widget = createWidget() 15 | Script.setWidget(widget) 16 | Script.complete() 17 | 18 | function createWidget() { 19 | const w = new ListWidget() 20 | const bgColor = new LinearGradient() 21 | 22 | bgColor.colors = [new Color('#2c5364'), new Color('#203a43'), new Color('#0f2027')] 23 | bgColor.locations = [0.0, 0.5, 1.0] 24 | w.backgroundGradient = bgColor 25 | 26 | w.setPadding(12, 12, 12, 0) 27 | w.spacing = 6 28 | 29 | const time = new Date() 30 | 31 | const hour = time.getHours() 32 | const isMidnight = hour < 8 && 'midnight' 33 | const isMorning = hour >= 8 && hour < 12 && 'morning' 34 | const isAfternoon = hour >= 12 && hour < 19 && 'afternoon' 35 | const isEvening = hour >= 19 && hour < 21 && 'evening' 36 | const isNight = hour >= 21 && 'night' 37 | 38 | const dfTime = new DateFormatter() 39 | dfTime.locale = 'en' 40 | dfTime.useMediumDateStyle() 41 | dfTime.useNoTimeStyle() 42 | 43 | const Line1 = w.addText(`[🤖]Hi, ${User}. Good ${isMidnight || isMorning || isAfternoon || isEvening || isNight}`) 44 | Line1.textColor = new Color('#ffffff') 45 | Line1.font = new Font('Menlo', 11) 46 | 47 | const enTime = dfTime.string(time) 48 | const Line2 = w.addText(`[📅]${enTime} ${lunarData}`) 49 | Line2.textColor = new Color('#C6FFDD') 50 | Line2.font = new Font('Menlo', 11) 51 | 52 | const Line3 = w.addText(`[☁️]${weatherData} AQI:${aqi}`) 53 | Line3.textColor = new Color('#FBD786') 54 | Line3.font = new Font('Menlo', 11) 55 | 56 | const Line4 = w.addText(`[${Device.isCharging() ? '⚡️' : '🔋'}]${renderBattery()} Battery`) 57 | Line4.textColor = new Color('#2aa876') 58 | Line4.font = new Font('Menlo', 11) 59 | 60 | const Line5 = w.addText(`[🕒]${renderYearProgress()} YearProgress`) 61 | Line5.textColor = new Color('#f19c65') 62 | Line5.font = new Font('Menlo', 11) 63 | 64 | return w 65 | } 66 | 67 | async function getAQI() { 68 | const url = `https://api.waqi.info/feed/${City}/?token=${AQIToken}` 69 | const request = new Request(url) 70 | const res = await request.loadJSON() 71 | return res.data.aqi 72 | } 73 | 74 | async function getLunarData() { 75 | const url = 'https://api.xlongwei.com/service/datetime/convert.json' 76 | const request = new Request(url) 77 | const res = await request.loadJSON() 78 | return `${res.ganzhi}年(${res.shengxiao})${res.chinese.replace(/.*年/, '')}` 79 | } 80 | 81 | async function getWeather() { 82 | const requestCityInfo = new Request( 83 | `https://geoapi.heweather.net/v2/city/lookup?key=${WeatherKey}&location=${City}&lang=en` 84 | ) 85 | const resCityInfo = await requestCityInfo.loadJSON() 86 | const { name, id } = resCityInfo.location[0] 87 | 88 | const requestNow = new Request(`https://devapi.heweather.net/v7/weather/now?location=${id}&key=${WeatherKey}&lang=en`) 89 | const requestDaily = new Request(`https://devapi.heweather.net/v7/weather/3d?location=${id}&key=${WeatherKey}&lang=en`) 90 | const resNow = await requestNow.loadJSON() 91 | const resDaily = await requestDaily.loadJSON() 92 | 93 | return `${name} ${resNow.now.text} T:${resNow.now.temp}° H:${resDaily.daily[0].tempMax}° L:${resDaily.daily[0].tempMin}°` 94 | } 95 | 96 | function renderProgress(progress) { 97 | const used = '▓'.repeat(Math.floor(progress * 24)) 98 | const left = '░'.repeat(24 - used.length) 99 | return `${used}${left} ${Math.floor(progress * 100)}%` 100 | } 101 | 102 | function renderBattery() { 103 | const batteryLevel = Device.batteryLevel() 104 | return renderProgress(batteryLevel) 105 | } 106 | 107 | function renderYearProgress() { 108 | const now = new Date() 109 | const start = new Date(now.getFullYear(), 0, 1) // Start of this year 110 | const end = new Date(now.getFullYear() + 1, 0, 1) // End of this year 111 | const progress = (now - start) / (end - start) 112 | return renderProgress(progress) 113 | } 114 | --------------------------------------------------------------------------------