-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLensCycle.scriptable
More file actions
12 lines (11 loc) · 12.3 KB
/
Copy pathLensCycle.scriptable
File metadata and controls
12 lines (11 loc) · 12.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
{
"always_run_in_app" : false,
"icon" : {
"color" : "purple",
"glyph" : "flushed"
},
"name" : "LensCycle",
"script" : "\/\/ Author: Aaron Liang\n\/\/ 隐形眼镜手动佩戴计数 - Scriptable 中号组件\n\nconst fm = FileManager.local()\nconst dir = fm.documentsDirectory()\nconst dataPath = fm.joinPath(dir, \"contactLensData.json\")\n\nconst MAX_DAY = 14\nconst REFRESH_DAYS = 30\n\nconst BASE64_ICON =\n\"iVBORw0KGgoAAAANSUhEUgAAAUgAAAGICAYAAAAj\/HmHAAAVF0lEQVR4nO3df6SmZ37H8c+0IfaPZTREV2tH4xpKCDGR+SeRylomUlOJ9J+sZVYrhGHZKvkrlDKE1HAYhmVWmFVSianURGtjV5bKSOwwGlYvHT26DEeHYSiHMf1jrjPznCfnfs7947qu7\/Xj\/WLZnX3Oc77nvq\/7c3\/vX9ctAQAAAAAAAAAAAAAAAAAAAAAAAACAjh2xLgBt89JPrWsY4qS\/tq4BZSMgsY+XtiSdta7DmmPbgBgEWOOl+9Y1lICAhCT9nnUBAFAqAhIABhCQADCAgASAAQQkAAwgIAFgAAEJAAMISAAYQEACwAACEgAGEJAAMGBWQHrpEs\/sAqiNl96b8vnJAemly5LOhP9OSAIonpeuhLz6Wy99NPbn5nSQf7j2i+976ZMZ3wMASXnpagjG0yv\/\/Edjf37ylE6bukamiKofRwUPMJbr56Wrkk4d9P+NXb9RL9KEbvJqzO8ELHjpS+saMJ+XrmggHKdIcRV7cVEAMJeXLmn\/IfVsSW7zCZ3k6BOhQGmc9Jx1DZjOSx8qXESOIeV9kK9xPgtADl76IOTNGzG\/N\/mN4oQkgJS89K+Sfpjiu7M8SUNIAkghHFJ\/P9X3P5bqi9d56T63TgCIJUfjlfVZ7HDx5krO3wmgPbmOSi0mqzjtpS8Mfi+AynnpYs5Tdlaz+TzPeUkAU3jpoqS3cv5O0+nOCEkAY4Sbv7OGo1TAfJCEJIBNwkMnZyx+d7ar2JuEkPzUSa9Y1wKgHNYNlHkHueKU9cIAUI4S8qCkgJRUxkIBYKuUHCguIKVyFg6AvLx0oaTtv8iAlAhJoDfhSvXb1nWsKjYgJUIS6EW4x\/GMdR3ririKvUkIyY+d9Lp1LQDiK7kRKrqDXMHckkCDSt+uawlISeUvTLSD+QLSq2F7riogpToWKoDNatmOqwtIiXdxA7XKPRvPUlUGZPBqTQsa6J3VhBNL1ByQkiQv\/cK6BgCbhWbmjHUdU1UfkJJeppMEylXz9tlCQEqqeyUArap9u2wmIKWHF2845AaMeWmr9nCUGgvI4GUvfWldBNArL21JOmtdRwwtBqQknWhh7wXUxkv\/qEbCUargWewleBc3kE+LTUmrHeRDLa40oDStbmfNB6TU7soDrNX2ZMxUXQSkREgCiVT1ZMxU3QSk9PA2oCvWdQAt6KHpmHwBo6GF8pWTnrMuojQNrd9FuLg3rIUxMnb9dtVBrjnB\/ZLANC2E4xQ9B6QknbAuAKhFb+EoEZBdrnRgitavVG\/S9I3iY4WV\/6mTXrGuBShJr8G4p\/sOcsUpL31uXQRQit7DUSIg173AoAAIxz0E5AEYHOiVly4w\/h8hIAeEm8ovWdcB5OKlq5Letq6jJATkZmesCwByCF3jKes6SkNAHiJ0klet6wBS4ZB6GAE5zikvfWhdBBAb4bgZATneG0x0gVa08s6Y1AjIaU5zuI3aeemyGnotQkoE5HSn2POiVl76QNKb1nXUgkcNZ+J9N6gNO\/bp6CAXYAJe1MBLHxGO8xCQy51m8KFU4Xzja9Z11IqAjISQRKE437gAARkRIYlSeOkc43E5AjIyBiWshSvV71jX0QKuYifAFW5YYQcdFx1kIswGhNwIx\/gIyLTOeOkT6yLQPsIxDQIyvVcZvEjFS1cYX+kQkJkwiBGbl85LOm1dR8sIyIwISUT2Y+sCWkdAZhYu3ly2rgP18tJldrZ5TL4VhRUT1WdO+p51EatYvw+UepsW6yeOseuXDtLWy9YFoA5e+oBwzI+ANMagx0g\/tC6gRwRkAQhJbML4sMOjhoXY2whKPfeF\/AhGe3SQhWGjABPcloOALBAbR7+8dFFMcFsMArJQhGS33rIuAI8QkAUjJPvBM9Vl4iJN4cJG8y9O+nPrWpAGwVguOsg6MCNQo1ivZSMgK8LG1BbWZ\/kIyMqEyS4+sq4D83npEuFYBwKyTq956UvrIjBdmGH+jHUdGIeArNcJupC6hHB81boOjEdAVs5LV6xrwOHCzoxwrAwBWb\/TdJJlY\/3Ui4BsRLh4c9W6DuxHONaNgGzLKS\/90roISF76O8KxfgRke17y0ufWRVTOL\/zh85LejVMKLPGoYZte8NJ95pacxTvp+OwfpmtsCh1kw9hYJ7tNOGIVAdk4NtrxnPTEnJ\/z0hbLuU0EZAfYeA8393SEly5JOhu5HBSCgOwEtwENWxiOZ+JWg5JwkaYvp7h4s9+CcKQr7wAdZIfYuB+6PeeHWH79ICA7xUau23MuyrDc+kJAdmx9Y\/fSF1a15OSkI1PD0Us\/JRzb4aXfjPkc5yA7t7LR\/7uk5y1ryeTm1B8IT8b8VfxSYMVJz475HCeo0ZWpF2UY60264aRnxnxw9tVMBg5qQzhC0raTjo398OxzkGGw\/WruzwM5EY6QpCnhKEW4Hy68G+XE0u8BUiEcIc2753XxVWwnPSfpt0u\/B0hk0tRlhGOb5j4QEOU2Hyf9qaR\/i\/FdQES3xs7Ow4QTzdpZ8uRY9EfOwmStL8T+XmCia046OeaDBGOTbjrpqaVfkuSZ3DDt\/0spvhsYYcdJT475IOHYpCjhKCWctIBOEkZuOek7Yz5IOLYn9kQsyR41dNKLzBqDzG6OCUcvvUs4tidF3mQJMAYjMhjVOXrpnKR3MtSDjFI1Y9k6PEISKY3ZQLy0JWb\/bs3o881zZD0E5qZypDAyHNlBNyj1aTyTc4QMVsRCOPYrxzUOk\/kgwx\/2lcXvRlO2D\/sA4dicu2E+zyzNndmEueERxV9b\/X5Ub2fTxANeOk84NmfHSd\/O+QvNb8NhEGOGjVNWeemCpLcz1oP0ot38PYX5KxdCq3zNug5U4\/Yh4XhZhGNrvrYIR6mADnIV3SQOs+ncE+OnPdYPm5h3kKusFwbKNjQ+vHSZcGyOLyEPigpIiZDEoAPfYe2li5LezFwL0roxdpq61IoNIy\/9l6Q\/sa4DRdh10uPr\/+gfPDJ4zqAeJFJag1RUMQfh6ZvuHXjFmkPqtpQWjHuKO8ReF+6X5OVgfbpJODbvRqnhKFUQkJLkpD8TN5X35s76rR28FqE9Y99PbaXY5B7CBtKH9a7CS+9L+olROUig5M5xTxUd5KqwUL+2rgPpHBCOWyIcW3KrhnCUKilyCN1kew4IR9ZxW0weGZyr6oCU2IBaQji2rZaucVV1h9gHuGFdAKLwa\/+DcGxIjeEoVVr0QdigqvbwfTJeuiTpjG05iOhu7inKYmqhg5TEJLwVu7MSjp+IcGyJrzkcpYY6yD28j7suTjripSuSTlvXgnhqPaRe18QfcRAOuavxK0kvWReBeFoJR6mhP+QgTHgBZFX1+caDNHMO8iDhfivOSwLpZX9fTA5Nd5CrOOQG0mjpkHpd0x3kqpZXImCl9e2q6T9uCN0ksEzrwbinmw5yVS8rF0ihp+2ny4CU+lrJQCy9bTfdBqTU38oGluhxe+k6IKU+Vzow0U6v20n3ASk9DEle6QCscdIRJz1pXYeVLvcKm3CFG3ig165xFR3kGgYFwHawh4UwwEv\/KclZ1wHkRDDuRwc5wEnHJV23rgPIyB\/+kb6wtxiB85Jo3LaTjlkXUSICciRCEi3ikHozDrFHCgOJF4ShJRxSH4KAnMBJz0j6zLoOIIJb4Tw7NqC9nolDbtSKw+rx6CBnYpChQncZt9MQkAuEwXbNug7gMOGRweZeiZAaAbmQk06K+yVRLrrGBVhwEXFeEoVp7i2DudFBRsSeGgXZJhyXY4NOgE4SlthRx0MHmQAXb2CFcIyLhZkY3SQyueekx6yLaA0dZGLs0ZHBbwnHNNh4M6GTRArsgNOig8yEgYzYGFPpEZAZhQF907oOVO8m4ZgHC9kIh9yYg2DMiw7SCAMdUzFm8iMgDTHgMRZjxQYBaYyBjxG2rQvoFRtnIbz0haTnretAWdiB2mLhF8ZLX0o6YV0HbBGMZWAlFIgr3H0jHMvBOcjCeOmqdQ0AHmBPVRi6R0h0kaWggywI4Yg9jIUyEJAF8NL7bBBY56X7XrpsXUfPaOONEYwY4Z+c9JfWRfSIDtKQl96zrgFVeIMdqQ06SCNe2pJ01roO1IWLN3mxsA3QDWAJQjIfDrEzIxyxVLh480vrOnpAQGbipfOEIyJ6ifGUHgGZQbhV48fWdaA9XvrAuoaWcS4jMfbyyOQfnPQ31kW0hoBMiHBEZj930g+si2gJh9gJeOldwhEG3mTcxUUHGRkDFIX41EmvWBdROwIyIsIRhfm1k160LqJmHGJH4KUtwhEFeoH5RZehg1zISxckvW1dB7AJT9\/MQwe5gJfOi3BEBcLTNx9Z11Eb9iozeemipLes6wAm4uLNBATkRF66JOmMdR3AAoTkSATkBFyIQUs4L3k4zkGORDiiNYzpwxGQh\/DSOQYSWsXY3owWewMGDzrysZNety6iNATkAMIRHeLizRoOsddwSI2OnWLs70dArvDS+5Lesa4DsBRuKmciXnGI\/RB7TuAbfuakH1kXYan7gPTSOdE1AoN6vl+y2z9comsEJvjMSd+zLiK3Ls9B8oZBYLKXe9xmuusgvbQl6ax1HUCtejrk7uYPlTikBmLpJSS7OcQmHIF4wq1An1jXkVoXAUk4Akm8GuZFbVbzbTLhCCTX7HPczQZkmF7+Nes6gF60eF6yuUNsL10IXSPhCGTU4nnJphKfW3iAMrTSTTbxR0i8KwYoTQshWf0fIHEhBihV7SFZ\/TlIwhEoV+1Tp1Wd7oQjUI8au8lqO0jCEahLjdtsdYle40IG8EhNnWQ1HSRTlAFtCOclq9iWq0jy8LznW9Z1AIir9G6y6OIkDqmB1pUckkUfYhOOQPvCIfcl6zoOUmxyE45Af0rrJovrIL10jnAE+lTatl9UWjPZBACpnE6yiCKk8vYcAMz93Ek\/sCzAPCC99L6kn1jXAaBMlt1kCQFJ5whgI6uQNL1IQzgCGMMqK0xSmWAEMEfuTjJrB+mlLcIRwFzhpvJf5Pp92dKY56kBxJSjm8zSQXrpPRGOACLKcTSaPIE5pAaQUspOMtkXE4wAMvuZk34U8wuTBCThCMBC7G4y6jlIL\/094QjASuy3KEZLWyaaAFCQKIfbiwOSYARQqH920l8s+YIYAckhNYBiLTkvuegcJOEIoHThvOSHc352VrISjABqNLWbnNxBhkcGAaA6U5u7OYfYPDIIoFpeujz2s5MPsTm8BlC7sYfaxb3VEABKQUAC6I6X\/mPM5whIAD361pgPEZAAevR\/Yz5EQEKSdsN\/8E33rAtAEqPWK1ex+3bPSY+t\/gPr96FbTvrO6j+wbNrBVWwcaj0c8ch6OIZ\/M3+PPPIiIPt0i419nrDcvrauA3kQkP3ZPqg7wnhOepodTB84xOoIG3VcTjrCecm20UF2gnBMg+XaNgKyfZxvTIzl2y4CsmFOOsL5xjxCSN60rgNxEZBt2qWrWcZLv5n6M056SlzhbgoB2Z47TnrcuogG\/P6cH+IKd1sIyLbccdJR6yIaMWoygyGEZBsIyHbcJhzLQkjWj\/sgG8CGmMSo2V4Ow72SdaODrBzhmEy0WXy4wl0vAhI4gJOejfx9T0nyMb8T6RGQ9bpN91gXJx0XIVkVzkFWhlCsWwhJScwvWQM6yIoQjm1hfZaPgKwEG1OzrlkXgGEEZPl4bLBhTjrJ+i0XAVmwMNkEjw12gJnKy0RAFoquoj9Oetq6BuxHQBaIcOwXN5WXhYAsC+cbsXdT+XXrOkBAlmSb843Y46Rn2Vna40bxArAhYAiTXdiigzRGOOIwjBE7BKQhBj7GCmOF57gzIyBtbBOOmCo8x33duo6eEJCZhZu\/j1nXgTqFadiuW9fRCwIyI7pGxBBC8oZ1HT0gIDMhHBGTk55hTKVHQKbnGchIhSdv0iIg07q5OkEqkAKvc0iHgExnJwxcIDle55AGAZnGjpOetC4CfSEk4yMgIwu38RCOMBFCknklIyEg42LvDXNhXkku3ETAZBVx7DITD0qyd\/6biS6WoYNcbodwRKm4xWwZAnIhzjeidITkfATkfPcYeKgFY3UeAnK6u+FKNedvUZUQktvWddSEgJzmd076tnURwFxOOkY3OR4BOVLoGv\/Yug4ghhCSv7Ouo3QE5AjscdGisMPfta6jZATkIQhHtIxb1DYjIDcgHNGDMM7vWNdRIgLyAOF8I+HYMS99bl1DTk46ypj\/JgJyDYMEPWP870dArmBwANwvuYqADAhH4JHw5s3uZ6ciIMOTMdZFAKUJc0t2PW1a9wHJkzHAsDBtWrcT8PYckHfoHIHDOenpXreVLgMy3MZz1LoOoCY9XrzpLSB3e90TAjGEizfdHHL3FJB3eawKWK6nQ+5eAnKHizFAXD2EZPOTvvawEgErTjrS8ovBmu4gCUcgvbCdNXm\/ZLMBSTgC+bR6v2STAUk4Avk56WnrGmJrLiAJR8BOa3NLNhOQzOGImJz0onUNtVqZW\/KGdS1LtRCQOwQjUB4nPSPpmnUdS1QfkE560roGAAdz0klV\/PbEqgOSzhEoX3h7YpXPcFcbkIQjUI\/wDPd16zqmqjEgmeAWqJCTnlVlIVnVo4YEI1C3EJKq5fHEajpIwhFoRy3bcxUBWcvCBDBeDdt16QHJBLdAw8L2fdu6jiElB+QOE9wC7XPSE6U2QqUG5F1uAAf6UmJIFheQ4ZlqZv8GOlTai8GKCsgS9yAA8go3lXvrOqRyAvIe4Qhgj5OOq4DZgEoIyDuushvWAaRXwmxA1gF520lHjWsAUCgnnQxHl9ctfr9VQO5K2nbSE0a\/H0BFwiOK2btJi4C87aTHw4lYABglzC2Z9eJN7oDcpWsEMFe4eJMtJHMG5C5PxgBYyknHc931kisgeWwQQFQ5QjL57TXc3wggoW1J30315Sk7SN42CCApJx1LmTNJOkiCEUBOTjripf+V9Acxvzd6B0k4ArAQ7pC5E\/M7owYk4QjAkpOOxsyhWAHJ+UYAxQh5tLP0exYHZJi\/kcltARQl5NLNJd8xJyA\/XimArhFAsZz0lBY8eTM5IJ30uqSvVNCsvwAwJDyeuC+vvPTfY36WDhD71PJC99Q4OmrT3vgeu36ZqBZAN6bu+KwnzAWAYhGQADCAgASAAQQkAAwgIAFgAAEJAAMISAAYQEACwAACEgAGEJAAMICABIABPJCPb\/DS\/+jBuz2+ZV1LBrf1YJr+vb9110nHDOsBAAAAAAAAAAAAAAAAAAAAAAAAAABAGf4fHf9I+DP3T5EAAAAASUVORK5CYII=\"\n\nconst COLORS = {\n bgTop: new Color(\"#05080c\"),\n bgMid: new Color(\"#07111b\"),\n bgBottom: new Color(\"#0a1620\"),\n neon: new Color(\"#20f0c8\"),\n neonSoft: new Color(\"#73ffd8\"),\n accent: new Color(\"#ff2a2a\"),\n warn: new Color(\"#ffb020\")\n}\n\nfunction loadData() {\n const fallback = { day: 0, lastIncrementAt: null }\n if (!fm.fileExists(dataPath)) return fallback\n try {\n const obj = JSON.parse(fm.readString(dataPath))\n return {\n day: Number.isInteger(obj.day) ? Math.max(0, Math.min(MAX_DAY, obj.day)) : 0,\n lastIncrementAt: typeof obj.lastIncrementAt === \"string\" ? obj.lastIncrementAt : null\n }\n } catch {\n return fallback\n }\n}\n\nfunction saveData(data) {\n const raw = JSON.stringify(data)\n if (fm.fileExists(dataPath)) {\n try {\n if (fm.readString(dataPath) === raw) return\n } catch {}\n }\n fm.writeString(dataPath, raw)\n}\n\nfunction formatDate(iso) {\n if (!iso) return \"--\/-- --:--\"\n const d = new Date(iso)\n const mm = String(d.getMonth() + 1).padStart(2, \"0\")\n const dd = String(d.getDate()).padStart(2, \"0\")\n const hh = String(d.getHours()).padStart(2, \"0\")\n const mi = String(d.getMinutes()).padStart(2, \"0\")\n return `${mm}\/${dd} ${hh}:${mi}`\n}\n\nfunction decodeBase64Image(base64) {\n return Image.fromData(Data.fromBase64String(base64))\n}\n\nfunction getScriptURL(action) {\n const name = encodeURIComponent(Script.name())\n return `scriptable:\/\/\/run?scriptName=${name}&action=${action}`\n}\n\nasync function handleAction(data) {\n const q = args.queryParameters || {}\n const action = q.action\n\n if (action === \"increment\") {\n if (data.day < MAX_DAY) {\n data.day += 1\n data.lastIncrementAt = new Date().toISOString()\n saveData(data)\n } else {\n data.day = 0\n data.lastIncrementAt = null\n saveData(data)\n }\n } else if (action === \"forceReset\") {\n if (config.runsInApp) {\n const alert = new Alert()\n alert.title = \"Purge Log?\"\n alert.message = \"Set day count to 0.\"\n alert.addAction(\"PURGE\")\n alert.addCancelAction(\"BACK\")\n const res = await alert.presentAlert()\n if (res === 0) {\n data.day = 0\n data.lastIncrementAt = null\n saveData(data)\n }\n }\n }\n\n return data\n}\n\nfunction applyBackground(widget) {\n const grad = new LinearGradient()\n grad.locations = [0, 0.48, 1]\n grad.colors = [COLORS.bgTop, COLORS.bgMid, COLORS.bgBottom]\n widget.backgroundGradient = grad\n widget.setPadding(0, 0, 0, 0)\n}\n\nfunction addLeftPanel(root, data) {\n const left = root.addStack()\n left.layoutVertically()\n left.url = getScriptURL(\"increment\")\n left.size = new Size(0, 0)\n\n left.addSpacer()\n\n const content = left.addStack()\n content.layoutVertically()\n content.centerAlignContent()\n content.setPadding(0, 0, 0, 0)\n\n const dayText = content.addText(`Day ${data.day}`)\n dayText.textColor = COLORS.neon\n dayText.font = new Font(\"DINAlternate-Bold\", 40)\n dayText.minimumScaleFactor = 0.6\n dayText.lineLimit = 1\n\n content.addSpacer(10)\n\n const timeText = content.addText(formatDate(data.lastIncrementAt))\n timeText.textColor = COLORS.neonSoft\n timeText.font = new Font(\"DINAlternate-Bold\", 16)\n timeText.minimumScaleFactor = 0.8\n timeText.lineLimit = 1\n\n if (data.day >= MAX_DAY) {\n content.addSpacer(8)\n const maxText = content.addText(\"MAX\")\n maxText.textColor = COLORS.warn\n maxText.font = Font.semiboldSystemFont(11)\n }\n\n left.addSpacer(30)\n}\n\nfunction addRightPanel(root) {\n root.addSpacer(30)\n\n const right = root.addStack()\n right.url = getScriptURL(\"forceReset\")\n right.centerAlignContent()\n right.size = new Size(112, 0)\n\n const img = right.addImage(decodeBase64Image(BASE64_ICON))\n img.imageSize = new Size(103, 103)\n img.resizable = true\n img.centerAlignImage()\n}\n\nasync function createWidget(data) {\n const widget = new ListWidget()\n applyBackground(widget)\n\n const outer = widget.addStack()\n outer.layoutHorizontally()\n outer.setPadding(18, 55, 18, 22)\n outer.centerAlignContent()\n\n addLeftPanel(outer, data)\n addRightPanel(outer)\n\n widget.refreshAfterDate = new Date(Date.now() + REFRESH_DAYS * 24 * 60 * 60 * 1000)\n return widget\n}\n\nasync function main() {\n let data = loadData()\n data = await handleAction(data)\n\n const widget = await createWidget(data)\n\n Script.setWidget(widget)\n\n const hasAction = !!(args.queryParameters && args.queryParameters.action)\n\n if (!config.runsInWidget && !hasAction) {\n await widget.presentMedium()\n }\n\n Script.complete()\n}\n\nawait main()",
"share_sheet_inputs" : [
]
}