Scriptables/Scripts/「源码」人生电量.js

342 lines
9.0 KiB
JavaScript
Raw Permalink Normal View History

2022-06-02 17:00:01 +08:00
// Variables used by Scriptable.
// These must be at the very top of the file. Do not edit.
// icon-color: green; icon-glyph: battery-half;
//
// iOS 桌面组件脚本 @「小件件」
// 开发说明:请从 Widget 类开始编写,注释请勿修改
// https://x.im3x.cn
//
// 添加require是为了vscode中可以正确引入包以获得自动补全等功能
if (typeof require === 'undefined') require = importModule
const { Base } = require("./「小件件」开发环境")
// @组件代码开始
class Widget extends Base {
/**
* 传递给组件的参数可以是桌面 Parameter 数据也可以是外部如 URLScheme 等传递的数据
* @param {string} arg 自定义参数
*/
constructor (arg) {
super(arg)
this.name = '人生电量'
this.desc = '预计一下余生还剩多少电量'
this.logo = 'https://txc.gtimg.com/data/287371/2020/1105/a8d2e9e19644b244b7a2307bdf2609c0.png'
this.registerAction("设置信息", this.actionSettings)
this.registerAction("透明背景", this.actionSettings3)
this.BG_FILE = this.getBackgroundImage()
if (this.BG_FILE) this.registerAction("移除背景", this.actionSettings4)
}
/**
* 渲染函数函数名固定
* 可以根据 this.widgetFamily 来判断小组件尺寸以返回不同大小的内容
*/
async render () {
if (!this.settings || !this.settings['name'] || !this.settings['date'] || !this.settings['gender']) {
return await this.renderConfigure()
}
switch (this.widgetFamily) {
case 'large':
return await this.renderLarge()
case 'medium':
return await this.renderMedium()
default:
return await this.renderSmall()
}
}
/**
* 手工绘制电量图标
* @param {int} num 0-100 电量
*/
async renderBattery (stack, num = 100, size = 'small') {
const SIZES = {
small: {
width: 40,
height: 20,
borderWidth: 3,
cornerRadius: 3,
rightWidth: 2,
rightHeight: 8,
spacer: 3
},
medium: {
width: 80,
height: 40,
borderWidth: 5,
cornerRadius: 10,
rightWidth: 5,
rightHeight: 15,
spacer: 5
},
large: {}
}
const SIZE = SIZES[size]
// 电池颜色
let color = new Color("#CCCCCC", 1)
if (num < 40) color = Color.yellow()
if (num > 80) color = Color.green()
const box = stack.addStack()
box.centerAlignContent()
const boxLeft = box.addStack()
boxLeft.size = new Size(SIZE['width'], SIZE['height'])
boxLeft.borderColor = new Color('#CCCCCC', 0.8)
boxLeft.borderWidth = SIZE['borderWidth']
boxLeft.cornerRadius = SIZE['cornerRadius']
// 中间电量
// 根据电量计算电量矩形的长总长80-边距10
// 算法70/100 * 电量
const BATTERY_WIDTH = parseInt((SIZE['width'] - (SIZE['spacer']*2)) / 100 * num)
boxLeft.addSpacer(SIZE['spacer'])
boxLeft.setPadding(SIZE['spacer'], 0, SIZE['spacer'], 0)
const boxCenter = boxLeft.addStack()
boxCenter.backgroundColor = color
boxCenter.size = new Size(BATTERY_WIDTH, SIZE['height'] - SIZE['spacer']*2)
boxCenter.cornerRadius = SIZE['cornerRadius'] / 2
boxLeft.addSpacer((SIZE['width'] - SIZE['spacer']*2) - BATTERY_WIDTH + SIZE['spacer'])
box.addSpacer(2)
const boxRight = box.addStack()
boxRight.backgroundColor = new Color('#CCCCCC', 0.8)
boxRight.cornerRadius = 5
boxRight.size = new Size(SIZE['rightWidth'], SIZE['rightHeight'])
return box
}
// 提示配置
async renderConfigure () {
const w = new ListWidget()
w.addText("请点击组件进行设置信息")
w.url = this.actionUrl("settings")
return w
}
// 获取电量值
getPricNum () {
// 电量
// 男7578预计寿命
const SM = this.settings['gender'] === '男' ? 75 : 78
// 1. 已经过了多少天
const DAY_TO_NOW = Math.floor((+new Date() - (+new Date(this.settings['date']))) / (24*60*60*1000))
// 2. 百分比
const PRIC_NUM = parseFloat(1-(DAY_TO_NOW / (75*365))).toFixed(2) * 100
return PRIC_NUM
}
/**
* 渲染小尺寸组件
*/
async renderSmall () {
let w = new ListWidget()
// 名称
await this.renderHeader(w, this.logo, this.name, this.BG_FILE ? Color.white() : null)
const PRIC_NUM = this.getPricNum()
const battery = w.addStack()
battery.addSpacer()
await this.renderBattery(battery, PRIC_NUM)
battery.addSpacer()
w.addSpacer(5)
const num = w.addText(` ${PRIC_NUM} %`)
num.centerAlignText()
num.font = Font.systemFont(36)
// 生日
w.addSpacer()
const _date = new DateFormatter()
_date.dateFormat = "yyyy/MM/dd"
const date = w.addText(this.settings['name'] + ' @ ' + _date.string(new Date(this.settings['date'])))
date.font = Font.lightSystemFont(10)
date.textOpacity = 0.8
date.centerAlignText()
if (this.BG_FILE) {
w.backgroundImage = this.BG_FILE
num.textColor = date.textColor = Color.white()
}
w.url = this.actionUrl("settings")
return w
}
/**
* 渲染中尺寸组件
*/
async renderMedium () {
let w = new ListWidget()
await this.renderHeader(w, this.logo, this.name, this.BG_FILE ? Color.white() : null)
w.addSpacer()
const name = w.addText(this.settings['name'])
name.centerAlignText()
name.font = Font.systemFont(14)
name.textOpacity = 0.8
w.addSpacer(10)
const box = w.addStack()
box.centerAlignContent()
box.addSpacer()
// 中间电量
const PRIC_NUM = this.getPricNum()
const num = box.addText(`${PRIC_NUM} %`)
num.font = Font.boldSystemFont(34)
box.addSpacer(10)
await this.renderBattery(box, PRIC_NUM, 'medium')
box.addSpacer()
w.addSpacer()
w.addSpacer(5)
const _date = new DateFormatter()
_date.dateFormat = "yyyy / MM / dd"
const date = w.addText(_date.string(new Date(this.settings['date'])))
date.font = Font.lightSystemFont(12)
date.textOpacity = 0.8
date.rightAlignText()
if (this.BG_FILE) {
w.backgroundImage = this.BG_FILE
name.textColor = num.textColor = date.textColor = Color.white()
}
w.url = this.actionUrl("settings")
return w
}
/**
* 渲染大尺寸组件
*/
async renderLarge () {
return await this.renderMedium()
}
/**
* 获取数据函数函数名可不固定
*/
async getData () {
return false
}
/**
* 自定义注册点击事件 actionUrl 生成一个触发链接点击后会执行下方对应的 action
* @param {string} url 打开的链接
*/
async actionOpenUrl (url) {
Safari.openInApp(url, false)
}
async actionSettings () {
const a = new Alert()
a.title = "设置信息"
a.message = "配置您的信息,以便小组件进行计算展示"
const menus = ['输入名称', '选择生日', '选择性别'];
;[{
name:'name',
text: '输入名称'
}, {
name: 'date',
text: '选择生日'
}, {
name: 'gender',
text: '选择性别'
}].map(item => {
a.addAction((this.settings[item.name] ? '✅ ' : '❌ ') + item.text)
})
a.addCancelAction('取消设置')
const id = await a.presentSheet()
if (id === -1) return
await this['actionSettings' + id]()
}
// 设置名称
async actionSettings0 () {
const a = new Alert()
a.title = "输入名称"
a.message = "请输入小组件显示的用户名称"
a.addTextField("名称", this.settings['name'])
a.addAction("确定")
a.addCancelAction("取消")
const id = await a.presentAlert()
if (id === -1) return await this.actionSettings()
const n = a.textFieldValue(0)
if (!n) return await this.actionSettings0()
this.settings['name'] = n
this.saveSettings()
return await this.actionSettings()
}
// 选择生日
async actionSettings1 () {
const dp = new DatePicker()
if (this.settings['date']) {
dp.initialDate = new Date(this.settings['date'])
}
let date
try {
date = await dp.pickDate()
} catch (e) {
return await this.actionSettings()
}
this.settings['date'] = date
this.saveSettings()
return await this.actionSettings()
}
// 选择性别
async actionSettings2 () {
const a = new Alert()
a.title = "选择性别"
a.message = "性别可用于预计寿命"
const genders = ['男', '女']
genders.map(n => {
a.addAction((this.settings['gender'] === n ? '✅ ' : '') + n)
})
a.addCancelAction('取消选择')
const i = await a.presentSheet()
if (i !== -1) {
this.settings['gender'] = genders[i]
this.saveSettings()
}
return await this.actionSettings()
}
// 透明背景
async actionSettings3 () {
const img = await this.getWidgetScreenShot()
if (!img) return
this.setBackgroundImage(img)
}
// 移除背景
async actionSettings4 () {
this.setBackgroundImage(null)
}
}
// @组件代码结束
const { Testing } = require("./「小件件」开发环境")
await Testing(Widget)