diff --git a/package-lock.json b/package-lock.json
index aca2c729..c1d52c0b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7540,7 +7540,7 @@
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
"integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"anymatch": "~3.1.1",
"braces": "~3.0.2",
@@ -7561,7 +7561,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
"integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
@@ -7574,7 +7574,7 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true,
+ "devOptional": true,
"engines": {
"node": ">=8"
}
@@ -7583,7 +7583,7 @@
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"fill-range": "^7.0.1"
},
@@ -7595,7 +7595,7 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"to-regex-range": "^5.0.1"
},
@@ -7607,7 +7607,6 @@
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
"hasInstallScript": true,
"optional": true,
"os": [
@@ -7621,7 +7620,7 @@
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"is-glob": "^4.0.1"
},
@@ -7633,7 +7632,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"binary-extensions": "^2.0.0"
},
@@ -7645,7 +7644,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
+ "devOptional": true,
"engines": {
"node": ">=0.12.0"
}
@@ -7654,7 +7653,7 @@
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
"integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"picomatch": "^2.2.1"
},
@@ -7666,7 +7665,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
+ "devOptional": true,
"dependencies": {
"is-number": "^7.0.0"
},
@@ -19361,7 +19360,7 @@
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
- "dev": true,
+ "devOptional": true,
"engines": {
"node": ">=8.6"
},
@@ -25658,7 +25657,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz",
"integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==",
- "dev": true,
"optional": true,
"dependencies": {
"chokidar": "^2.1.8"
@@ -25669,7 +25667,6 @@
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
"integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
"deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.",
- "dev": true,
"optional": true,
"dependencies": {
"anymatch": "^2.0.0",
@@ -33044,7 +33041,7 @@
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz",
"integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==",
- "dev": true,
+ "devOptional": true,
"requires": {
"anymatch": "~3.1.1",
"braces": "~3.0.2",
@@ -33060,7 +33057,7 @@
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
"integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
- "dev": true,
+ "devOptional": true,
"requires": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
@@ -33070,13 +33067,13 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
- "dev": true
+ "devOptional": true
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
- "dev": true,
+ "devOptional": true,
"requires": {
"fill-range": "^7.0.1"
}
@@ -33085,7 +33082,7 @@
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
- "dev": true,
+ "devOptional": true,
"requires": {
"to-regex-range": "^5.0.1"
}
@@ -33094,14 +33091,13 @@
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
- "dev": true,
"optional": true
},
"glob-parent": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
- "dev": true,
+ "devOptional": true,
"requires": {
"is-glob": "^4.0.1"
}
@@ -33110,7 +33106,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
+ "devOptional": true,
"requires": {
"binary-extensions": "^2.0.0"
}
@@ -33119,13 +33115,13 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true
+ "devOptional": true
},
"readdirp": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
"integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
- "dev": true,
+ "devOptional": true,
"requires": {
"picomatch": "^2.2.1"
}
@@ -33134,7 +33130,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
+ "devOptional": true,
"requires": {
"is-number": "^7.0.0"
}
@@ -42059,7 +42055,7 @@
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
- "dev": true
+ "devOptional": true
},
"pify": {
"version": "4.0.1",
@@ -46911,7 +46907,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz",
"integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==",
- "dev": true,
"optional": true,
"requires": {
"chokidar": "^2.1.8"
@@ -46921,7 +46916,6 @@
"version": "2.1.8",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
"integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
- "dev": true,
"optional": true,
"requires": {
"anymatch": "^2.0.0",
diff --git a/src/components/inputField.ts b/src/components/inputField.ts
index c85998ad..61a92939 100644
--- a/src/components/inputField.ts
+++ b/src/components/inputField.ts
@@ -101,8 +101,9 @@ export type InputFieldOptions = {
maxLength?: number,
showLengthOn?: number,
plainText?: true,
- animate?: true,
+ animate?: boolean,
required?: boolean,
+ canBeEdited?: boolean,
validate?: () => boolean
};
@@ -132,7 +133,7 @@ class InputField {
options.showLengthOn = Math.min(40, Math.round(options.maxLength / 3));
}
- const {placeholder, maxLength, showLengthOn, name, plainText} = options;
+ const {placeholder, maxLength, showLengthOn, name, plainText, canBeEdited = true} = options;
let label = options.label || options.labelText;
@@ -143,7 +144,7 @@ class InputField {
}
this.container.innerHTML = `
-
+
`;
input = this.container.firstElementChild as HTMLElement;
diff --git a/src/components/peerProfile.ts b/src/components/peerProfile.ts
index 8891bbb6..37bfcbde 100644
--- a/src/components/peerProfile.ts
+++ b/src/components/peerProfile.ts
@@ -47,9 +47,10 @@ export default class PeerProfile {
private username: Row;
private phone: Row;
private notifications: Row;
+ private location: Row;
private cleaned: boolean;
- private setBioTimeout: number;
+ private setMoreDetailsTimeout: number;
private setPeerStatusInterval: number;
private peerId: PeerId;
@@ -64,6 +65,7 @@ export default class PeerProfile {
public init() {
this.init = null;
+
this.element = document.createElement('div');
this.element.classList.add('profile-content');
@@ -122,13 +124,25 @@ export default class PeerProfile {
}
});
+ this.location = new Row({
+ title: ' ',
+ subtitleLangKey: 'ChatLocation',
+ icon: 'location'
+ });
+
this.notifications = new Row({
checkboxField: new CheckboxField({toggle: true}),
titleLangKey: 'Notifications',
icon: 'unmute'
});
- this.section.content.append(this.phone.container, this.username.container, this.bio.container, this.notifications.container);
+ this.section.content.append(
+ this.phone.container,
+ this.username.container,
+ this.location.container,
+ this.bio.container,
+ this.notifications.container
+ );
this.element.append(this.section.container);
@@ -160,7 +174,7 @@ export default class PeerProfile {
rootScope.addEventListener('peer_bio_edit', (peerId) => {
if(peerId === this.peerId) {
- this.setBio(true);
+ this.setMoreDetails(true);
}
});
@@ -197,11 +211,12 @@ export default class PeerProfile {
this.bio.container.style.display = 'none';
this.phone.container.style.display = 'none';
this.username.container.style.display = 'none';
+ this.location.container.style.display = 'none';
this.notifications.container.style.display = '';
this.notifications.checkboxField.checked = true;
- if(this.setBioTimeout) {
- window.clearTimeout(this.setBioTimeout);
- this.setBioTimeout = 0;
+ if(this.setMoreDetailsTimeout) {
+ window.clearTimeout(this.setMoreDetailsTimeout);
+ this.setMoreDetailsTimeout = 0;
}
}
@@ -279,7 +294,7 @@ export default class PeerProfile {
//membersLi.style.display = appPeersManager.isBroadcast(peerId) ? 'none' : '';
} */
- this.setBio();
+ this.setMoreDetails();
replaceContent(this.name, new PeerTitle({
peerId,
@@ -294,10 +309,10 @@ export default class PeerProfile {
this.setPeerStatus(true);
}
- public setBio(override?: true) {
- if(this.setBioTimeout) {
- window.clearTimeout(this.setBioTimeout);
- this.setBioTimeout = 0;
+ public setMoreDetails(override?: true) {
+ if(this.setMoreDetailsTimeout) {
+ window.clearTimeout(this.setMoreDetailsTimeout);
+ this.setMoreDetailsTimeout = 0;
}
const peerId = this.peerId;
@@ -335,13 +350,19 @@ export default class PeerProfile {
setText(RichTextProcessor.wrapRichText(chatFull.about), this.bio);
}
+ // @ts-ignore
+ if(chatFull?.location?._ == 'channelLocation') {
+ // @ts-ignore
+ setText(chatFull.location.address, this.location);
+ }
+
return true;
});
}
promise.then((canSetNext) => {
if(canSetNext) {
- this.setBioTimeout = window.setTimeout(() => this.setBio(true), 60e3);
+ this.setMoreDetailsTimeout = window.setTimeout(() => this.setMoreDetails(true), 60e3);
}
});
}
diff --git a/src/components/sidebarLeft/index.ts b/src/components/sidebarLeft/index.ts
index 6a4cf47c..e5a97be6 100644
--- a/src/components/sidebarLeft/index.ts
+++ b/src/components/sidebarLeft/index.ts
@@ -26,6 +26,7 @@ import AppContactsTab from "./tabs/contacts";
import AppArchivedTab from "./tabs/archivedTab";
import AppAddMembersTab from "./tabs/addMembers";
import { FormatterArguments, i18n_, LangPackKey } from "../../lib/langPack";
+import AppPeopleNearby from "./tabs/peopleNearby";
import { ButtonMenuItemOptions } from "../buttonMenu";
import CheckboxField from "../checkboxField";
import { IS_MOBILE_SAFARI } from "../../environment/userAgent";
@@ -131,6 +132,12 @@ export class AppSidebarLeft extends SidebarSlider {
icon: 'user',
text: 'Contacts',
onClick: onContactsClick
+ }, {
+ icon: 'group',
+ text: 'PeopleNearby',
+ onClick: () => {
+ new AppPeopleNearby(this).open();
+ }
}, {
icon: 'settings',
text: 'Settings',
diff --git a/src/components/sidebarLeft/tabs/generalSettings.ts b/src/components/sidebarLeft/tabs/generalSettings.ts
index fbd4b0f9..97dd657e 100644
--- a/src/components/sidebarLeft/tabs/generalSettings.ts
+++ b/src/components/sidebarLeft/tabs/generalSettings.ts
@@ -135,6 +135,36 @@ export default class AppGeneralSettingsTab extends SliderSuperTabEventable {
container.append(form);
}
+ {
+ const container = section('DistanceUnitsTitle');
+
+ const form = document.createElement('form');
+
+ const name = 'distance-unit';
+ const stateKey = 'settings.distanceUnit';
+
+ const kilometersRow = new Row({
+ radioField: new RadioField({
+ langKey: 'DistanceUnitsKilometers',
+ name,
+ value: 'kilometers',
+ stateKey
+ })
+ });
+
+ const milesRow = new Row({
+ radioField: new RadioField({
+ langKey: 'DistanceUnitsMiles',
+ name,
+ value: 'miles',
+ stateKey
+ })
+ });
+
+ form.append(kilometersRow.container, milesRow.container);
+ container.append(form);
+ }
+
{
const container = section('General.TimeFormat');
diff --git a/src/components/sidebarLeft/tabs/newGroup.ts b/src/components/sidebarLeft/tabs/newGroup.ts
index 1693e406..dd92be92 100644
--- a/src/components/sidebarLeft/tabs/newGroup.ts
+++ b/src/components/sidebarLeft/tabs/newGroup.ts
@@ -12,15 +12,32 @@ import appUsersManager from "../../../lib/appManagers/appUsersManager";
import InputField from "../../inputField";
import { SliderSuperTab } from "../../slider";
import AvatarEdit from "../../avatarEdit";
+import I18n, { i18n } from "../../../lib/langPack";
import ButtonCorner from "../../buttonCorner";
+interface OpenStreetMapInterface {
+ place_id?: number;
+ license?: string;
+ osm_type?: string;
+ osm_id?: number;
+ lat?: string;
+ lon?: string;
+ display_name: string;
+ address?: object;
+ boundingbox?: object;
+}
+
export default class AppNewGroupTab extends SliderSuperTab {
private avatarEdit: AvatarEdit;
private uploadAvatar: () => Promise = null;
private peerIds: PeerId[];
+ private isGeoChat: boolean = false;
private nextBtn: HTMLButtonElement;
private groupNameInputField: InputField;
private list: HTMLUListElement;
+ private groupLocationInputField: InputField;
+ private userLocationCoords: { lat: number, long: number };
+ private userLocationAddress: string;
protected init() {
this.container.classList.add('new-group-container');
@@ -40,11 +57,22 @@ export default class AppNewGroupTab extends SliderSuperTab {
maxLength: 128
});
- inputWrapper.append(this.groupNameInputField.container);
+ this.groupLocationInputField = new InputField({
+ label: 'ChatLocation',
+ name: 'location',
+ canBeEdited: false
+ });
+
+ inputWrapper.append(
+ this.groupNameInputField.container,
+ this.groupLocationInputField.container
+ );
this.groupNameInputField.input.addEventListener('input', () => {
const value = this.groupNameInputField.value;
- this.nextBtn.classList.toggle('is-visible', !!value.length && !this.groupNameInputField.input.classList.contains('error'));
+ let valueCheck = !!value.length && !this.groupNameInputField.input.classList.contains('error');
+ if(this.isGeoChat) valueCheck = valueCheck && !!this.userLocationCoords && !!this.userLocationAddress;
+ this.nextBtn.classList.toggle('is-visible', !!valueCheck);
});
this.nextBtn = ButtonCorner({icon: 'arrow_next'});
@@ -52,17 +80,35 @@ export default class AppNewGroupTab extends SliderSuperTab {
this.nextBtn.addEventListener('click', () => {
const title = this.groupNameInputField.value;
- this.nextBtn.disabled = true;
- appChatsManager.createChat(title, this.peerIds.map(peerId => peerId.toUserId())).then((chatId) => {
- if(this.uploadAvatar) {
- this.uploadAvatar().then((inputFile) => {
- appChatsManager.editPhoto(chatId, inputFile);
- });
- }
-
- appSidebarLeft.removeTabFromHistory(this);
- appSidebarLeft.selectTab(0);
- });
+ if(this.isGeoChat){
+ if(!this.userLocationAddress || !this.userLocationCoords) return;
+ appChatsManager.createGeoChat(title, '', this.userLocationCoords, this.userLocationAddress).then((chatId) => {
+ if(this.uploadAvatar) {
+ this.uploadAvatar().then((inputFile) => {
+ appChatsManager.editPhoto(chatId, inputFile);
+ });
+ }
+
+ if(this.peerIds.length){
+ appChatsManager.inviteToChannel(chatId, this.peerIds);
+ }
+
+ appSidebarLeft.removeTabFromHistory(this);
+ appSidebarLeft.selectTab(0);
+ });
+ }else{
+ this.nextBtn.disabled = true;
+ appChatsManager.createChat(title, this.peerIds.map(peerId => peerId.toUserId())).then((chatId) => {
+ if(this.uploadAvatar) {
+ this.uploadAvatar().then((inputFile) => {
+ appChatsManager.editPhoto(chatId, inputFile);
+ });
+ }
+
+ appSidebarLeft.removeTabFromHistory(this);
+ appSidebarLeft.selectTab(0);
+ });
+ }
});
const chatsSection = new SettingSection({
@@ -86,13 +132,25 @@ export default class AppNewGroupTab extends SliderSuperTab {
this.avatarEdit.clear();
this.uploadAvatar = null;
this.groupNameInputField.value = '';
+ this.groupLocationInputField.container.classList.add('hide');
this.nextBtn.disabled = false;
}
- public open(peerIds: PeerId[]) {
+ public open(peerIds: PeerId[], isGeoChat: boolean = false) {
+ this.isGeoChat = isGeoChat;
this.peerIds = peerIds;
const result = super.open();
result.then(() => {
+
+ if(isGeoChat){
+ this.setTitle('NearbyCreateGroup');
+ this.groupLocationInputField.container.classList.remove('hide');
+ this.groupLocationInputField.setValueSilently(I18n.format('Loading', true));
+ this.startLocating();
+ }else{
+ this.groupLocationInputField.container.classList.add('hide');
+ }
+
this.peerIds.forEach(userId => {
let {dom} = appDialogsManager.addDialogNew({
dialog: userId,
@@ -108,4 +166,35 @@ export default class AppNewGroupTab extends SliderSuperTab {
return result;
}
+
+ private startLocating(){
+ navigator.geolocation.getCurrentPosition((location) => {
+ this.userLocationCoords = {
+ lat: location.coords.latitude,
+ long: location.coords.longitude
+ };
+
+ let uri = "https://nominatim.openstreetmap.org/reverse";
+ uri += "?lat="+location.coords.latitude;
+ uri += "&lon="+location.coords.longitude;
+ uri += "&format=json";
+ uri += "&addressdetails=1";
+ uri += "&accept-language=en";
+ fetch(uri)
+ // @ts-ignore
+ .then((response) => response.json() as OpenStreetMapInterface)
+ .then(
+ (response: OpenStreetMapInterface) => {
+ this.userLocationAddress = response.display_name;
+ this.groupLocationInputField.setValueSilently(response.display_name);
+ }
+ );
+ }, (error) => {
+ if(error instanceof GeolocationPositionError){
+ this.groupLocationInputField.setValueSilently('Location permission denied. Please retry later.');
+ }else{
+ this.groupLocationInputField.setValueSilently('An error has occurred. Please retry later.');
+ }
+ });
+ }
}
diff --git a/src/components/sidebarLeft/tabs/notifications.ts b/src/components/sidebarLeft/tabs/notifications.ts
index 05eb9de6..cd0abfdb 100644
--- a/src/components/sidebarLeft/tabs/notifications.ts
+++ b/src/components/sidebarLeft/tabs/notifications.ts
@@ -39,7 +39,7 @@ export default class AppNotificationsTab extends SliderSuperTabEventable {
});
const previewEnabledRow = new Row({
- checkboxField: new CheckboxField({text: 'Notifications.MessagePreview', checked: true}),
+ checkboxField: new CheckboxField({text: 'MessagePreview', checked: true}),
subtitleLangKey: 'Loading',
});
diff --git a/src/components/sidebarLeft/tabs/peopleNearby.ts b/src/components/sidebarLeft/tabs/peopleNearby.ts
new file mode 100644
index 00000000..80537648
--- /dev/null
+++ b/src/components/sidebarLeft/tabs/peopleNearby.ts
@@ -0,0 +1,283 @@
+/*
+ * https://github.com/morethanwords/tweb
+ * Copyright (C) 2019-2021 Eduard Kuzmenko
+ * https://github.com/morethanwords/tweb/blob/master/LICENSE
+ */
+
+import { SliderSuperTab } from "../../slider";
+import AvatarElement from "../../avatar";
+import ButtonCorner from "../../buttonCorner";
+import { InputUser } from "../../../layer";
+import apiManager from "../../../lib/mtproto/mtprotoworker";
+import appUsersManager from "../../../lib/appManagers/appUsersManager";
+import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
+import appImManager from "../../../lib/appManagers/appImManager";
+import ButtonMenuToggle from "../../buttonMenuToggle";
+import { SearchGroup } from "../../appSearch";
+import Button from "../../button";
+import PeerTitle from "../../peerTitle";
+import lottieLoader from "../../../lib/rlottie/lottieLoader";
+import PopupPeer from "../../popups/peer";
+import AppNewGroupTab from "./newGroup";
+import { toast } from "../../toast";
+import { ButtonMenuItemOptions } from "../../buttonMenu";
+import { cancelEvent } from "../../../helpers/dom/cancelEvent";
+import type { LazyLoadQueueIntersector } from "../../lazyLoadQueue";
+import I18n, { i18n } from "../../../lib/langPack";
+import rootScope from '../../../lib/rootScope';
+
+export default class AppPeopleNearby extends SliderSuperTab {
+ private usersCategory = new SearchGroup(true, 'contacts', true, 'people-nearby-users', false);
+ private groupsCategory = new SearchGroup(true, 'contacts', true, 'people-nearby-groups', false);
+ private latestLocationSaved: { latitude: number, longitude: number, accuracy: number };
+ private isLocationWatched: boolean = false;
+ private errorCategory: HTMLElement;
+ private retryBtn: HTMLButtonElement;
+ private btnOptions: HTMLButtonElement;
+ private menuButtons: (ButtonMenuItemOptions & {verify?: () => boolean})[];
+
+ protected lazyLoadQueue: LazyLoadQueueIntersector;
+
+ protected init() {
+ this.container.classList.add('peoplenearby-container');
+ this.setTitle('PeopleNearby');
+
+ this.menuButtons = [{
+ icon: 'tip',
+ text: 'MakeMyselfVisible',
+ onClick: () => this.startWatching(),
+ verify: () => !this.isLocationWatched
+ },
+ {
+ icon: 'tip',
+ text: 'StopShowingMe',
+ onClick: () => this.stopWatching(),
+ verify: () => this.isLocationWatched
+ },
+ {
+ icon: 'newgroup',
+ text: 'NearbyCreateGroup',
+ onClick: () => {
+ new AppNewGroupTab(this.slider).open([], true);
+ }
+ }];
+
+ this.btnOptions = ButtonMenuToggle({}, 'bottom-left', this.menuButtons, () => this.verifyButtons());
+
+ this.header.append(this.btnOptions);
+
+ const locatingIcon = document.createElement('span');
+ locatingIcon.classList.add('tgico', 'tgico-location');
+
+ const locatingAnimation = document.createElement('div');
+ locatingAnimation.classList.add('locating-animation-container');
+ locatingAnimation.appendChild(locatingIcon);
+
+ for(let i=1; i<=4; i++){
+ let animatingWaves = document.createElement('div');
+ animatingWaves.classList.add('locating-animation-waves', 'wave-'+i);
+ locatingAnimation.appendChild(animatingWaves);
+ }
+
+ this.errorCategory = document.createElement('div');
+ this.errorCategory.classList.add('text', 'hide', 'nearby-error');
+
+ this.retryBtn = ButtonCorner({icon: 'check'});
+
+ const textContainer = document.createElement('div');
+ textContainer.classList.add('text', 'nearby-description');
+ textContainer.appendChild(i18n('PeopleNearbyInfo2'));
+
+ const chatsContainer = document.createElement('div');
+ chatsContainer.classList.add('chatlist-container');
+ chatsContainer.append(this.usersCategory.container);
+ chatsContainer.append(this.groupsCategory.container);
+
+ this.content.append(this.retryBtn);
+ this.scrollable.append(
+ locatingAnimation,
+ textContainer,
+ this.errorCategory,
+ chatsContainer
+ );
+ }
+
+ public onCloseAfterTimeout() {
+ this.usersCategory.clear();
+ this.groupsCategory.clear();
+ }
+
+ private verifyButtons(e?: Event){
+ const isMenuOpen = !!e || !!(this.btnOptions && this.btnOptions.classList.contains('menu-open'));
+ e && cancelEvent(e);
+
+ this.menuButtons.filter(button => button.verify).forEach(button => {
+ button.element.classList.toggle('hide', !button.verify());
+ });
+ }
+
+ private parseDistance(distance: number){
+ if(rootScope.settings.distanceUnit == 'miles'){
+ if(distance > 1609.34) {
+ return i18n('MilesAway', [Math.round(distance / 1609)]);
+ }else{
+ return i18n('FootsAway', [Math.round(distance * 3.281)]);
+ }
+ }else{
+ if(distance >= 1000){
+ return i18n('KMetersAway2', [distance / 1000]);
+ }else{
+ return i18n('MetersAway2', [distance]);
+ }
+ }
+ }
+
+ // @ts-ignore
+ public open() {
+ const result = super.open();
+ result.then(() => {
+ this.retryBtn.classList.remove('is-visible');
+ navigator.geolocation.getCurrentPosition((location) => {
+ this.latestLocationSaved = {
+ latitude: location.coords.latitude,
+ longitude: location.coords.longitude,
+ accuracy: location.coords.accuracy
+ };
+
+ console.log(this.latestLocationSaved);
+
+ appUsersManager.getLocated(
+ location.coords.latitude,
+ location.coords.longitude,
+ location.coords.accuracy
+ ).then((response) => {
+
+ // @ts-ignore
+ const orderedPeers = response?.updates[0]?.peers.sort((a, b) => a.distance-b.distance);
+ // @ts-ignore
+ const groupsCounter = response?.updates[0]?.peers.filter((e) => e.peer._ == 'peerChannel').length;
+ // @ts-ignore
+ const usersCounter = response?.updates[0]?.peers.filter((e) => e.peer._ != 'peerChannel').length;
+ // @ts-ignore
+ orderedPeers?.forEach(peer => {
+ const isChannel = peer.peer._ == 'peerChannel';
+ const peerId = (isChannel ? -peer.peer.channel_id : peer.peer.user_id);
+
+ let {dialog, dom} = appDialogsManager.addDialogNew({
+ dialog: peerId,
+ container: (isChannel ? this.groupsCategory : this.usersCategory).list,
+ drawStatus: false,
+ rippleEnabled: true,
+ meAsSaved: true,
+ avatarSize: 48,
+ lazyLoadQueue: this.lazyLoadQueue
+ });
+
+ dom.lastMessageSpan.append(this.parseDistance(peer.distance));
+ dom.containerEl.onclick = () => appImManager.setPeer(peerId);
+
+ if(isChannel){
+ let participantsCount = 0;
+ // @ts-ignore
+ for(let chat of response.chats){
+ if(chat.id == peer.peer.channel_id){
+ participantsCount = chat.participants_count;
+ break;
+ }
+ }
+ dom.lastMessageSpan.append(', ', i18n('Members', [participantsCount]));
+ }
+ });
+
+ this.usersCategory.nameEl.textContent = '';
+ this.usersCategory.nameEl.append(i18n('PeopleNearbyHeader'));
+ usersCounter && this.usersCategory.setActive();
+
+ this.groupsCategory.nameEl.textContent = '';
+ this.groupsCategory.nameEl.append(i18n('ChatsNearbyHeader'));
+ groupsCounter && this.groupsCategory.setActive();
+
+ this.errorCategory.classList.toggle('hide', (usersCounter || groupsCounter));
+ this.errorCategory.innerHTML = "No groups or channels found around you.";
+ });
+ }, (error) => {
+ this.errorCategory.classList.remove('hide');
+ this.retryBtn.classList.add('is-visible');
+ this.retryBtn.addEventListener('click', this.open);
+ if(error instanceof GeolocationPositionError){
+ this.errorCategory.innerHTML = "Location permission denied. Click below to retry.";
+ }else{
+ this.errorCategory.innerHTML = "An error has occurred. Please retry later clicking the button below.";
+ }
+ });
+ });
+ }
+
+ private startWatching(){
+ if(!this.latestLocationSaved || this.isLocationWatched) return;
+ this.isLocationWatched = true;
+
+ toast('Your position is now being shared. Do not close the page or it will be suspended.');
+
+ appUsersManager.getLocated(
+ this.latestLocationSaved.latitude,
+ this.latestLocationSaved.longitude,
+ this.latestLocationSaved.accuracy,
+ true, // background parameter
+ 0x7fffffff // self_expires parameter
+ );
+
+ navigator.geolocation.watchPosition(
+ (result) => {
+ const isLongitudeDifferent = result.coords.longitude != this.latestLocationSaved.longitude;
+ const isLatitudeDifferent = result.coords.latitude != this.latestLocationSaved.latitude;
+ const distanceCheck = this.calculateDistance(
+ result.coords.latitude, result.coords.longitude,
+ this.latestLocationSaved.latitude, this.latestLocationSaved.longitude
+ ) > 100;
+ if((isLatitudeDifferent || isLongitudeDifferent) && distanceCheck){
+ appUsersManager.getLocated(
+ result.coords.latitude,
+ result.coords.longitude,
+ result.coords.accuracy,
+ true, // background parameter
+ 0x7fffffff // self_expires parameter
+ );
+ this.latestLocationSaved = {
+ latitude: result.coords.latitude,
+ longitude: result.coords.longitude,
+ accuracy: result.coords.accuracy
+ }
+ }
+ }
+ );
+ }
+
+ private stopWatching(){
+ if(!this.isLocationWatched) return;
+ this.isLocationWatched = false;
+ toast('The sharing of your position has been stopped. You will no longer be visible to other users.');
+ appUsersManager.getLocated(
+ 0, // latitude parameter
+ 0, // longitude parameter
+ 0, // accuracy parameter
+ false, // background parameter
+ 0 // self_expires parameter
+ );
+ }
+
+ private calculateDistance(lat1: number, long1: number, lat2: number, long2: number){
+ const p = 0.017453292519943295; // Math.PI/180
+ return (
+ 12742 * Math.asin(
+ Math.sqrt(
+ (0.5 - Math.cos((lat2-lat1) * p)) +
+ (
+ Math.cos(lat1 * p) * Math.cos(lat2 * p)
+ * (1 - Math.cos((long2 - long1) * p)/2)
+ )
+ )
+ )
+ );
+ }
+}
diff --git a/src/lang.ts b/src/lang.ts
index ed57c46e..159f1017 100644
--- a/src/lang.ts
+++ b/src/lang.ts
@@ -1,4 +1,22 @@
const lang = {
+ "DistanceUnitsTitle":"Distance units",
+ "DistanceUnitsKilometers":"Kilometers",
+ "DistanceUnitsMiles":"Miles",
+ "PeopleNearby":"PeopleNearby",
+ "MakeMyselfVisible":"Make myself visible",
+ "StopShowingMe":"Stop showing me",
+ "PeopleNearbyInfo2":"Exchange contact info with people nearby and find new friends.",
+ "NearbyCreateGroup":"Create a Local group",
+ "GrantPermissions":"Grant me permissions",
+ "AwayTo":"%1$s away",
+ "MessagePreview":"Message Preview",
+ "KMetersAway2":"%1$s km away",
+ "MetersAway2":"%1$s m away",
+ "MilesAway":"%1$s mi away",
+ "FootsAway":"%1$s ft away",
+ "PeopleNearbyHeader":"People nearby",
+ "ChatsNearbyHeader":"Groups nearby",
+ "ChatLocation":"Location",
"Animations": "Animations",
"AttachAlbum": "Album",
"Appearance.Color.Hex": "HEX",
@@ -73,7 +91,6 @@ const lang = {
"ChatBackground.UploadWallpaper": "Upload Wallpaper",
"ChatBackground.Blur": "Blur Wallpaper Image",
"Notifications.Sound": "Notification Sound",
- "Notifications.MessagePreview": "Message preview",
"NewPrivateChat": "New Private Chat",
"NewPoll.OptionLabel": "Option %d",
"Message.Context.Selection.Copy": "Copy selected",
@@ -400,6 +417,7 @@ const lang = {
"MegaPrivateInfo": "Private groups can only be joined if you were invited or have an invite link.",
"ChannelPrivateLinkHelp": "People can join your channel by following this link. You can revoke the link any time.",
"MegaPrivateLinkHelp": "People can join your group by following this link. You can revoke the link any time.",
+ "ChannelGeoGroupLocation":"Group location",
"RevokeButton": "Revoke",
"RevokeLink": "Revoke Link",
"RevokeAlert": "Are you sure you want to revoke this link? Once the link is revoked, no one will be able to join using it.",
diff --git a/src/lib/appManagers/appChatsManager.ts b/src/lib/appManagers/appChatsManager.ts
index 5f944424..2a189d49 100644
--- a/src/lib/appManagers/appChatsManager.ts
+++ b/src/lib/appManagers/appChatsManager.ts
@@ -11,7 +11,7 @@
import DEBUG, { MOUNT_CLASS_TO } from "../../config/debug";
import { isObject, safeReplaceObject, copy, deepEqual } from "../../helpers/object";
-import { ChannelParticipant, Chat, ChatAdminRights, ChatBannedRights, ChatParticipant, ChatPhoto, InputChannel, InputChatPhoto, InputFile, InputPeer, Update, Updates } from "../../layer";
+import { InputGeoPoint, ChannelParticipant, Chat, ChatAdminRights, ChatBannedRights, ChatParticipant, ChatPhoto, InputChannel, InputChatPhoto, InputFile, InputPeer, Update, Updates } from "../../layer";
import apiManagerProxy from "../mtproto/mtprotoworker";
import apiManager from '../mtproto/mtprotoworker';
import { RichTextProcessor } from "../richtextprocessor";
@@ -502,6 +502,31 @@ export class AppChatsManager {
});
}
+ public createGeoChat(title: string, about: string, gpoint: {
+ lat: number,
+ long: number
+ }, address: string): Promise {
+ let geo_point = {
+ _: 'inputGeoPoint',
+ lat: gpoint['lat'],
+ long: gpoint['long']
+ } as InputGeoPoint;
+ return apiManager.invokeApi('channels.createChannel', {
+ megagroup: true,
+ title,
+ about,
+ geo_point,
+ address
+ }).then((updates) => {
+ apiUpdatesManager.processUpdateMessage(updates);
+
+ const channelId = (updates as any).chats[0].id;
+ rootScope.dispatchEvent('history_focus', {peerId: channelId.toPeerId(true)});
+
+ return channelId;
+ });
+ }
+
public inviteToChannel(id: ChatId, userIds: UserId[]) {
const input = this.getChannelInput(id);
const usersInputs = userIds.map(u => appUsersManager.getUserInput(u));
diff --git a/src/lib/appManagers/appStateManager.ts b/src/lib/appManagers/appStateManager.ts
index 6fd5870a..110758e8 100644
--- a/src/lib/appManagers/appStateManager.ts
+++ b/src/lib/appManagers/appStateManager.ts
@@ -70,6 +70,7 @@ export type State = {
hiddenPinnedMessages: {[peerId: PeerId]: number},
settings: {
messagesTextSize: number,
+ distanceUnit: 'kilometers' | 'miles',
sendShortcut: 'enter' | 'ctrlEnter',
animationsEnabled: boolean,
autoDownload: {
@@ -123,6 +124,7 @@ export const STATE_INIT: State = {
hiddenPinnedMessages: {},
settings: {
messagesTextSize: 16,
+ distanceUnit: 'kilometers',
sendShortcut: 'enter',
animationsEnabled: true,
autoDownload: {
diff --git a/src/lib/appManagers/appUsersManager.ts b/src/lib/appManagers/appUsersManager.ts
index d56864e0..1500e14e 100644
--- a/src/lib/appManagers/appUsersManager.ts
+++ b/src/lib/appManagers/appUsersManager.ts
@@ -17,7 +17,7 @@ import cleanUsername from "../../helpers/cleanUsername";
import { formatFullSentTimeRaw, tsNow } from "../../helpers/date";
import { formatPhoneNumber } from "../../helpers/formatPhoneNumber";
import { safeReplaceObject, isObject } from "../../helpers/object";
-import { Chat, InputContact, InputMedia, InputPeer, InputUser, User as MTUser, UserProfilePhoto, UserStatus } from "../../layer";
+import { Chat, InputContact, InputMedia, InputPeer, InputUser, User as MTUser, UserProfilePhoto, UserStatus, InputGeoPoint } from "../../layer";
import I18n, { i18n, LangPackKey } from "../langPack";
//import apiManager from '../mtproto/apiManager';
import apiManager from '../mtproto/mtprotoworker';
@@ -862,6 +862,32 @@ export class AppUsersManager {
});
}
+ public getLocated(
+ lat: number, long: number,
+ accuracy_radius: number,
+ background: boolean = false,
+ self_expires: number = 0
+ ) {
+ const _globalThis = this;
+ const geo_point = {
+ _: 'inputGeoPoint',
+ lat,
+ long,
+ accuracy_radius
+ } as InputGeoPoint;
+
+ return apiManager.invokeApi(
+ 'contacts.getLocated',
+ {geo_point, background}
+ ).then((result) => {
+ // @ts-ignore
+ appUsersManager.saveApiUsers(result.users);
+ // @ts-ignore
+ appChatsManager.saveApiChats(result.chats);
+ return result;
+ });
+ }
+
/* public searchContacts(query: string, limit = 20) {
return Promise.all([
this.getContacts(query),
diff --git a/src/lib/mtproto/schema.ts b/src/lib/mtproto/schema.ts
index ba2cde56..2adc2752 100644
--- a/src/lib/mtproto/schema.ts
+++ b/src/lib/mtproto/schema.ts
@@ -36,4 +36,4 @@ export default {"MTProto":{"constructors":[{"id":481674261,"predicate":"vector",
constructorsIndex?: {[id: number]: number}
},
layer: number,
-};
+};
\ No newline at end of file
diff --git a/src/lib/mtproto/tl_utils.ts b/src/lib/mtproto/tl_utils.ts
index 69bba4a1..3d948b5b 100644
--- a/src/lib/mtproto/tl_utils.ts
+++ b/src/lib/mtproto/tl_utils.ts
@@ -829,4 +829,4 @@ class TLDeserialization {
MOUNT_CLASS_TO.TLDeserialization = TLDeserialization;
MOUNT_CLASS_TO.TLSerialization = TLSerialization;
-export { TLDeserialization, TLSerialization };
+export { TLDeserialization, TLSerialization };
\ No newline at end of file
diff --git a/src/scripts/out/langPack.strings b/src/scripts/out/langPack.strings
index 4e528933..f6ec248b 100644
--- a/src/scripts/out/langPack.strings
+++ b/src/scripts/out/langPack.strings
@@ -1,3 +1,6 @@
+"GrantPermissions" = "Grant permissions";
+"NewGeoGroup" = "New GeoGroup";
+"ChannelGeoGroupLocation" = "Group location";
"Animations" = "Animations";
"AttachAlbum" = "Album";
"BlockModal.Search.Placeholder" = "Block user...";
diff --git a/src/scss/partials/_chat.scss b/src/scss/partials/_chat.scss
index de2b9108..ad448a37 100644
--- a/src/scss/partials/_chat.scss
+++ b/src/scss/partials/_chat.scss
@@ -1493,4 +1493,4 @@ $background-transition-total-time: #{$input-transition-time - $background-transi
margin-bottom: 1rem;
}
}
-}
+}
\ No newline at end of file
diff --git a/src/scss/partials/_peopleNearby.scss b/src/scss/partials/_peopleNearby.scss
new file mode 100644
index 00000000..609d33a2
--- /dev/null
+++ b/src/scss/partials/_peopleNearby.scss
@@ -0,0 +1,81 @@
+.peoplenearby-container {
+ div.text.nearby-description {
+ margin-top: 15px;
+ text-align: center;
+ color: var(--primary-text-color);
+ }
+
+ div.text.nearby-error {
+ color: var(--gc-secondary-text-color);
+ margin-top: 10px;
+ text-align: center;
+ }
+
+ .locating-animation-container {
+ min-height: 140px;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ & .tgico.tgico-location {
+ padding: 50px;
+ background: var(--avatar-color-bottom);
+ width: 140px;
+ height: 140px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 50%;
+
+ &::before {
+ font-size: 58px;
+ color: white;
+ }
+ }
+
+ & .locating-animation-waves {
+ position: fixed;
+
+ &.wave-1,
+ &.wave-3 {
+ animation: 3s waves-animation infinite;
+ width: 50px;
+ height: 50px;
+ border: 5px solid white;
+ border-radius: 50%;
+ clip-path: polygon(72% 0, 100% 0, 100% 100%, 72% 100%);
+ margin-left: 36px;
+ }
+
+ &.wave-2,
+ &.wave-4 {
+ animation: 5s waves-animation infinite;
+ width: 66px;
+ height: 71px;
+ border: 5px solid white;
+ border-radius: 50%;
+ clip-path: polygon(72% 0, 100% 0, 100% 100%, 72% 100%);
+ margin-left: 51px;
+ margin-top: 1px;
+ animation-delay: 2s;
+ }
+
+ &.wave-3 {
+ margin-left: -36px !important;
+ transform: rotateY(180deg);
+ }
+
+ &.wave-4 {
+ margin-left: -51px !important;
+ transform: rotateY(180deg);
+ }
+ }
+ }
+
+ @keyframes waves-animation {
+ from { opacity: 100%; }
+ 50% { opacity: 0%; }
+ to { opacity: 100%; }
+ }
+}
\ No newline at end of file
diff --git a/src/scss/style.scss b/src/scss/style.scss
index f5c074b0..45c8b8d7 100644
--- a/src/scss/style.scss
+++ b/src/scss/style.scss
@@ -299,6 +299,7 @@ $chat-input-inner-padding-handhelds: .25rem;
@import "partials/row";
@import "partials/colorPicker";
@import "partials/replyKeyboard";
+@import "partials/peopleNearby";
@import "partials/popups/popup";
@import "partials/popups/editAvatar";