diff options
| -rw-r--r-- | src/wallet.ts | 24 | ||||
| -rw-r--r-- | src/webex/chromeBadge.ts | 37 | ||||
| -rw-r--r-- | src/webex/messages.ts | 4 | ||||
| -rw-r--r-- | src/webex/pages/popup.tsx | 3 | ||||
| -rw-r--r-- | src/webex/wxApi.ts | 4 | ||||
| -rw-r--r-- | src/webex/wxBackend.ts | 20 | 
6 files changed, 91 insertions, 1 deletions
| diff --git a/src/wallet.ts b/src/wallet.ts index 5b658de85..9e8eb3f3e 100644 --- a/src/wallet.ts +++ b/src/wallet.ts @@ -247,6 +247,16 @@ export interface Badge {     * Stop indicating background activity.     */    stopBusy(): void; + +  /** +   * Show the notification in the badge. +   */ +  showNotification(): void; + +  /** +   * Stop showing the notification. +   */ +  clearNotification(): void;  } @@ -982,7 +992,7 @@ export class Wallet {                .put(Stores.purchases, t)                .putAll(Stores.coins, payCoinInfo.map((pci) => pci.updatedCoin))                .finish(); - +    this.badge.showNotification();      this.notifier.notify();    } @@ -1198,7 +1208,11 @@ export class Wallet {              return c;            }            await this.q().mutate(Stores.coins, coin.coinPub, mutateCoin) +          // Show notifications only for accepted tips +          this.badge.showNotification();          } +      } else { +        this.badge.showNotification();        }        this.notifier.notify(); @@ -1720,6 +1734,7 @@ export class Wallet {        console.log("suspending coin", c);        c.suspended = true;        q.put(Stores.coins, c); +      this.badge.showNotification();        this.notifier.notify();      });      await q.finish(); @@ -2673,6 +2688,7 @@ export class Wallet {                .put(Stores.coinsReturns, coinsReturnRecord)                .putAll(Stores.coins, payCoinInfo.map((pci) => pci.updatedCoin))                .finish(); +    this.badge.showNotification();      this.notifier.notify();      this.depositReturnedCoins(coinsReturnRecord); @@ -2835,6 +2851,7 @@ export class Wallet {        this.refresh(perm.coin_pub);      } +    this.badge.showNotification();      this.notifier.notify();    } @@ -2968,6 +2985,7 @@ export class Wallet {      }      await q.finish(); +    this.badge.showNotification();      this.notifier.notify();    } @@ -3047,4 +3065,8 @@ export class Wallet {      // FIXME(#5210) also GC coins    } + +  clearNotification(): void { +    this.badge.clearNotification(); +  }  } diff --git a/src/webex/chromeBadge.ts b/src/webex/chromeBadge.ts index 13add9b3f..3dfe94518 100644 --- a/src/webex/chromeBadge.ts +++ b/src/webex/chromeBadge.ts @@ -63,6 +63,11 @@ export class ChromeBadge implements Badge {    private gapWidth: number = 0;    /** +   * Should we show the notification dot? +   */ +  private hasNotification = false; + +  /**     * Maximum value for our rotationAngle, corresponds to 2 Pi.     */    static rotationAngleMax = 1000; @@ -150,6 +155,21 @@ export class ChromeBadge implements Badge {      // go back to the origin      this.ctx.translate(-this.canvas.width / 2, -this.canvas.height / 2); +    if (this.hasNotification) { +      // We draw a circle with a soft border in the +      // lower right corner. +      const r = 8; +      const cw = this.canvas.width; +      const ch = this.canvas.height; +      this.ctx.beginPath(); +      this.ctx.arc(cw - r, ch - r, r, 0, 2 * Math.PI, false); +      const gradient = this.ctx.createRadialGradient(cw - r, ch - r, r, cw - r, ch - r, 5); +      gradient.addColorStop(0, "rgba(255, 255, 255, 1)"); +      gradient.addColorStop(1, "blue"); +      this.ctx.fillStyle = gradient; +      this.ctx.fill(); +    } +      // Allow running outside the extension for testing      // tslint:disable-next-line:no-string-literal      if (window["chrome"] && window.chrome["browserAction"]) { @@ -211,6 +231,23 @@ export class ChromeBadge implements Badge {      rAF(step);    } +  /** +   * Draw the badge such that it shows the +   * user that something happened (balance changed). +   */ +  showNotification() { +    this.hasNotification = true; +    this.draw(); +  } + +  /** +   * Draw the badge without the notification mark. +   */ +  clearNotification() { +    this.hasNotification = false; +    this.draw(); +  } +    startBusy() {      if (this.isBusy) {        return; diff --git a/src/webex/messages.ts b/src/webex/messages.ts index 7cc6c4259..44c9f166c 100644 --- a/src/webex/messages.ts +++ b/src/webex/messages.ts @@ -208,6 +208,10 @@ export interface MessageMap {      request: types.TipStatusRequest;      response: void;    }; +  "clear-notification": { +    request: { }; +    response: void; +  };  }  /** diff --git a/src/webex/pages/popup.tsx b/src/webex/pages/popup.tsx index 389be3b5c..6d1ff3b2b 100644 --- a/src/webex/pages/popup.tsx +++ b/src/webex/pages/popup.tsx @@ -566,4 +566,7 @@ const el = (  document.addEventListener("DOMContentLoaded", () => {    ReactDOM.render(el, document.getElementById("content")!); +  // Will be used by the backend to detect when the popup gets closed, +  // so we can clear notifications +  chrome.runtime.connect({name: "popup"});  }); diff --git a/src/webex/wxApi.ts b/src/webex/wxApi.ts index 61a45c024..2575eec90 100644 --- a/src/webex/wxApi.ts +++ b/src/webex/wxApi.ts @@ -381,3 +381,7 @@ export function acceptTip(merchantDomain: string, tipId: string): Promise<TipSta  export function processTipResponse(merchantDomain: string, tipId: string, tipResponse: TipResponse): Promise<void> {    return callBackend("process-tip-response", { merchantDomain, tipId, tipResponse });  } + +export function clearNotification(): Promise<void> { +  return callBackend("clear-notification", { }); +} diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts index a7757c68e..a804c73d1 100644 --- a/src/webex/wxBackend.ts +++ b/src/webex/wxBackend.ts @@ -337,6 +337,9 @@ function handleMessage(sender: MessageSender,        const req = GetTipPlanchetsRequest.checked(detail);        return needsWallet().getTipPlanchets(req.merchantDomain, req.tipId, req.amount, req.deadline, req.exchangeUrl, req.nextUrl);      } +    case "clear-notification": { +      return needsWallet().clearNotification(); +    }      default:        // Exhaustiveness check.        // See https://www.typescriptlang.org/docs/handbook/advanced-types.html @@ -698,6 +701,23 @@ export async function wxMain() {    }); + +  // Clear notifications both when the popop opens, +  // as well when it closes. +  chrome.runtime.onConnect.addListener((port) => { +    if (port.name == "popup") { +      if (currentWallet) { +        currentWallet.clearNotification(); +      } +      port.onDisconnect.addListener(() => { +          if (currentWallet) { +            currentWallet.clearNotification(); +          } +      }); +    } +  }); + +    // Handlers for catching HTTP requests    chrome.webRequest.onHeadersReceived.addListener((details) => {      const wallet = currentWallet; | 
