Skip to content

Commit b2aed1e

Browse files
committed
AG-37779 Improve mobile view of the extension in popup page
Merge in EXTENSIONS/vpn-extension from feature/AG-37779-1-3 to master Squashed commit of the following: commit 55fedb5 Author: Kurbanali Ruslan <[email protected]> Date: Fri Dec 6 17:59:51 2024 +0500 fixed comment and order of data loading commit 2ab45de Author: Kurbanali Ruslan <[email protected]> Date: Fri Dec 6 17:02:38 2024 +0500 fixed header referral commit 700c2ee Author: Kurbanali Ruslan <[email protected]> Date: Fri Dec 6 16:44:32 2024 +0500 fixed dots loader not centered commit 277de9c Author: Kurbanali Ruslan <[email protected]> Date: Fri Dec 6 16:41:26 2024 +0500 added tablet adaptation commit a0f7ae2 Author: Kurbanali Ruslan <[email protected]> Date: Fri Dec 6 16:09:46 2024 +0500 changed naming of state commit 10ab340 Author: Kurbanali Ruslan <[email protected]> Date: Fri Dec 6 13:51:32 2024 +0500 refactored header commit 7e44aec Author: Kurbanali Ruslan <[email protected]> Date: Fri Dec 6 13:41:31 2024 +0500 fixed locations doesn't appear on android commit f221e33 Author: Kurbanali Ruslan <[email protected]> Date: Fri Dec 6 13:41:04 2024 +0500 fixed mobile view commit 7865f31 Author: Kurbanali Ruslan <[email protected]> Date: Fri Dec 6 11:35:15 2024 +0500 added android detection
1 parent caefb48 commit b2aed1e

File tree

17 files changed

+176
-43
lines changed

17 files changed

+176
-43
lines changed

src/common/prefs.ts

+16
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ interface PrefsInterface {
7171
* @returns Promise that will be fulfilled with `true` if the current OS is MacOS, `false` otherwise.
7272
*/
7373
isMacOS(): Promise<boolean>;
74+
75+
/**
76+
* Checks whether the current OS is Android.
77+
*
78+
* Uses native {@link https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/runtime/getPlatformInfo | runtime.getPlatformInfo()}
79+
* to determine the OS.
80+
*
81+
* @returns Promise that will be fulfilled with `true` if the current OS is Android, `false` otherwise.
82+
*/
83+
isAndroid(): Promise<boolean>;
7484
}
7585

7686
enum BrowserName {
@@ -85,6 +95,7 @@ enum BrowserName {
8595
enum SystemName {
8696
MacOS = 'mac',
8797
Windows = 'win',
98+
Android = 'android',
8899
}
89100

90101
export const Prefs: PrefsInterface = {
@@ -151,4 +162,9 @@ export const Prefs: PrefsInterface = {
151162
const os = await this.getOS();
152163
return os === SystemName.MacOS;
153164
},
165+
166+
async isAndroid(): Promise<boolean> {
167+
const os = await this.getOS();
168+
return os === SystemName.Android;
169+
},
154170
};

src/options/components/App/App.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useContext, useEffect } from 'react';
1+
import React, { useContext, useEffect, useLayoutEffect } from 'react';
22
import { observer } from 'mobx-react';
33
import { HashRouter, Route, Switch } from 'react-router-dom';
44
import Modal from 'react-modal';
@@ -94,7 +94,7 @@ export const App = observer(() => {
9494
* if any modal, sidebar is open. We are adding specifically to body because
9595
* in Apple devices "spring scroll" is not works if we add locking to div elements.
9696
*/
97-
useEffect(() => {
97+
useLayoutEffect(() => {
9898
const BODY_LOCK_CLASS = 'locked';
9999

100100
if (isContentLocked) {

src/popup/components/App/App.tsx

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useContext, useEffect } from 'react';
1+
import React, { useContext, useEffect, useLayoutEffect } from 'react';
22
import { observer } from 'mobx-react';
33
import Modal from 'react-modal';
44
import { CSSTransition } from 'react-transition-group';
@@ -62,6 +62,7 @@ export const App = observer(() => {
6262
isHostPermissionsGranted,
6363
hasDesktopAppForOs,
6464
isLimitedOfferActive,
65+
isAndroidBrowser,
6566
} = settingsStore;
6667

6768
const { authenticated } = authStore;
@@ -157,6 +158,24 @@ export const App = observer(() => {
157158
};
158159
}, []);
159160

161+
/**
162+
* We are adding "android" class to html element
163+
* in order to apply android specific styles.
164+
*/
165+
useLayoutEffect(() => {
166+
const ANDROID_CLASS = 'android';
167+
168+
if (isAndroidBrowser) {
169+
document.documentElement.classList.add(ANDROID_CLASS);
170+
} else {
171+
document.documentElement.classList.remove(ANDROID_CLASS);
172+
}
173+
174+
return () => {
175+
document.documentElement.classList.remove(ANDROID_CLASS);
176+
};
177+
}, [isAndroidBrowser]);
178+
160179
useAppearanceTheme(settingsStore.appearanceTheme);
161180

162181
// show skeleton while data is loading.

src/popup/components/Authentication/auth.pcss

+2-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
position: absolute;
7272
cursor: pointer;
7373
top: 0;
74-
left: 0;
74+
left: 50%;
75+
transform: translateX(-50%);
7576
}
7677
}

src/popup/components/ConnectionsLimitError/popup-error.pcss

+5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
color: var(--gray-base);
1515
text-align: center;
1616

17+
/* TODO: Remove it when popup design will be available in wider screens. */
18+
.android & {
19+
position: absolute;
20+
}
21+
1722
&__close {
1823
top: 16px;
1924
right: 16px;

src/popup/components/Header/Header.tsx

+21-31
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import classnames from 'classnames';
55

66
import { rootStore } from '../../stores';
77
import { popupActions } from '../../actions/popupActions';
8-
import { reactTranslator } from '../../../common/reactTranslator';
8+
import { translator } from '../../../common/translator';
9+
import { Icon } from '../ui/Icon';
910

1011
import './header.pcss';
1112

@@ -18,8 +19,7 @@ export const Header = observer(({ showMenuButton }: { showMenuButton: boolean })
1819
uiStore.openOptionsModal();
1920
};
2021

21-
const handleOpenReferral = async (e: React.MouseEvent<HTMLButtonElement> | React.MouseEvent<HTMLAnchorElement>) => {
22-
e.preventDefault();
22+
const handleOpenReferral = async () => {
2323
await popupActions.openFreeGbsPage();
2424
};
2525

@@ -45,38 +45,28 @@ export const Header = observer(({ showMenuButton }: { showMenuButton: boolean })
4545
<div className="header__logo">
4646
<div className="logo" />
4747
</div>
48-
{shouldShowGiftBtn && (
49-
<div className="header__referral">
48+
<div className="header__actions">
49+
{shouldShowGiftBtn && (
50+
<button className="header__referral" type="button" onClick={handleOpenReferral}>
51+
<span className="button header__referral__button">
52+
<Icon icon="gift" className="icon--button" />
53+
</span>
54+
<span className="header__referral__hint">
55+
{translator.getMessage('referral_get_free_traffic')}
56+
</span>
57+
</button>
58+
)}
59+
{showMenuButton && (
5060
<button
51-
className="button header__referral__button"
61+
className="button header__setting"
5262
type="button"
53-
onClick={handleOpenReferral}
63+
tabIndex={tabIndex}
64+
onClick={handleOpenModal}
5465
>
55-
<svg className="icon icon--button">
56-
<use xlinkHref="#gift" />
57-
</svg>
66+
<Icon icon="bar" className="icon--button icon--popup-menu" />
5867
</button>
59-
<a
60-
className="header__referral__hint"
61-
href="#"
62-
onClick={handleOpenReferral}
63-
>
64-
{reactTranslator.getMessage('referral_get_free_traffic')}
65-
</a>
66-
</div>
67-
)}
68-
{showMenuButton && (
69-
<button
70-
className="button header__setting"
71-
type="button"
72-
tabIndex={tabIndex}
73-
onClick={handleOpenModal}
74-
>
75-
<svg className="icon icon--button icon--popup-menu">
76-
<use xlinkHref="#bar" />
77-
</svg>
78-
</button>
79-
)}
68+
)}
69+
</div>
8070
</div>
8171
);
8272
});

src/popup/components/Header/header.pcss

+23-3
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
padding: 16px;
99
height: var(--header-height);
1010

11+
&__logo {
12+
flex: 1 1 auto;
13+
}
14+
1115
&__setting {
1216
width: 24px;
1317
height: 24px;
@@ -21,12 +25,16 @@
2125
}
2226

2327
&__referral {
24-
position: relative;
25-
left: 30px;
28+
padding: 0;
29+
margin: 0;
30+
background-color: transparent;
31+
border: none;
32+
outline: none;
33+
cursor: pointer;
2634

2735
&__hint {
2836
position: fixed;
29-
right: 47px;
37+
right: 38px;
3038
top: 50px;
3139
max-width: 250px;
3240
display: none;
@@ -39,6 +47,10 @@
3947
cursor: pointer;
4048
text-decoration: none;
4149

50+
/* TODO: Remove it when popup design will be available in wider screens. */
51+
.android & {
52+
position: absolute;
53+
}
4254

4355
&:after {
4456
content: "▲";
@@ -56,6 +68,14 @@
5668
display: block;
5769
}
5870
}
71+
72+
&__actions {
73+
flex-shrink: 0;
74+
display: flex;
75+
align-items: center;
76+
justify-content: flex-end;
77+
column-gap: 16px;
78+
}
5979
}
6080

6181
.logo {

src/popup/components/Locations/endpoints.pcss

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.endpoints {
2-
position: absolute;
2+
position: fixed;
33
left: 0;
44
top: 0;
55
z-index: var(--endpoints-z-index);
@@ -10,6 +10,11 @@
1010
background-color: var(--white);
1111
overflow: hidden;
1212

13+
/* TODO: Remove it when popup design will be available in wider screens. */
14+
.android & {
15+
position: absolute;
16+
}
17+
1318
&__header {
1419
position: relative;
1520
margin: 0 16px 32px;

src/popup/components/PromoNotificationModal/promo-notification-modal.pcss

+6
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
right: 0;
2525
bottom: 0;
2626

27+
/* TODO: Remove it when popup design will be available in wider screens. */
28+
.android & {
29+
position: absolute;
30+
}
31+
2732
&__wrap {
2833
outline: none;
2934
animation: notify-show 0.3s ease-in
@@ -35,6 +40,7 @@
3540
background-color: #E6F6FF;
3641
background-size: cover;
3742
background-repeat: no-repeat;
43+
background-position: bottom center;
3844
}
3945

4046
&__close {

src/popup/components/VpnBlockedError/vpn-blocked-notice.pcss

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
.vpn-blocked-notice {
22
position: absolute;
33
top: 56px;
4-
left: 20px;
4+
left: 50%;
5+
transform: translateX(-50%);
56
height: 40px;
67
width: 280px;
78
background-color: var(--dark13);

src/popup/components/ui/SkeletonEndpoint/SkeletonEndpoint.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import './skeleton-endpoint.pcss';
44

55
export const SkeletonEndpoint = () => {
66
return (
7-
<div className="endpoint endpoint__skeleton">
7+
<div className="endpoint skeleton-endpoint endpoint__skeleton">
88
<div className="skeleton-endpoint__empty skeleton-endpoint__empty-flag" />
99
<div className="skeleton-endpoint__container">
1010
<div className="skeleton-endpoint__empty skeleton-endpoint__empty-title" />

src/popup/components/ui/SkeletonEndpoint/skeleton-endpoint.pcss

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
.skeleton-endpoint {
2+
&.endpoint {
3+
justify-content: flex-start;
4+
}
25

36
&__container {
47
margin-left: 12px;

src/popup/stores/GlobalStore.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,17 @@ export class GlobalStore {
2323
@action
2424
async getDesktopAppData(): Promise<void> {
2525
const { rootStore: { settingsStore } } = this;
26-
settingsStore.setHasDesktopAppForOs();
26+
await settingsStore.setHasDesktopAppForOs();
27+
}
28+
29+
/**
30+
* Checks whether the extension is running on a android browser.
31+
* Sets the result to the settings store.
32+
*/
33+
@action
34+
async getAndroidData(): Promise<void> {
35+
const { rootStore: { settingsStore } } = this;
36+
await settingsStore.setIsAndroidBrowser();
2737
}
2838

2939
@action
@@ -128,6 +138,11 @@ export class GlobalStore {
128138

129139
@action
130140
async init(): Promise<void> {
141+
/**
142+
* Get android data first because our styles depends on it,
143+
* and UI might shift because it was loaded too late.
144+
*/
145+
await this.getAndroidData();
131146
await this.getPopupData(MAX_GET_POPUP_DATA_ATTEMPTS);
132147
await this.getDesktopAppData();
133148
await this.rootStore.authStore.getResendCodeCountdownAndStart();

src/popup/stores/SettingsStore.ts

+13
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ export class SettingsStore {
7272

7373
@observable hasDesktopAppForOs: boolean = false;
7474

75+
@observable isAndroidBrowser: boolean = false;
76+
7577
@observable arePingsRecalculating: boolean = false;
7678

7779
@observable forwarderDomain: string;
@@ -460,6 +462,17 @@ export class SettingsStore {
460462
});
461463
}
462464

465+
/**
466+
* Checks whether the extension is running on a android browser.
467+
* Sets the result to {@link isAndroidBrowser}
468+
*/
469+
@action async setIsAndroidBrowser(): Promise<void> {
470+
const isAndroid = await Prefs.isAndroid();
471+
runInAction(() => {
472+
this.isAndroidBrowser = isAndroid;
473+
});
474+
}
475+
463476
/**
464477
* Sets the {@link arePingsRecalculating} to the specified value.
465478
*

0 commit comments

Comments
 (0)