284 lines
10 KiB
TypeScript
284 lines
10 KiB
TypeScript
/*
|
|
* 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)
|
|
)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
}
|