Weekly design meeting #24

This meeting is about the views of cards.

There are two types of views: item-view and view. Each card can have an item-view and a view.

For example

<cards>
  <token>
     <item-view>...</item-view>
     <view>...</view>
  </token>
  <activity>
     <item-view>...</item-view>
     <view>...</view>
  </activity>
  <action>
     <item-view>...</item-view>
     <view>...</view>
  </action>
</cards>

Sunil produced an illustration with two example tokens with different item-views, denoted by ➀ and ➁:

Screenshot_2020-03-27

Observe that ➀ is a typical payment token which only has 1 important value: the amount. ➁ is a bit more complicated since points expire. The expiration date is under highlight. What he didn't illustrate are non-payment-tokens. e.g. a car ownership token might have 1 or 2 keys produced, or is being rented to someone else hence not under the control of the original owner. A crypto-kitty, however, might be pregnant or sick. You can imagine these are going to have a bit different content in the view. You get the idea with a bit of imagination.

Traditionally in TokenScript, a view is programmed with a web-view (or iframe) of HTML, CSS and JavaScript in it (wasm views are on the horizon). The question is whether or not item-view should be done in the same way.

The argument for using HTML/JavaScript/CSS is straightforward - you can reuse existing knowledge, resources (e.g. icon) and perhaps existing code. The argument against it is performance. In Wallet context, where a lot of item-view are in one list, it can be expensive to maintain a lot of web-views. It is clearly impossible to maintain a list of web-views each with its own reactJS components, but it may also be a bad user experience even if we implement a lot of web-views without using reactJS components (that is, the view is regenerated when marked dirty, instead of updated).

Having the implementation dictating the design is a bit tail wagging the dog, but we have to put implementation restraint in mind. There are a few approaches for implementations in the context of mobile wallet:

  1. Just use HTML/JavaScript and see how bad the performance is. Of course, not using reactJS.
  2. Use cached static HTML. Since the item-view are non-intractable, we can limit what JavaScript can do in it. e.g. it may not run setInterval or display an input box. Each view is rendered in a webview, and it's in-memory DOM tree parsed for static HTML.
  3. Use a cached image. I wouldn't recommend this unless with quite a noticeable user experience difference, since 𝑎) static HTML still needs to be generated for the search to work; 𝑏) result isn't responsive (e.g. when a user rotates the screen).
  4. Hardcode ERC20 views with native components, since they are mostly similar, and take either 0 or 1 approach for other views.

The last combined approach needs a bit of elaboration.

Combined approach

Case 1. Standard ERC20 tokens

Let's first assume all ERC20 tokens look like Suni's illustrated ➀, in which case the TokenScript author doesn't need to define an <item-view> in the <token> card.

Therefore, the ERC20 tokens can be rendered in a mobile wallet with native widgets. No cached HTML is needed since we also know what search keys match these tokens (token name, symbol and balance).

This is achieved by having a default ERC20 TokenScript released by tokenscript.org and shipped by user-agents like αWallet. In that default ERC20 TokenScript, the <item-view> is rendered with HTML/JavaScript, to the same look as achieved by the hardcoded native widgets. This retrofit is needed because <item-view> can be used on the web (see Sunil's illustration) and therefore require an HTML/JavaScript-based implementation. It also provides the basis for customisation.

Case 2. ERC20 tokens with customisation

Then, let's look at ERC20 tokoens with customisation, like Suni's illustrated ➁. The TokenScript author takes the default ERC20 TokenScript, modify its <item-view>, in this case adding expiry, and includes it in the TokenScript he releases.

Seeing <item-view> being defined, mobile wallet like αWallet, the wallet renders the <item-view> with a WebView.

Case 3. Non-ERC20 or SmartTokens

Finally, the SmartTokens - like Car Ownership Toke, which Sunil did not illustrate - can have their own <item-view> from scratch.

Advantages

  • The implementation is transparent to the TokenScript authors. TokenScript authors do not need to learn that wallets render default ERC20 tokens hard-coded to look like that they are generated from the default ERC20 TokenScript's <item-view>. They are introduced to <item-view> only when they need to customise it.
  • The implementation does not forbid the authors to use setInterval(). In Sunil's ➁, the TokenScript author might wish to replace the expiry date with something like "Expiring in 1 days" or "Expiring in 1 hours" which depends on setInterval().
  • The implementation doesn't block the furture use of solution 1.

Alternative approaches

One approach is to restrict the <item-view> into a message. A wiki-like style can be implemented to allow expression of fields, values and translation.

My (Weiwu)'s objection is that, first, it's not supportive of web3 use-cases. e.g. One might wish to display a car photo with a certain layout, in the case of car-ownership token. (Observe Car-Next-Door example). Second, it adds one concept TokenScript authors needs to master which doesn't have a reuse case (e.g. in the <view>).

The counter-argument for my object in the meeting was that you can use the message-approach for wallet context and when we properly support web3 context we can use a proper view. My argument against that "migration path" is there is unnecessary baggage to carry to web3. Either web3 engine still have to learn to implement messages in case the author chose that implementation for web3, or the authors have to remember that message implementation isn't possible for web3 context, adding to the number of different views they have to maintain. The increase of "you can, but ...." scenarios hurts adoption.

But there are some merits of this approach, to restrict the <item-view> into a message. One is that it does away the performance issue completely, now and the future. The other advantage is that implementing different tenses ("you are about to receive an either" and "you received an ether") is easier with a message than with view, and that situation rises when you apply <item-view> to activities.

My general feedback on that is 𝑎) that restriction hurts web3 innovations too much; 𝑏) if only used for activites', but not tokens' <item-view>, it has less damage to web3 use-cases, but more special cases ("Yes you can, but ...") for authors. As of the tense problem, there is still might be room to fix that during the design for notifications (another piece of ongoing work).

  1. Just use HTML/JavaScript and see how bad the performance is. Of course, not using reactJS.
  2. Use cached static HTML. Since the item-view are non-intractable, we can limit what JavaScript can do in it. e.g. it may not run setInterval or display an input box. Each view is rendered in a webview, and it's in-memory DOM tree parsed for static HTML.
  3. Use a cached image. I wouldn't recommend this unless with quite a noticeable user experience difference, since 𝑎) static HTML still needs to be generated for the search to work; 𝑏) result isn't responsive (e.g. when a user rotates the screen).
  4. Hardcode ERC20 views with native components, since they are mostly similar, and take either 0 or 1 approach for other views.

For (1) caching static HTML. I figure this wouldn't be different from 0 if the keyword here is caching HTML, because in both cases, the TokenScript author writes the view with HTML and JavaScript and is free to do what they want. But if the emphasis is on static, i.e. restricting what they can do with JavaScript, then it sounds better than (0), but there are least 4 major parts for performance issues:

(A) Getting a webkit webview running, loading HTML into it and for the HTML to be rendered is slow (B) Webkit webviews takes up memory (we should reuse webviews aggressively, but there's implications too) (C) The HTML source itself is complicated or slow. The latter might often be because the images aren't optimized (D) The JavaScript code being executed is slow or simply takes time to run because it is waiting for something. e.g. waiting for a remote call to execute

With (1), since we are caching HTML, even if there is no JavaScript running at all, (A) and (B) will continue to be an issue.

For (2). I actually think this will be significantly better performance-wise. We take a hit (or many hits) to fill the cache, but when it's cached, displaying and scrolling will be smooth and buttery (compare how apps that show your entire photo gallery work with our current token view showing a list of say, 10 token IDs). How we maintain the cache might be tricky and might introduce usability issues (do we blank it out when it's dirty, for example?). Supporting portrait and landscape only needs a dumb approach, generate the 2nd set upon rotation. Alternatively, modify the UI so that when running in landscape, the screen breaks into half, the left half as if it's running with portrait width, the right half showing the selected token. i.e. like how most mail apps show the list of emails and email body with 2 panes. We still don't support landscape use for both mobile platforms, so this might not be a problem.

(3). I think the benefit of (3) really comes when it's not a combination of (0) and (1) (or 2). It only works if the item views are all pre-baked and hardcoded. There is an upgrade path, when we do support HTML/JavaScript, we can just map the pre-baked ones to standard ones we implement in HTML/JavaScript

I feel like (2) (with the content generated by 0 or 1) and (3) are the more viable options among the 4.

And one more thing,

I forgot one point about JSX which could bring it back into the picture. Unlike React, React Native uses JSX to render native components. So instead of using that to generate JavaScript create the DOM, what about using JSX to render it directly? If done well, this should be much more performant than anything dealing with HTML since the React Native guys have proven it with both iOS and Android. It might or might not be a bit more work than the other approaches, but it feels more like working on foundations/frameworks.

I was blindsided earlier because I kept thinking of JSX -> HTML. While Apple prohibits using non-webkit HTML renders, they shouldn't prohibit JSX -> native based on the same guideline.

This approach could potentially work with TokenScript views too, not just item views.