From c78a91ea46b48694a67d6ea34658f57606ef9c5e Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 17 Nov 2020 15:15:11 +0100 Subject: [PATCH 1/5] WIP --- src/clients/Element.ts | 25 +++++++++++++++- src/clients/Fractal.tsx | 1 + src/clients/Nheko.tsx | 1 + src/clients/Weechat.tsx | 1 + src/clients/types.ts | 24 +++++++++++++++ src/components/ClientTile.scss | 3 +- src/components/ClientTile.tsx | 55 +++++++++++++++++++++++++++++++--- 7 files changed, 104 insertions(+), 6 deletions(-) diff --git a/src/clients/Element.ts b/src/clients/Element.ts index 0693ede..369c0e9 100644 --- a/src/clients/Element.ts +++ b/src/clients/Element.ts @@ -20,6 +20,7 @@ import { ClientKind, ClientId, Platform, + StoreDistribution, } from './types'; import { LinkKind } from '../parser/types'; import logo from '../imgs/element.svg'; @@ -31,7 +32,7 @@ export const Element: LinkedClient = { logo: logo, homepage: 'https://element.io', maturity: Maturity.STABLE, - description: 'Fully-featured Matrix client for the Web', + description: 'Cross platfom fully-featured Matrix client', platforms: [Platform.Desktop, Platform.Android, Platform.iOS], experimental: false, clientId: ClientId.Element, @@ -59,6 +60,27 @@ export const Element: LinkedClient = { } }, linkSupport: () => true, + installLinks: [ + new StoreDistribution( + 'App Store', + Platform.iOS, + 'https://apps.apple.com/app/vector/id1083446067', + false + ), + new StoreDistribution( + 'Google Play', + Platform.Android, + 'https://play.google.com/store/apps/details?id=im.vector.app', + true + ), + new StoreDistribution( + 'F-Droid', + Platform.Android, + 'https://f-droid.org/fr/packages/im.vector.app/', + false + ), + // TODO desktop clients? + ], }; export const ElementDevelop: LinkedClient = { @@ -94,4 +116,5 @@ export const ElementDevelop: LinkedClient = { } }, linkSupport: () => true, + installLinks: [], }; diff --git a/src/clients/Fractal.tsx b/src/clients/Fractal.tsx index bd0f068..f9ea9a2 100644 --- a/src/clients/Fractal.tsx +++ b/src/clients/Fractal.tsx @@ -69,6 +69,7 @@ const Fractal: TextClient = { }, description: 'Fractal is a Matrix Client written in Rust', + installLinks: [], }; export default Fractal; diff --git a/src/clients/Nheko.tsx b/src/clients/Nheko.tsx index 1195716..f9201d3 100644 --- a/src/clients/Nheko.tsx +++ b/src/clients/Nheko.tsx @@ -86,6 +86,7 @@ const Nheko: TextClient = { }, description: 'A native desktop app for Matrix that feels more like a mainstream chat app.', + installLinks: [], }; export default Nheko; diff --git a/src/clients/Weechat.tsx b/src/clients/Weechat.tsx index 105a979..805a4b2 100644 --- a/src/clients/Weechat.tsx +++ b/src/clients/Weechat.tsx @@ -86,6 +86,7 @@ const Weechat: TextClient = { }, description: 'Command-line Matrix interface using Weechat', + installLinks: [], }; export default Weechat; diff --git a/src/clients/types.ts b/src/clients/types.ts index 3278f96..8e41546 100644 --- a/src/clients/types.ts +++ b/src/clients/types.ts @@ -53,6 +53,29 @@ export enum ClientId { Fractal = 'fractal', } +/** + * Define a native distribution channel for a client. + * E.g App store for apple, PlayStore or F-Droid for Android + */ +export class StoreDistribution { + public name: string; + public platform: Platform; + public download: string; + public supportReferrer: boolean; + + constructor( + name: string, + platform: Platform, + download: string, + supportReferrer: boolean + ) { + this.name = name; + this.platform = platform; + this.download = download; + this.supportReferrer = supportReferrer; + } +} + /* * The descriptive details of a client */ @@ -67,6 +90,7 @@ export interface ClientDescription { clientId: ClientId; experimental: boolean; linkSupport: (link: SafeLink) => boolean; + installLinks: StoreDistribution[]; } /* diff --git a/src/components/ClientTile.scss b/src/components/ClientTile.scss index 996c56f..6bd4dfb 100644 --- a/src/components/ClientTile.scss +++ b/src/components/ClientTile.scss @@ -51,7 +51,8 @@ limitations under the License. .button { height: 40px; - width: 130px; + min-width: 130px; + max-width: 165px; margin-top: 16px; } } diff --git a/src/components/ClientTile.tsx b/src/components/ClientTile.tsx index e8eddde..7076bc2 100644 --- a/src/components/ClientTile.tsx +++ b/src/components/ClientTile.tsx @@ -14,10 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, { useContext } from 'react'; import classNames from 'classnames'; +import { UAContext } from '@quentin-sommer/react-useragent'; -import { Client, ClientKind } from '../clients/types'; +import { Client, ClientKind, Platform } from '../clients/types'; import { SafeLink } from '../parser/types'; import Tile from './Tile'; import Button from './Button'; @@ -35,13 +36,54 @@ const ClientTile: React.FC = ({ client, link }: IProps) => {

{client.toInviteString(link)}

) : null; + const { uaResults } = useContext(UAContext); + const className = classNames('clientTile', { clientTileLink: client.kind === ClientKind.LINKED_CLIENT, }); let inviteButton: JSX.Element = <>; + let hasNativeClient = false; + let installButton = undefined; if (client.kind === ClientKind.LINKED_CLIENT) { - inviteButton = ; + const availableClients = client.installLinks.filter((distrib) => { + if ((uaResults as any).ios) { + return distrib.platform == Platform.iOS; + } else if ((uaResults as any).android) { + return distrib.platform == Platform.Android; + } else { + return false; + } + }); + hasNativeClient = availableClients.length > 0; + if (hasNativeClient) { + inviteButton = ( + + ); + } else { + inviteButton = ; + } + + installButton = availableClients.map((distrib) => ( + + )); } else { const copyString = client.copyString(link); if (copyString !== '') { @@ -63,13 +105,18 @@ const ClientTile: React.FC = ({ client, link }: IProps) => {

{client.name}

{client.description}

{inviteLine} + {hasNativeClient && installButton} {inviteButton} ); if (client.kind === ClientKind.LINKED_CLIENT) { - clientTile = {clientTile}; + if (!hasNativeClient) { + clientTile = ( + {clientTile} + ); + } } return clientTile; From d484a9a4231983532e77d81f927e25f83ad2c269 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 23 Nov 2020 18:23:23 +0100 Subject: [PATCH 2/5] add app store install badges --- src/clients/Element.ts | 26 +++-------- src/clients/types.ts | 83 ++++++++++++++++++++++++++------- src/components/ClientTile.scss | 9 ++++ src/components/ClientTile.tsx | 77 +++++++++++++++--------------- src/imgs/app-store-us-alt.svg | 7 +++ src/imgs/fdroid-badge.png | Bin 0 -> 27159 bytes src/imgs/google-play-us.svg | 41 ++++++++++++++++ 7 files changed, 168 insertions(+), 75 deletions(-) create mode 100644 src/imgs/app-store-us-alt.svg create mode 100644 src/imgs/fdroid-badge.png create mode 100644 src/imgs/google-play-us.svg diff --git a/src/clients/Element.ts b/src/clients/Element.ts index 369c0e9..2b9fb8d 100644 --- a/src/clients/Element.ts +++ b/src/clients/Element.ts @@ -20,7 +20,9 @@ import { ClientKind, ClientId, Platform, - StoreDistribution, + AppleStoreLink, + PlayStoreLink, + FDroidLink } from './types'; import { LinkKind } from '../parser/types'; import logo from '../imgs/element.svg'; @@ -61,25 +63,9 @@ export const Element: LinkedClient = { }, linkSupport: () => true, installLinks: [ - new StoreDistribution( - 'App Store', - Platform.iOS, - 'https://apps.apple.com/app/vector/id1083446067', - false - ), - new StoreDistribution( - 'Google Play', - Platform.Android, - 'https://play.google.com/store/apps/details?id=im.vector.app', - true - ), - new StoreDistribution( - 'F-Droid', - Platform.Android, - 'https://f-droid.org/fr/packages/im.vector.app/', - false - ), - // TODO desktop clients? + new AppleStoreLink("vector", "id1083446067"), + new PlayStoreLink("im.vector.app"), + new FDroidLink("im.vector.app"), ], }; diff --git a/src/clients/types.ts b/src/clients/types.ts index 8e41546..7a2f8c4 100644 --- a/src/clients/types.ts +++ b/src/clients/types.ts @@ -57,22 +57,73 @@ export enum ClientId { * Define a native distribution channel for a client. * E.g App store for apple, PlayStore or F-Droid for Android */ -export class StoreDistribution { - public name: string; - public platform: Platform; - public download: string; - public supportReferrer: boolean; +export interface InstallLink { + createInstallURL(deepLink: SafeLink) : string; + //get buttonCSSClass(): string; + platform: Platform; + // in AppleStoreLink, we can set the cookie here + // onInstallChosen(deepLink: SafeLink); + channelId: string; + description: string; +} - constructor( - name: string, - platform: Platform, - download: string, - supportReferrer: boolean - ) { - this.name = name; - this.platform = platform; - this.download = download; - this.supportReferrer = supportReferrer; +export class AppleStoreLink implements InstallLink { + constructor(private org: string, private appId: string) {} + + createInstallURL(deepLink: SafeLink) : string { + return `https://apps.apple.com/app/${encodeURIComponent(this.org)}/${encodeURIComponent(this.appId)}`; + } + + get platform() : Platform { + return Platform.iOS; + } + + get channelId(): string { + return "apple-app-store"; + } + + get description() { + return "Download on the App Store"; + } +} + +export class PlayStoreLink implements InstallLink { + constructor(private appId: string) {} + + createInstallURL(deepLink: SafeLink) : string { + return `https://play.google.com/store/apps/details?id=${encodeURIComponent(this.appId)}&referrer=${encodeURIComponent(deepLink.originalLink)}`; + } + + get platform() : Platform { + return Platform.Android; + } + + get channelId(): string { + return "play-store"; + } + + get description() { + return "Get it on Google Play"; + } +} + +export class FDroidLink implements InstallLink { + constructor(private appId: string) {} + + createInstallURL(deepLink: SafeLink) : string { + return `https://f-droid.org/packages/${encodeURIComponent(this.appId)}`; + } + + get platform() : Platform { + return Platform.Android; + } + + get channelId(): string { + return "fdroid"; + } + + get description() { + return "Get it on F-Droid"; } } @@ -90,7 +141,7 @@ export interface ClientDescription { clientId: ClientId; experimental: boolean; linkSupport: (link: SafeLink) => boolean; - installLinks: StoreDistribution[]; + installLinks: InstallLink[]; } /* diff --git a/src/components/ClientTile.scss b/src/components/ClientTile.scss index 6bd4dfb..a697aea 100644 --- a/src/components/ClientTile.scss +++ b/src/components/ClientTile.scss @@ -67,6 +67,15 @@ limitations under the License. &:hover { background-color: $app-background; } + + .installLink { + display: inline-block; + height: 40px; + margin: 8px 16px 8px 0; + img { + height: 100%; + } + } } .clientTileLink { diff --git a/src/components/ClientTile.tsx b/src/components/ClientTile.tsx index 7076bc2..5ec1311 100644 --- a/src/components/ClientTile.tsx +++ b/src/components/ClientTile.tsx @@ -23,6 +23,10 @@ import { SafeLink } from '../parser/types'; import Tile from './Tile'; import Button from './Button'; +import appStoreBadge from '../imgs/app-store-us-alt.svg'; +import playStoreBadge from '../imgs/google-play-us.svg'; +import fdroidBadge from '../imgs/fdroid-badge.png'; + import './ClientTile.scss'; interface IProps { @@ -30,6 +34,16 @@ interface IProps { link: SafeLink; } +interface IInstallBadgeImages { + [index: string]: string; +} + +const installBadgeImages : IInstallBadgeImages = { + "fdroid": fdroidBadge, + "apple-app-store": appStoreBadge, + "play-store": playStoreBadge +}; + const ClientTile: React.FC = ({ client, link }: IProps) => { const inviteLine = client.kind === ClientKind.TEXT_CLIENT ? ( @@ -43,47 +57,32 @@ const ClientTile: React.FC = ({ client, link }: IProps) => { }); let inviteButton: JSX.Element = <>; - let hasNativeClient = false; - let installButton = undefined; - if (client.kind === ClientKind.LINKED_CLIENT) { - const availableClients = client.installLinks.filter((distrib) => { - if ((uaResults as any).ios) { - return distrib.platform == Platform.iOS; - } else if ((uaResults as any).android) { - return distrib.platform == Platform.Android; - } else { - return false; - } - }); - hasNativeClient = availableClients.length > 0; - if (hasNativeClient) { - inviteButton = ( - - ); + const matchingInstallLinks = client.installLinks.filter((installLink) => { + if ((uaResults as any).ios) { + return installLink.platform === Platform.iOS; + } else if ((uaResults as any).android) { + return installLink.platform === Platform.Android; } else { - inviteButton = ; + return false; } + }); + const hasNativeClient = matchingInstallLinks.length > 0; + let installButtons = undefined; + if (matchingInstallLinks.length) { + installButtons =

{matchingInstallLinks.map((installLink) => { + return + {installLink.description} + ; + })}

; + } - installButton = availableClients.map((distrib) => ( - - )); + if (client.kind === ClientKind.LINKED_CLIENT) { + inviteButton = ; } else { const copyString = client.copyString(link); if (copyString !== '') { @@ -104,8 +103,8 @@ const ClientTile: React.FC = ({ client, link }: IProps) => {

{client.name}

{client.description}

+ {installButtons} {inviteLine} - {hasNativeClient && installButton} {inviteButton}
diff --git a/src/imgs/app-store-us-alt.svg b/src/imgs/app-store-us-alt.svg new file mode 100644 index 0000000..83437ba --- /dev/null +++ b/src/imgs/app-store-us-alt.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/imgs/fdroid-badge.png b/src/imgs/fdroid-badge.png new file mode 100644 index 0000000000000000000000000000000000000000..7c8c3c5e57a2462f347f7f2fa117bf8617690f30 GIT binary patch literal 27159 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 Ciu_&x literal 0 HcmV?d00001 diff --git a/src/imgs/google-play-us.svg b/src/imgs/google-play-us.svg new file mode 100644 index 0000000..888691a --- /dev/null +++ b/src/imgs/google-play-us.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From f8c16f520eb481c2c32967a726d50155a0ecb856 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 24 Nov 2020 12:21:39 +0100 Subject: [PATCH 3/5] do copy change in other pr if needed --- src/clients/Element.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/clients/Element.ts b/src/clients/Element.ts index 2b9fb8d..37e3db0 100644 --- a/src/clients/Element.ts +++ b/src/clients/Element.ts @@ -22,7 +22,7 @@ import { Platform, AppleStoreLink, PlayStoreLink, - FDroidLink + FDroidLink, } from './types'; import { LinkKind } from '../parser/types'; import logo from '../imgs/element.svg'; @@ -34,7 +34,7 @@ export const Element: LinkedClient = { logo: logo, homepage: 'https://element.io', maturity: Maturity.STABLE, - description: 'Cross platfom fully-featured Matrix client', + description: 'Fully-featured Matrix client', platforms: [Platform.Desktop, Platform.Android, Platform.iOS], experimental: false, clientId: ClientId.Element, @@ -63,9 +63,9 @@ export const Element: LinkedClient = { }, linkSupport: () => true, installLinks: [ - new AppleStoreLink("vector", "id1083446067"), - new PlayStoreLink("im.vector.app"), - new FDroidLink("im.vector.app"), + new AppleStoreLink('vector', 'id1083446067'), + new PlayStoreLink('im.vector.app'), + new FDroidLink('im.vector.app'), ], }; From 89de7e671d82c9918fdee5ddd0c14169d40125ef Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 24 Nov 2020 12:23:04 +0100 Subject: [PATCH 4/5] remove obsolete ideas --- src/clients/types.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/clients/types.ts b/src/clients/types.ts index 7a2f8c4..9c4c266 100644 --- a/src/clients/types.ts +++ b/src/clients/types.ts @@ -59,10 +59,9 @@ export enum ClientId { */ export interface InstallLink { createInstallURL(deepLink: SafeLink) : string; - //get buttonCSSClass(): string; - platform: Platform; - // in AppleStoreLink, we can set the cookie here + // in AppleStoreLink, we can set the cookie here for deeplinking // onInstallChosen(deepLink: SafeLink); + platform: Platform; channelId: string; description: string; } From e9d14926e34881aae61a8def810a9d4ec9666a14 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 24 Nov 2020 12:29:38 +0100 Subject: [PATCH 5/5] add a11y label to install buttons --- src/components/ClientTile.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ClientTile.tsx b/src/components/ClientTile.tsx index 5ec1311..9464e61 100644 --- a/src/components/ClientTile.tsx +++ b/src/components/ClientTile.tsx @@ -72,6 +72,7 @@ const ClientTile: React.FC = ({ client, link }: IProps) => { installButtons =

{matchingInstallLinks.map((installLink) => { return