-
Notifications
You must be signed in to change notification settings - Fork 88
Expand file tree
/
Copy pathPriceWidgets.scriptable
More file actions
12 lines (11 loc) · 10.7 KB
/
Copy pathPriceWidgets.scriptable
File metadata and controls
12 lines (11 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
{
"always_run_in_app" : false,
"icon" : {
"color" : "deep-green",
"glyph" : "hand-holding-usd"
},
"name" : "PriceWidgets",
"script" : "\n\/\/ 添加require,是为了vscode中可以正确引入包,以获得自动补全等功能\nif (typeof require === 'undefined') require = importModule;\nconst { DmYY, Runing } = require('.\/DmYY');\n\n\/\/ @组件代码开始\nclass Widget extends DmYY {\n constructor(arg) {\n super(arg);\n this.en = ' btc';\n this.name = '比特币';\n config.runsInApp &&\n this.registerAction(\n '关注种类',\n async () => {\n return this.setAlertInput('比特币种类', '设置关注种类', {\n btcType: 'BTC,ETH,BNB',\n });\n },\n { name: 'centsign.circle', color: '#feda31' }\n );\n config.runsInApp && this.registerAction('基础设置', this.setWidgetConfig);\n }\n\n format = (str) => {\n return parseInt(str) >= 10 ? str : `0${str}`;\n };\n\n endpoint = 'https:\/\/api.coingecko.com\/api\/v3';\n nomicsEndpoint = 'https:\/\/api.nomics.com\/v1';\n\n dataSource = [];\n\n init = async () => {\n if (this.settings.dataSource && !config.runsInApp) {\n this.dataSource = this.settings.dataSource;\n } else {\n await this.cacheData(this.settings.btcType);\n }\n this.cacheData(this.settings.btcType);\n };\n\n cacheData = async (params) => {\n try {\n const ids = await this.transforBtcType(params);\n let response = await this.$request.get(\n `${this.endpoint}\/coins\/markets?vs_currency=usd&ids=${ids}`,\n 'STRING'\n );\n this.dataSource = [];\n response = JSON.parse(response);\n if (!response.length) response = await this.getAllJson();\n if (ids) {\n const idsData = ids.split(',');\n idsData.forEach((id) => {\n const it = response.find((item) => item.id === id);\n if (it && this.dataSource.length < 6) {\n this.dataSource.push({\n id: it.id,\n name: it.name,\n image: it.image,\n symbol: it.symbol.toUpperCase(),\n current_price: '' + it.current_price,\n high_24h: it.high_24h,\n low_24h: it.low_24h,\n price_change_percentage_24h: it.price_change_percentage_24h,\n last_updated: it.last_updated,\n });\n }\n });\n } else {\n response.forEach((it, index) => {\n if (index > 5) return;\n this.dataSource.push({\n id: it.id,\n name: it.name,\n image: it.image,\n symbol: it.symbol.toUpperCase(),\n current_price: '' + it.current_price,\n high_24h: it.high_24h,\n low_24h: it.low_24h,\n price_change_percentage_24h: it.price_change_percentage_24h,\n last_updated: it.last_updated,\n });\n });\n }\n\n this.settings.dataSource = this.dataSource;\n this.saveSettings(false);\n } catch (e) {\n console.log(e);\n return [];\n }\n };\n\n transforBtcType = async (params) => {\n let btcType;\n if (params) btcType = params.split(',');\n\n const btcAll = await this.getAllJson();\n\n if (!btcType)\n return btcAll\n .filter((item, index) => index < 6)\n .map((item) => item.id)\n .join(',');\n\n return btcType\n .map((item) => {\n const result =\n btcAll.find((btc) => btc.symbol.toUpperCase() === item) || {};\n return result.id;\n })\n .filter((item) => !!item)\n .join(',');\n };\n\n getAllJson = async () => {\n const cachePath = this.FILE_MGR.joinPath(\n this.FILE_MGR.libraryDirectory(),\n `${Script.name()}\/datas`\n );\n const filename = `${cachePath}\/BTC.json`;\n if (!this.FILE_MGR.fileExists(cachePath))\n this.FILE_MGR.createDirectory(cachePath, true);\n\n if (this.FILE_MGR.fileExists(filename)) {\n const data = Data.fromFile(`${cachePath}\/BTC.json`).toRawString();\n return JSON.parse(data);\n } else {\n const response = await this.$request.get(\n `${this.endpoint}\/coins\/markets?vs_currency=usd&ids=`\n );\n const data = Data.fromString(JSON.stringify(response));\n this.FILE_MGR.write(filename, data);\n return response;\n }\n };\n\n renderImage = async (uri) => {\n return this.$request.get(uri, 'IMG');\n };\n\n notSupport(w) {\n const stack = w.addStack();\n stack.addText('暂不支持');\n return w;\n }\n\n getSmallBg = async (url) => {\n const webview = new WebView();\n let js = `const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.onload = () => {\n const { width, height } = img\n canvas.width = width\n canvas.height = height\n ctx.globalAlpha = 0.3\n ctx.drawImage(\n img,\n -width \/ 2 + 50,\n -height \/ 2 + 50,\n width,\n height\n )\n const uri = canvas.toDataURL()\n completion(uri);\n };\n img.src = 'data:image\/png;base64,${Data.fromPNG(url).toBase64String()}'`;\n let image = await webview.evaluateJavaScript(js, true);\n image = image.replace(\/^data\\:image\\\/\\w+;base64,\/, '');\n return Image.fromData(Data.fromBase64String(image));\n };\n\n renderSmall = async (widget) => {\n const market = this.dataSource[0] || {};\n\n widget.url = `https:\/\/www.coingecko.com\/zh\/${encodeURIComponent('数字货币')}\/${market.id}`;\n\n const image = await this.renderImage(market.image);\n const backgroundImg = await this.getSmallBg(image);\n widget.backgroundColor = this.backGroundColor;\n widget.backgroundImage = backgroundImg;\n widget.setPadding(12, 12, 12, 12);\n const coin = widget.addText(market.symbol.toUpperCase());\n coin.font = Font.heavySystemFont(24);\n coin.textColor = this.widgetColor;\n\n coin.rightAlignText();\n const name = widget.addText(market.name);\n name.font = Font.systemFont(10);\n name.textColor = Color.gray();\n name.rightAlignText();\n widget.addSpacer();\n\n const trend = widget.addText(\n `${market.price_change_percentage_24h.toFixed(2)}%`\n );\n trend.font = Font.semiboldSystemFont(16);\n trend.textColor =\n market.price_change_percentage_24h >= 0 ? Color.green() : Color.red();\n\n trend.rightAlignText();\n const price = widget.addText(`$ ${market.current_price}`);\n price.font = Font.boldSystemFont(28);\n price.textColor = this.widgetColor;\n price.rightAlignText();\n price.lineLimit = 1;\n price.minimumScaleFactor = 0.1;\n const history = widget.addText(\n `H: ${market.high_24h}, L: ${market.low_24h}`\n );\n history.font = Font.systemFont(10);\n history.textColor = Color.gray();\n history.rightAlignText();\n history.lineLimit = 1;\n history.minimumScaleFactor = 0.1;\n return widget;\n };\n\n rowCell = async (rowStack, market) => {\n rowStack.url = `https:\/\/www.coingecko.com\/zh\/${encodeURIComponent('数字货币')}\/${market.id}`;\n rowStack.layoutHorizontally();\n const image = await this.renderImage(market.image);\n const iconImage = rowStack.addImage(image);\n iconImage.imageSize = new Size(28, 28);\n iconImage.cornerRadius = 14;\n\n rowStack.addSpacer(10);\n\n const centerStack = rowStack.addStack();\n centerStack.layoutVertically();\n\n const topCenterStack = centerStack.addStack();\n topCenterStack.layoutHorizontally();\n\n const titleText = topCenterStack.addText(market.symbol);\n titleText.textColor = this.widgetColor;\n titleText.font = this.provideFont('semibold', 16);\n\n topCenterStack.addSpacer();\n\n const priceText = topCenterStack.addText(`$ ${market.current_price}`);\n priceText.textColor = this.widgetColor;\n priceText.font = this.provideFont('semibold', 15);\n priceText.rightAlignText();\n\n const bottomCenterStack = centerStack.addStack();\n bottomCenterStack.layoutHorizontally();\n\n const subText = bottomCenterStack.addText(market.name);\n subText.textColor = Color.gray();\n subText.font = this.provideFont('semibold', 10);\n\n bottomCenterStack.addSpacer();\n\n const historyText = bottomCenterStack.addText(\n `H: ${market.high_24h}, L: ${market.low_24h}`\n );\n historyText.textColor = Color.gray();\n historyText.font = this.provideFont('semibold', 10);\n historyText.rightAlignText();\n\n rowStack.addSpacer(8);\n\n const rateStack = rowStack.addStack();\n rateStack.size = new Size(72, 28);\n rateStack.centerAlignContent();\n rateStack.cornerRadius = 4;\n rateStack.backgroundColor =\n market.price_change_percentage_24h >= 0 ? Color.green() : Color.red();\n const rateText = rateStack.addText(\n (market.price_change_percentage_24h >= 0 ? '+' : '') +\n market.price_change_percentage_24h.toFixed(2) +\n '%'\n );\n rateText.textColor = new Color('#fff', 0.9);\n rateText.font = this.provideFont('semibold', 14);\n rateText.minimumScaleFactor = 0.01;\n rateText.lineLimit = 1;\n };\n\n renderLarge = async (widget) => {\n widget.setPadding(12, 12, 12, 12);\n const containerStack = widget.addStack();\n containerStack.layoutVertically();\n for (let index = 0; index < this.dataSource.length; index++) {\n const item = this.dataSource[index];\n const rowCellStack = containerStack.addStack();\n await this.rowCell(rowCellStack, item);\n if (index !== this.dataSource.length - 1) containerStack.addSpacer();\n }\n return widget;\n };\n\n renderMedium = async (widget) => {\n widget.setPadding(12, 12, 12, 12);\n const containerStack = widget.addStack();\n containerStack.layoutVertically();\n for (let index = 0; index < this.dataSource.length; index++) {\n if (index > 2) return;\n const item = this.dataSource[index];\n const rowCellStack = containerStack.addStack();\n await this.rowCell(rowCellStack, item);\n if (index !== 2) containerStack.addSpacer();\n }\n return widget;\n };\n\n \/**\n * 渲染函数,函数名固定\n * 可以根据 this.widgetFamily 来判断小组件尺寸,以返回不同大小的内容\n *\/\n async render() {\n await this.init();\n const widget = new ListWidget();\n if (this.widgetFamily === 'small') await this.renderSmall(widget);\n await this.getWidgetBackgroundImage(widget);\n if (this.widgetFamily === 'medium') await this.renderMedium(widget);\n if (this.widgetFamily === 'large') await this.renderLarge(widget);\n return widget;\n }\n}\n\n\/\/ @组件代码结束\nawait Runing(Widget, '', false); \/\/远程开发环境\n\n\/\/version:1.0.0",
"share_sheet_inputs" : [
]
}