One weekday evening, near dinner time, I opened the nuggets and found a cute iOS desktop component that could be written in Javascript! 👇 Use Scriptable to create your own iPhone widget

Hello World learned, however, that while writing the components they wanted, they still knew very little about them, and the official documentation was rudimentary. Therefore, I want to share what I understand and gain, so that you can better write your own ideal components by hand.

(It is recommended to go to the above article to understand the usage.)

The container

Containers in Scriptable are equivalent to Html tag elements. Contents to be displayed must be placed in containers to be presented, mainly including the following:

  • ListWidget: The most basic, outermost container, equivalent to<body>
  • WidgetStack: a block equivalent to<div>/<span>
  • WidgetText: Text container
  • WidgetSpacer: Empty line element, elastic scaling
  • WidgetImage: Image container
  • WidgetDate: date container, automatically refreshed (other contents in Scriptable are not refreshed in real time, so date and time contents need to be placed in a special container)

layout

ListWidget

As the base container for the entire component, there are three sizes available:

To determine whether to obtain the config. WidgetFamily

WidgetStack

Create a new one using the addStack() method of the ListWidget. Create a “row” directly from the ListWidget, and then create a “column” row from the ListWidget, as follows:

const widget = new ListWidget()
const row = widget.addStack()  
      
const cell = row.addStack() Copy the code

A small example of a table layout with 8 rows and 10 columns:

const widget = new ListWidget()
widget.spacing = 2  // Make a bit of padding

for (let i=0; i<8; i++) {
    const row = widget.addStack()
    row.spacing = 2  // Make a bit of padding
    for (let j=0; j<10; j++) {
        const cell = row.addStack()
        cell.size = new Size(12.12)
        cell.cornerRadius = 100  // border-radius: 100%
        cell.backgroundColor = new Color(`#ff${i}6${j}6 `)  // Change the color to I and j}}Copy the code

WidgetSpacer

Used to create empty elements such as widget.addspacer (len: number) and row.addspacer (len). When len = 0, it is useful for creating elastic Spaces. For example, we could insert WdigetSpacer in the middle of each row in the table example above:

const widget = new ListWidget()
widget.spacing = 2  // Make a bit of padding

for (let i=0; i<8; i++) {
    const row = widget.addStack()
    row.spacing = 2  // Make a bit of padding
    for (let j=0; j<10; j++) {
        // ...
        if (j === 4) {
            row.addSpacer()
        }
    }
}
Copy the code

Development framework

The debugging process is very low-level and time-consuming if the code is written only on the IDE and then copied and pasted into Scriptable, so here is an interesting widget development framework:

It will connect PC to Scriptable, and then we can write code directly on VSCode. After saving, the code will be automatically synchronized to the mobile phone and run automatically. The specific operation method is clearly written in the author’s document, which is not repeated here.

Briefly say the analysis of its implementation ideas:

  1. Start the Node service on the PC, enter the server address (THE IP address of the PC) on the mobile terminal, and upload the filePOSTBrought the Node
  2. Node end after the save to the local, record the file update time, usechild_process.execOpen VSCode with system commands and open editing
  3. The clientwhile(1)The Node side compares the latest update time of the file with the record time, and sends the file to the client when it is updated
  4. Finally, the client parses, updates the file, and executes

Here’s an interesting point: the client will await the request while(1) :

const _res = await _req.loadString()
Copy the code

The node response to the request is placed in a 1s setTimeout:

setTimeout(() = > {
  // Determine the file time
  const _time = fs.statSync(WIDGET_FILE).mtimeMs
  if (_time === FILE_DATE) {
    res.send("no").end()
    return
  }
  / / synchronize
  res.sendFile(WIDGET_FILE)
  console.log('[+] Sync to phone finished ')
  FILE_DATE = _time
}, 1000)
Copy the code

Therefore, it is through the delayed response of the node side to achieve the effect of controlling the client while throttling.

Deficiencies and Expectations

  • Single layout, unable to get container width and height (impossible to fit different screens)
  • Background not transparent (opacity 0, result is black background)
  • Update frequency cannot be set (can only be set later than default frequency…)
  • Unable to update data-driven view (interface/local storage may be available)

The sample

Finally, click the list component of my website B, and you can directly jump to the corresponding video of the App of Website B: (The upper left corner is a local love-talk panel that is mixed in, and you can swipe your phone to have a look before dating…)

B station component source 👈

Components of other people’s homes 👈