From 31799ccfb0300b105e1d329c997911827ba21c94 Mon Sep 17 00:00:00 2001 From: V Date: Fri, 23 Jun 2023 17:20:54 +0200 Subject: [PATCH] Add Notification badge --- src/main/about.ts | 4 +-- src/main/appBadge.ts | 50 +++++++++++++++++++++++++++ src/main/firstLaunch.ts | 4 +-- src/main/ipc.ts | 3 ++ src/main/splash.ts | 4 +-- src/preload/VencordDesktopNative.ts | 3 +- src/renderer/appBadge.ts | 43 +++++++++++++++++++++++ src/renderer/components/Settings.tsx | 13 +++++++ src/renderer/index.ts | 1 + src/shared/IpcEvents.ts | 2 ++ src/shared/paths.ts | 2 ++ src/shared/settings.d.ts | 1 + src/updater/main.ts | 4 +-- static/badges/1.ico | Bin 0 -> 15086 bytes static/badges/10.ico | Bin 0 -> 15086 bytes static/badges/11.ico | Bin 0 -> 15086 bytes static/badges/2.ico | Bin 0 -> 15086 bytes static/badges/3.ico | Bin 0 -> 15086 bytes static/badges/4.ico | Bin 0 -> 15086 bytes static/badges/5.ico | Bin 0 -> 15086 bytes static/badges/6.ico | Bin 0 -> 15086 bytes static/badges/7.ico | Bin 0 -> 15086 bytes static/badges/8.ico | Bin 0 -> 15086 bytes static/badges/9.ico | Bin 0 -> 15086 bytes static/{ => views}/about.html | 0 static/{ => views}/first-launch.html | 0 static/{ => views}/splash.html | 0 static/{ => views}/updater.html | 0 28 files changed, 125 insertions(+), 9 deletions(-) create mode 100644 src/main/appBadge.ts create mode 100644 src/renderer/appBadge.ts create mode 100644 static/badges/1.ico create mode 100644 static/badges/10.ico create mode 100644 static/badges/11.ico create mode 100644 static/badges/2.ico create mode 100644 static/badges/3.ico create mode 100644 static/badges/4.ico create mode 100644 static/badges/5.ico create mode 100644 static/badges/6.ico create mode 100644 static/badges/7.ico create mode 100644 static/badges/8.ico create mode 100644 static/badges/9.ico rename static/{ => views}/about.html (100%) rename static/{ => views}/first-launch.html (100%) rename static/{ => views}/splash.html (100%) rename static/{ => views}/updater.html (100%) diff --git a/src/main/about.ts b/src/main/about.ts index a335b85..c15f2b8 100644 --- a/src/main/about.ts +++ b/src/main/about.ts @@ -7,7 +7,7 @@ import { app, BrowserWindow } from "electron"; import { readFileSync } from "fs"; import { join } from "path"; -import { ICON_PATH, STATIC_DIR } from "shared/paths"; +import { ICON_PATH, VIEW_DIR } from "shared/paths"; import { makeLinksOpenExternally } from "./utils/makeLinksOpenExternally"; @@ -20,7 +20,7 @@ export function createAboutWindow() { makeLinksOpenExternally(about); - const html = readFileSync(join(STATIC_DIR, "about.html"), "utf-8").replaceAll("%VERSION%", app.getVersion()); + const html = readFileSync(join(VIEW_DIR, "about.html"), "utf-8").replaceAll("%VERSION%", app.getVersion()); about.loadURL("data:text/html;charset=utf-8," + html); diff --git a/src/main/appBadge.ts b/src/main/appBadge.ts new file mode 100644 index 0000000..2887498 --- /dev/null +++ b/src/main/appBadge.ts @@ -0,0 +1,50 @@ +/* + * SPDX-License-Identifier: GPL-3.0 + * Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience + * Copyright (c) 2023 Vendicated and Vencord contributors + */ + +import { app, NativeImage, nativeImage } from "electron"; +import { join } from "path"; +import { BADGE_DIR } from "shared/paths"; + +const imgCache = new Map(); +function loadBadge(index: number) { + const cached = imgCache.get(index); + if (cached) return cached; + + const img = nativeImage.createFromPath(join(BADGE_DIR, `${index}.ico`)); + imgCache.set(index, img); + + return img; +} + +let lastIndex: null | number = -1; + +export function setBadgeCount(count: number) { + switch (process.platform) { + case "darwin": + case "linux": + if (count === -1) count = 0; + app.setBadgeCount(count); + break; + case "win32": + const [index, description] = getBadgeIndexAndDescription(count); + if (lastIndex === index) break; + + lastIndex = index; + + // circular import shenanigans + const { mainWin } = require("./mainWindow") as typeof import("./mainWindow"); + mainWin.setOverlayIcon(index === null ? null : loadBadge(index), description); + break; + } +} + +function getBadgeIndexAndDescription(count: number): [number | null, string] { + if (count === -1) return [11, "Unread Messages"]; + if (count === 0) return [null, "No Notifications"]; + + const index = Math.max(1, Math.min(count, 10)); + return [index, `${index} Notification`]; +} diff --git a/src/main/firstLaunch.ts b/src/main/firstLaunch.ts index e635fbd..f1b39dd 100644 --- a/src/main/firstLaunch.ts +++ b/src/main/firstLaunch.ts @@ -9,7 +9,7 @@ import { BrowserWindow } from "electron/main"; import { copyFileSync, mkdirSync, readdirSync } from "fs"; import { join } from "path"; import { SplashProps } from "shared/browserWinProperties"; -import { STATIC_DIR } from "shared/paths"; +import { VIEW_DIR } from "shared/paths"; import { autoStart } from "./autoStart"; import { DATA_DIR } from "./constants"; @@ -33,7 +33,7 @@ export function createFirstLaunchTour() { width: 550 }); - win.loadFile(join(STATIC_DIR, "first-launch.html")); + win.loadFile(join(VIEW_DIR, "first-launch.html")); win.webContents.addListener("console-message", (_e, _l, msg) => { if (msg === "cancel") return app.exit(); diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 617cccf..138ad76 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -11,6 +11,7 @@ import { join } from "path"; import { debounce } from "shared/utils/debounce"; import { IpcEvents } from "../shared/IpcEvents"; +import { setBadgeCount } from "./appBadge"; import { autoStart } from "./autoStart"; import { VENCORD_FILES_DIR, VENCORD_QUICKCSS_FILE } from "./constants"; import { mainWin } from "./mainWindow"; @@ -89,6 +90,8 @@ ipcMain.handle(IpcEvents.SELECT_VENCORD_DIR, async () => { return dir; }); +ipcMain.handle(IpcEvents.SET_BADGE_COUNT, (_, count: number) => setBadgeCount(count)); + function readCss() { return readFile(VENCORD_QUICKCSS_FILE, "utf-8").catch(() => ""); } diff --git a/src/main/splash.ts b/src/main/splash.ts index b158a58..728c688 100644 --- a/src/main/splash.ts +++ b/src/main/splash.ts @@ -7,12 +7,12 @@ import { BrowserWindow } from "electron"; import { join } from "path"; import { SplashProps } from "shared/browserWinProperties"; -import { STATIC_DIR } from "shared/paths"; +import { VIEW_DIR } from "shared/paths"; export function createSplashWindow() { const splash = new BrowserWindow(SplashProps); - splash.loadFile(join(STATIC_DIR, "splash.html")); + splash.loadFile(join(VIEW_DIR, "splash.html")); return splash; } diff --git a/src/preload/VencordDesktopNative.ts b/src/preload/VencordDesktopNative.ts index 2e56324..d526fa8 100644 --- a/src/preload/VencordDesktopNative.ts +++ b/src/preload/VencordDesktopNative.ts @@ -13,7 +13,8 @@ import { invoke, sendSync } from "./typedIpcs"; export const VencordDesktopNative = { app: { relaunch: () => invoke(IpcEvents.RELAUNCH), - getVersion: () => sendSync(IpcEvents.GET_VERSION) + getVersion: () => sendSync(IpcEvents.GET_VERSION), + setBadgeCount: (count: number) => invoke(IpcEvents.SET_BADGE_COUNT, count) }, autostart: { isEnabled: () => sendSync(IpcEvents.AUTOSTART_ENABLED), diff --git a/src/renderer/appBadge.ts b/src/renderer/appBadge.ts new file mode 100644 index 0000000..ea40b60 --- /dev/null +++ b/src/renderer/appBadge.ts @@ -0,0 +1,43 @@ +/* + * SPDX-License-Identifier: GPL-3.0 + * Vencord Desktop, a desktop app aiming to give you a snappier Discord Experience + * Copyright (c) 2023 Vendicated and Vencord contributors + */ + +import { filters, waitFor } from "@vencord/types/webpack"; +import { RelationshipStore } from "@vencord/types/webpack/common"; + +import { Settings } from "./settings"; + +let GuildReadStateStore: any; +let NotificationSettingsStore: any; + +export function setBadge() { + if (Settings.store.appBadge === false) return; + + const mentionCount = GuildReadStateStore.getTotalMentionCount(); + const pendingRequests = RelationshipStore.getPendingCount(); + const hasUnread = GuildReadStateStore.hasAnyUnread(); + const disableUnreadBadge = NotificationSettingsStore.getDisableUnreadBadge(); + + let totalCount = mentionCount + pendingRequests; + if (!totalCount && hasUnread && !disableUnreadBadge) totalCount = -1; + + VencordDesktopNative.app.setBadgeCount(totalCount); +} + +let toFind = 3; + +function waitForAndSubscribeToStore(name: string, cb?: (m: any) => void) { + waitFor(filters.byStoreName(name), store => { + cb?.(store); + store.addChangeListener(setBadge); + + toFind--; + if (toFind === 0) setBadge(); + }); +} + +waitForAndSubscribeToStore("GuildReadStateStore", store => (GuildReadStateStore = store)); +waitForAndSubscribeToStore("NotificationSettingsStore", store => (NotificationSettingsStore = store)); +waitForAndSubscribeToStore("RelationshipStore"); diff --git a/src/renderer/components/Settings.tsx b/src/renderer/components/Settings.tsx index 1c43b79..bf915b0 100644 --- a/src/renderer/components/Settings.tsx +++ b/src/renderer/components/Settings.tsx @@ -8,6 +8,7 @@ import "./settings.css"; import { Margins } from "@vencord/types/utils"; import { Button, Forms, Select, Switch, Text, useState } from "@vencord/types/webpack/common"; +import { setBadge } from "renderer/appBadge"; import { useSettings } from "renderer/settings"; export default function SettingsUi() { @@ -72,6 +73,18 @@ export default function SettingsUi() { Start With System + { + Settings.appBadge = v; + if (v) setBadge(); + else VencordDesktopNative.app.setBadgeCount(0); + }} + note="Show mention badge on the app icon" + > + Notification Badge + + {switches.map(([key, text, note, def, predicate]) => ( -f5>cdL7SQx~momL{)1Xjcw6_+7d3RlRz(?dqQzKiHv;|0H(QJW@C^dO7_!;ZbM)Bs|L8 z8B?mxg*by4bJ~bAD^aXUmok|C&$OJ&A2^r45{We;@sLQo(J>Kzg*w{SKm*!Pwpv^q zen%w#AQC+y@j2tSSwF@zXnN>_zEyE7E$trZbmS=_(I@hX-&rh(`F-#Jud+Bg9r-(v zc{sW7A#PB`dKJ^;%-&o}5?N6+DYRKRE56Yjl z{io@F4=wh`zQQ`rX8YN*`!qGie`5am#-FE8$Lj6dZFTeJP~E-zt!(^tVe=#0D>(8xQL-pdtSdB*evP-Og&h-cKeb?XRWub1|7^;^q<8xRE z`MK*aFwAoQ0r|7ue*uHG!%X&{iF|E`neD$59I;PM|NN22Pwt2hIz}N*KCqm>&=&ms zmB>G+_jER3`UQCkq)3;{JjL-z90%3@hkAw0b2n|zZdd+HG`PgMyu-PCL?kwheEJ63 z@D4PfZ5odcf6nCz&gEa6%lGD9(x;9-y6*`eSs`h<-QkZ!a-DPOofB~B6!Vbl;29F5 zjn~SGLeB0okqntbige>#4#68TY_jXNojIe9md%5>Y+lgbgRHuE&Hk8goXd{|a*J?z zzlW?)b3BeK_U}av>m%ywfN`9r-Lv+9?5e&L&($cmKEXFDr{U*bl{w8h;!Hj4_wJ3N zGo)Fn@syX%`B+rf@x6A8422)Dwaof}wW*q&(&H5he~d-07ug-}^`4;ix(b;g@nf9^ zwjv#{CkbKu(D=a**gWu;-ix{P4QYRk|9u{QjE@UTmG;p1wGK`n!rr_JPFJ61@DDD! z#vndlq+^H+n@@W)_~o4({5UsxVe_GD2>&A&etqWi!Zs`Xz?g&I`nx0_tTvh^?2j|` z0mhGf{qY_q|eof#9MwkDzJ$|-f{Q^dp{qI*jiFx$?Zld9WI z_ie&|iq6DUa%s>5Sn=KR{{4}CaIxt7HIHeWIW!yZ!?t$)mZ44K75^d#{}Y9Bc%QZ%{so@x-9G>T literal 0 HcmV?d00001 diff --git a/static/badges/10.ico b/static/badges/10.ico new file mode 100644 index 0000000000000000000000000000000000000000..1e02de381e4694340f25fdb90e603e3ae7974252 GIT binary patch literal 15086 zcmeHOOK4O{6n!$nY~9E#W-)Gr*~sW-*22KRtY$I0dYzakN)Z1V1Y;zS1Pv-;0{)#4 zbo?WVx(FfB7!U)&_(38520!r^5!?4V{qGu1y;t4!s_Xr_Um|gGp;MoC>)u

fWll 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 literal 0 HcmV?d00001 diff --git a/static/badges/2.ico b/static/badges/2.ico new file mode 100644 index 0000000000000000000000000000000000000000..d7b6f4419574b303d7ea6f9adf373d23460d8b28 GIT binary patch literal 15086 zcmeHOOK22H7;aJ6s~6eB9@dMn7g@dRSy))u(;oI#mBd6*qaY|=)TpRqe4wa^4}2Th zMe(91G32mfKp0dsB8o&<6cI6?j$QN0JZky6t2)&^)z#JWNEp|GPSte(@2dLiufHme zGtZgtEL`X~jYH8H$#Z~m=M<$584@gGx4I-{gV(kM~KT~o*ZCwGz4xf22Z6|i_#D> z2YhR_I**p4M++*AoT`h^H~4<;T+yR3GE(F{J+Aj?<3s?evFp@Kbx)a(a|zLb*ji8Jg9j1J9gxQ?*dk_pEu@${yTD{z+b(p^6BY1|MaQG zuU;)l99f6@4|Zr}{75?r8i5?DPNE$oI<%a*^; z8@$VH;4Nh;Lk1f=2%EPKMu)}hb9sIH8^|!2jN>{=QrqL zt*%sjJ7E1heOenosJwLTDe#KgK=?HseCXYY69xY9qi=_5weHEVa%C7s(KW6;tl*I1=T< zhZ@gh8e*{kKB7;qRsNFR_3I^GD)}krRaIkJ__@}bJx;4+AJ)5!rojZy8YyD4>|Gjpt>sG^lMzuNGvFi``o7P`S zUA}oUMwG6*}&N&G4K z3p>nN{4M41$K>qqKO}!y!#@Zg1wT2e*?-|(+xK6R|JPcFvjMYTkf%V3v|r6rENPVE zYqkG3z1o}S?zBDo`qJA4BSU^^|34Sh=4QcBq|O4+}< z_|fzZI0AR64X<{>^z{{gB!rDn%CtEFlibm7J`FYkn(dTPM{D}StON4U$By|q2jm@0 zkByBa4AyDLmZSq>5{Y9|!Zp!; zX^>xgFR2M09uDqcMekBi!%S>pz0iL%_kZ@f}%OtRyfZVp(UNrz}B?TORm z(jYhPJU)M3<=eK!&&T!a8UOMn92=#N|6Pn7WBi7GNE1JA+{l74f%^tHd&PP1rcM4i zFz%pY4S4(3zYn1n+!Iaev*>rr_!&7(tNqKqeFasdR0X(E`AolU_b=!J+x;WX%6>jlM<@Ia_ZP;-rW@jBUBMiellMse?bKyYu`=>VR70cf0QVPSpWzkt^-G^V6svGrHu5u)h%dIPLj0 g@=vB5nvV9jcinZDp_}^4zY&E0i9-2S&$b=@1FWZ3`~Uy| literal 0 HcmV?d00001 diff --git a/static/badges/3.ico b/static/badges/3.ico new file mode 100644 index 0000000000000000000000000000000000000000..43ce7cf299065c0ea4a17f8a7bc9a6a25e431796 GIT binary patch literal 15086 zcmeHOOK25I6m3zMt(##MvlutRY-DsZYhhquR{D@#DFj=8lw?K{2)Zo*!6zNd+!dXx~tROue!VXC;PS6@oMznO(juEg8yYiv-B$i*)HyE+|jGw=YhA-8S2|r>VX^MYCsHv~OQV z(Al&p<<>hgHpqTBx{}|0<;s;@;5Rm=ecyrO!H1rG^&2*%=+UD=N~Ma_-kuZs2(+=H z@K>$kbo6MJdVBNK-8~qGkMVWs&zd##ym4bn$iH@NN&mg_!(LqcW5=@e>Q$aPI|u0P z+X8*~P@tJJhw7cS9{mZMbH}f`+SdDp3pqM*A}j2`OW(FJzbyvsC(z#eUSdB|j}8r2 z4h4-+`;|0?Gk+wFB&A^x4d(|x10OTh<7euHuku3@nf}jhO_Tp|gSWxivK|H+uu$(Yrru-%|NqfIApfLpE{H8sVtRaJZnV^$Yq zL;hQXzib1a-vt_=l~j(ZD*gv!*8K$hB;R0pAGCD&JN*XlTm^VbS#pp;M-Pt9Bl``X zyLK%XYgt{LrCI|dUvCLLOo`HiZEIq@y?Ekz-aJl6j%0=3FBa`JSb}90>G<(1)z$G5 zynqh7qHNN!b2nD-;x;s-sK37;S(d=yV3F?J86eXvmEA+903IqGV9q*o%-i05Ub!+w z4;~DPHGB8&G_6>{Y2iXnO-*Tf_AKwpbMRos#qsdOcBCYe(wXXpbi|rCfg(`p$iGOZ^w=SXm3^UhyP5(7ww^s)2FkNJ)Jz6 z)uC}!!5=8@jc#)?Ay9+FDE4H^%wgxg71zEynxCHa4?r9T@m@_;-AQlvHBJjKLPIlfl? zf9qFe^W2|XpVig;7sgWSO_LupP5uvK))P-Y{RzII4sFo(bIYSc-!%Co)8xBMlfOv1 zb_2)3outF7l5MK1Ge0rLTTPQIa{@{FV$TLTzS3tm~W=ZU&io_lS{iEyec)vZNE}_UNi!Iv4-0R zjN?e^J*X4#F4vaqxhit&C3J&)QAGe@6>q~$3)%bC-r z2|uI9ciXl!b#)Djy>l46eqEqFdopo(RIl8gXWr*@yW;9HZd4_KRY>Ep~dDIm|F%J)R`QNnOYY%2KN3UUI#&%aqq|@BB$wv>(>Wj@l;=w?I%kqfp4i8Q$?xp>lz6)GzkBD`a}cl&DCy zB`NSjzv1o{&b(BBoILJU#hk;2()P&V-h&GE!`W|p+a`L(ou?@H^r=XP4{M#HMDdN1 zA31|4+{ik_nTX}^gYCDqWvRQnG(I|eHufwyichHhIC+mK+_LJLnle7S!W}=HEtjLK zsQLT3{3qnRch4U`;B2}~`9uBZ=Ul(8T*>*S2F}#VksmS!=dFBq_PUAa;{FNFIpfaQ za4*seh+E5%KWd8^ZCUv%^kFpT4dsGt{TS*?Y901K&OT0g ievSN7R1Qr=``fqCb(di@jhB5R2>%lW_*Raz9{vMg^fg%k literal 0 HcmV?d00001 diff --git a/static/badges/4.ico b/static/badges/4.ico new file mode 100644 index 0000000000000000000000000000000000000000..91bd61f30d192284326203fdcf167a65301b8405 GIT binary patch literal 15086 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 G9{vN@K2C1{ literal 0 HcmV?d00001 diff --git a/static/badges/7.ico b/static/badges/7.ico new file mode 100644 index 0000000000000000000000000000000000000000..b50750c267a29ff9a18fe175afd4b0497afa7f29 GIT binary patch literal 15086 zcmeHOOK22H7_MMouerz`_OM=ry~yfi&%(mOp7yY}sw5^V53BCe>p!fm_cu>*B zfXbpEA}VUYRf2~o8Ur2-L083tFVN6EnM~$U%U4}BQ{7!%{g^gk+!S=Gy61ma)n9-8 zRUxE}tRNj7gb=cd^tBW63tFqZ_rE&``Kz6fwQJ@3YC?WnNytxx5TF38P5dQfeLG&AP=R>LcJ*CbtrOqU!jw2tmhw+<@7h}$!lsdDNIy~Z;1&oP?#I5Rhot;KH)gTQi zvybnM8zuhgRV7jmT^FgZ4|ea~0dGA)puWg`gD<(N;Tfs7m`7j zALFHtclKm*MLO5^cfuDhoS+Dt-A>ph1C5=q~XIRGE9~g6g zrPMh#ueK5b^tJd&C6C@UB&Mxb^oB$8K>0wXc)U{467P2cLEsz1D`(u8laU{j?PZ^cS@b9guHArO@UTY{!(x7F6F>m$yI_3 zN$enP9;^3;4G!<_uG3e1Y&Gn#&SnR1tcm`Pq;vG>oLGO$0w?1RC<0{`%#D%PGiZz`OzSe`nKDtMS|fH^DYm<}ImBX+rUt0efNjEqFa5g}Zu z%ecuuNZ*oVe)Bzhych;$Vxr79ZHnZjc@Cw>M`ZXQS+J5w?EciQ4O^k_PKgGNs zFz|=}jKiz{4!akNH4#VMzi*6#>aYg7w+;N^!%eWpZ(FuFA_hdMRBC+3j!+zB#FIQ` z4E$~JiNf>Mr%n|Gf0Qd%=6%1#=rWrJ|E?~FzkBD+MZ}{61Bq>5;-AX?O212&=EWF* zKSFG&zQ@!i`==UzivF%$E`R;ni-qBrdV2hQq~HSen8E&tD}r#b@92Y@Hyi%w*s(!!KMY^6S@2q36Mah59&r@}$f+ZnVm6^gnU_cmMu|-?x?L&ntZER_i!4 z`d{>iZT-QzGc{Ef^uZ(QxpSu^d_zQEMy@~LZ(Dz{-b1gr2Y$)2CR*2D$dEMth|tgW zJvROT|D}$UtW^~yKT{k84c-R=HNX@F)-uc)vUZaKIR)^?&}!7adIX8 z9lY|IKtC>~-GlZ3@2q3Vo2w$X9-zx?}OptM7cj7 z9i66XBj&TokN#1x&D81)L6ygkBkxqC=3^T}h|QakTj3536_n_r;9kkjo%yT>j1~4p z^?|p)NN*D*w_eZ8c)4p;Ffa7qv$i3lMSkp?GSk*^M@AZFASm!l@J~8SmNxcrQS!?@ zUnaUiS&*xJ|K7iz;Y=e4m*IWdBERuoQU)FZ=iE8}diMEqF6&wS9#c>cx!=w#Z&1(P zUWdD`-8284n$sb=V5j0f$m-eumSS^7SFoNM3=PcN1` zdOlo}p0@d$r~lM>-@E6JDV{#fzMk3qXI|@wms9k(Y=n@dBycKrBU?1THQdRbU7-qEzm9~Zx&Khnm}*RJ{H zN>gxWs4*_=vI8z*{EVDt;{D6RhyHPqrlgTS>HY^{x-J0h|N(a<3zuR)>ce)N}%Uo&8ou3Bv sXy{Vdhy8`z#~IJBk$*Ckkb`UTi!32R0MvyZ`_I literal 0 HcmV?d00001 diff --git a/static/badges/8.ico b/static/badges/8.ico new file mode 100644 index 0000000000000000000000000000000000000000..8d0ca36cfb85fb8b2d9841a47947fe2c453d5116 GIT binary patch literal 15086 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 S8ZY-o5dJ3$@a@^zdiW1YaE?s? literal 0 HcmV?d00001 diff --git a/static/badges/9.ico b/static/badges/9.ico new file mode 100644 index 0000000000000000000000000000000000000000..c1537794956ce6a53c42bebe9d413d9aa19652cd GIT binary patch literal 15086 zcmeHONoW;G7;aIRs~4HW9L9?<7a6_GSr{0Y(;Vhj9b=;6iaUvj3y~0a)QGr&BOcUo zjT_<~HKMpHZqbMfZr~of-+OuMKYZ0yFWvpByQ^QGkvRVF(%sd6{agL@_g{Zi45OdX z-xxU1Fbrd`F=2pV{D!;1&hx(m4db5yhB0iIcphRHe+)8=Ukt-Q7ohdye+^^A0N{9m zi27CX$C&*iV^$+$)(yriOZ;%(h<9PUOw;i;q)L`fw=P0o58mX-Hf`J1MTta#_U})7-U%5Sr5?govYlTiO|q%6 zF+t0hCn=vV(7bsG&wKQ7^@p8{@0Tu3QYKTN*RS*R?p>bWD`c>O`d`1ErEAx+oL*Ix zMeXf5I(afvq%U~6`(u1%JMY`p=HR3M+qZdc3pb8We)voA{jz0_{HIT6=-$07efpHA z@#DMS3tX4|xX*dUZ|>X#?c0~8?c2L(;zV2akyp?7!47`^am(YoFYzB~M?u3Qhp%s- z|4JG?nLm<7oU36F_2h>*gBUZy6=xcFtnxw}nf}kXrfL6Vn)dIESxt;tCm6FjL`;NV z;T~;GzyWThY&CLZ>IcT`zZkRH7_;8`{MPTscm_@z`k-&Qa@5om`d3xi!x^(KG1eWw zHTX*$#QaO30a|h8sH(F6WX!r1gP-K z=1M+cSJ+{Am>nEnckw)I&K#TT4>)xy&2yUwTE`Up5yM0KH8mx8-sXpo zAM-qy0z7@1qnR@!=R}8se^`D(Q>WV0-tLSw;PK-ewYFyH#*Hj>b~=6t`0ydm{USn_ z&ba*7u1)cL7dh{V6J9?XGsfb1B>;K#;>F6`+%1!ef2jR;?Q-V5Z5L?Cl2ZCxwxl?J z*aG=^g#Ie~hx*^noeuvX`lnAjbKv>&9M#oDj{gaT{gGD$%H7(qeO6Ffw{Fye*F2)+mD$x4%DO#`~K`U1#`C0$~-@v*kOb_HIs`#T5e=+We za{yeihDs(2JpSf#1-f)8LnB89+fc}*jK3HUo$pV5y-lsHX?pS`$LIWu7dfu~+OgMCBivd{lUm`3Lxa?feTe2s?b0 z{8RE5cKB-fx0J*2$=+XoNdEGQ_#k2w;^Z;K`U`CpUw=vd-|E#{4d{J9odPA&8h4#y zNU0p(s{Oy~RoOcCm$qkhwf!q&iTS2!Z!=B1l`-pqtDgPu+V8=uQghsiE8hL0 zUed$rsSX&&-n6^lF5q3RFFA9S*Vaqu`uWIb?1Rf_6P5!beI=Co-d&gjcBYLvy- z=~zEsxss)I>r%Xa5Qj!EuD#SfAEWL?e2*0)>+2JI{qF|UM6f40dbGYBR5~EG#`!+r z+oYls*0yR@(k;3N-n_}v!iABwt5EuoDa!76FLHv|-&NQcI>6qjzxV+)paTceI&~PO z9{5f}wkREtlZ4q>=bdR=VE?7^0}(Yq8&TB_eCV^ z+2gI#O8lrRa=tM6F+Nc=%6Y$OlT%}s0AJFmr7L-b`4DpRa^%zLBkR->uur7Z&yQo8 ziMc^z;H)pydi&|9p4Y5N(edLMUMqg_BG1o-96FSyMT?Sret-V#)K~!+1H~B+C0#c! z$QU9&)=eIKo#$DzY`S+ZCrzt_M~`xJ=T7%N2>^Q+I`rK*SjPp)FV=h>e0N{fJ@N&_ z_j2IOnX-K7L5TdGb4eC;*|S^;p1+^sIZS@k3{-uTZIH zh?_rS-3Xc8fLM?HW}HL7nOuMDPo)an_oPjAubTNYYMQauFF1SZ&TYZ~=NMM6j@-*G z(Mfmxf-xv({fP4~$OqupL4f>c%9O}62qm&RpgEOc5=Khh?0asDq?Q{EgZXIwhYNdT{|J1KXw=Rjf oSYL>BoO1sf^{22Jnu_-Kw!U?ip)ZY>b0P@;69xEw?QJ{!2cB|KPXGV_ literal 0 HcmV?d00001 diff --git a/static/about.html b/static/views/about.html similarity index 100% rename from static/about.html rename to static/views/about.html diff --git a/static/first-launch.html b/static/views/first-launch.html similarity index 100% rename from static/first-launch.html rename to static/views/first-launch.html diff --git a/static/splash.html b/static/views/splash.html similarity index 100% rename from static/splash.html rename to static/views/splash.html diff --git a/static/updater.html b/static/views/updater.html similarity index 100% rename from static/updater.html rename to static/views/updater.html