mirror of
https://github.com/irislib/iris-messenger.git
synced 2024-10-18 22:23:23 +00:00
fix safari logout, move menu to its own file, fix pm webtorrent
This commit is contained in:
parent
f7566f7da7
commit
7aa1764ffd
@ -1,6 +1,5 @@
|
|||||||
import Component from './BaseComponent';
|
import Component from './BaseComponent';
|
||||||
import { Router } from 'preact-router';
|
import { Router } from 'preact-router';
|
||||||
import { Link } from 'preact-router/match';
|
|
||||||
import {Helmet} from "react-helmet";
|
import {Helmet} from "react-helmet";
|
||||||
|
|
||||||
import Helpers from './Helpers.js';
|
import Helpers from './Helpers.js';
|
||||||
@ -8,7 +7,6 @@ import { html } from 'htm/preact';
|
|||||||
import QRScanner from './QRScanner.js';
|
import QRScanner from './QRScanner.js';
|
||||||
import PeerManager from './PeerManager.js';
|
import PeerManager from './PeerManager.js';
|
||||||
import Session from './Session.js';
|
import Session from './Session.js';
|
||||||
import { translate as t } from './Translation.js';
|
|
||||||
|
|
||||||
import Settings from './views/Settings.js';
|
import Settings from './views/Settings.js';
|
||||||
import LogoutConfirmation from './views/LogoutConfirmation.js';
|
import LogoutConfirmation from './views/LogoutConfirmation.js';
|
||||||
@ -27,14 +25,12 @@ import Explorer from './views/Explorer.js';
|
|||||||
import Contacts from './views/Contacts.js';
|
import Contacts from './views/Contacts.js';
|
||||||
import Torrent from './views/Torrent.js';
|
import Torrent from './views/Torrent.js';
|
||||||
|
|
||||||
|
import Menu from './components/Menu.js';
|
||||||
import VideoCall from './components/VideoCall.js';
|
import VideoCall from './components/VideoCall.js';
|
||||||
import Identicon from './components/Identicon.js';
|
|
||||||
import MediaPlayer from './components/MediaPlayer.js';
|
import MediaPlayer from './components/MediaPlayer.js';
|
||||||
import Footer from './components/Footer.js';
|
import Footer from './components/Footer.js';
|
||||||
import State from './State.js';
|
import State from './State.js';
|
||||||
import Icons from './Icons.js';
|
|
||||||
|
|
||||||
import logo from '../assets/img/icon128.png';
|
|
||||||
import logoType from '../assets/img/iris_logotype.png';
|
import logoType from '../assets/img/iris_logotype.png';
|
||||||
|
|
||||||
import '../css/style.css';
|
import '../css/style.css';
|
||||||
@ -50,63 +46,6 @@ PeerManager.init();
|
|||||||
|
|
||||||
Helpers.checkColorScheme();
|
Helpers.checkColorScheme();
|
||||||
|
|
||||||
const APPLICATIONS = [ // TODO: move editable shortcuts to localState gun
|
|
||||||
{url: '/', text: t('home'), icon: Icons.home},
|
|
||||||
{url: '/media', text: t('media'), icon: Icons.play},
|
|
||||||
{url: '/chat', text: t('messages'), icon: Icons.chat},
|
|
||||||
{url: '/store', text: t('market'), icon: Icons.store},
|
|
||||||
{url: '/contacts', text: t('contacts'), icon: Icons.user},
|
|
||||||
{url: '/settings', text: t('settings'), icon: Icons.settings},
|
|
||||||
{url: '/explorer', text: t('explorer'), icon: Icons.folder},
|
|
||||||
{url: '/about', text: t('about')},
|
|
||||||
];
|
|
||||||
|
|
||||||
class Menu extends Component {
|
|
||||||
componentDidMount() {
|
|
||||||
State.local.get('unseenTotal').on(this.inject());
|
|
||||||
}
|
|
||||||
|
|
||||||
menuLinkClicked() {
|
|
||||||
State.local.get('toggleMenu').put(false);
|
|
||||||
State.local.get('scrollUp').put(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const pub = Session.getPubKey();
|
|
||||||
return html`
|
|
||||||
<div class="application-list">
|
|
||||||
${Helpers.isElectron ? html`<div class="electron-padding"/>` : html`
|
|
||||||
<a href="/" onClick=${() => this.menuLinkClicked()} class="hidden-xs" tabindex="0" class="logo">
|
|
||||||
<img class="hidden-xs" src=${logo} width=40 height=40/>
|
|
||||||
<img src=${logoType} height=23 width=41 />
|
|
||||||
</a>
|
|
||||||
`}
|
|
||||||
<div class="visible-xs-block">
|
|
||||||
<${Link} onClick=${() => this.menuLinkClicked()} activeClassName="active" href="/profile/${pub}">
|
|
||||||
<span class="icon"><${Identicon} str=${pub} width=40/></span>
|
|
||||||
<span class="text" style="font-size: 1.2em;border:0;margin-left: 7px;"><iris-text user="${pub}" path="profile/name" editable="false"/></span>
|
|
||||||
<//>
|
|
||||||
<br/><br/>
|
|
||||||
</div>
|
|
||||||
${APPLICATIONS.map(a => {
|
|
||||||
if (a.url) {
|
|
||||||
return html`
|
|
||||||
<${a.native ? 'a' : Link} onClick=${() => this.menuLinkClicked()} activeClassName="active" href=${a.url}>
|
|
||||||
<span class="icon">
|
|
||||||
${a.text === t('messages') && this.state.unseenTotal ? html`<span class="unseen unseen-total">${this.state.unseenTotal}</span>`: ''}
|
|
||||||
${a.icon || Icons.circle}
|
|
||||||
</span>
|
|
||||||
<span class="text">${a.text}</span>
|
|
||||||
<//>`;
|
|
||||||
}
|
|
||||||
return html`<br/><br/>`;
|
|
||||||
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Main extends Component {
|
class Main extends Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
State.local.get('loggedIn').on(this.inject());
|
State.local.get('loggedIn').on(this.inject());
|
||||||
|
@ -226,8 +226,25 @@ async function createChatLink() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearIndexedDB() {
|
function clearIndexedDB() {
|
||||||
window.indexedDB.deleteDatabase('State.local');
|
return new Promise(resolve => {
|
||||||
window.indexedDB.deleteDatabase('radata');
|
const r1 = window.indexedDB.deleteDatabase('State.local');
|
||||||
|
const r2 = window.indexedDB.deleteDatabase('radata');
|
||||||
|
let r1done;
|
||||||
|
let r2done;
|
||||||
|
const check = () => {
|
||||||
|
r1done && r2done && resolve();
|
||||||
|
}
|
||||||
|
r1.onerror = r2.onerror = e => console.error(e);
|
||||||
|
//r1.onblocked = r2.onblocked = e => console.error('blocked', e);
|
||||||
|
r1.onsuccess = () => {
|
||||||
|
r1done = true;
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
r2.onsuccess = () => {
|
||||||
|
r2done = true;
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMyChatLink() {
|
function getMyChatLink() {
|
||||||
@ -252,7 +269,7 @@ async function logOut() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await clearIndexedDB();
|
clearIndexedDB();
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
route('/');
|
route('/');
|
||||||
location.reload();
|
location.reload();
|
||||||
@ -277,6 +294,8 @@ function init(options = {}) {
|
|||||||
login(JSON.parse(localStorageKey));
|
login(JSON.parse(localStorageKey));
|
||||||
} else if (options.autologin) {
|
} else if (options.autologin) {
|
||||||
loginAsNewUser(name);
|
loginAsNewUser(name);
|
||||||
|
} else {
|
||||||
|
clearIndexedDB();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import { Component } from 'preact';
|
|||||||
import Helpers from '../Helpers.js';
|
import Helpers from '../Helpers.js';
|
||||||
import { html } from 'htm/preact';
|
import { html } from 'htm/preact';
|
||||||
import { translate as t } from '../Translation.js';
|
import { translate as t } from '../Translation.js';
|
||||||
|
import Torrent from './Torrent';
|
||||||
import State from '../State.js';
|
import State from '../State.js';
|
||||||
import Session from '../Session.js';
|
import Session from '../Session.js';
|
||||||
import iris from 'iris-lib';
|
import iris from 'iris-lib';
|
||||||
@ -30,12 +31,12 @@ class ChatMessageForm extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate() {
|
||||||
if (!iris.util.isMobile && this.props.autofocus !== false) {
|
if (!iris.util.isMobile && this.props.autofocus !== false) {
|
||||||
$(this.base).find(".new-msg").focus();
|
$(this.base).find(".new-msg").focus();
|
||||||
}
|
}
|
||||||
if (this.state.torrentId && this.state.torrentId !== prevState.torrentId) {
|
if ($('#attachment-preview:visible').length) {
|
||||||
this.downloadWebtorrent(this.state.torrentId);
|
$('#attachment-preview').append($('#webtorrent'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,30 +70,13 @@ class ChatMessageForm extends Component {
|
|||||||
this.picker.pickerVisible ? this.picker.hidePicker() : this.picker.showPicker(event.target);
|
this.picker.pickerVisible ? this.picker.hidePicker() : this.picker.showPicker(event.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadWebtorrent(torrentId) {
|
|
||||||
function onTorrent(torrent) {
|
|
||||||
// Torrents can contain many files. Let's use the .mp4 file
|
|
||||||
let file = torrent.files.find((file) => {
|
|
||||||
return file.name.endsWith('.mp4')
|
|
||||||
})
|
|
||||||
// Stream the file in the browser
|
|
||||||
file.appendTo('#webtorrent', {autoplay: true, muted: true})
|
|
||||||
}
|
|
||||||
const client = await Helpers.getWebTorrentClient();
|
|
||||||
const existing = client.get(torrentId);
|
|
||||||
if (existing) {
|
|
||||||
onTorrent(existing);
|
|
||||||
} else {
|
|
||||||
client.add(torrentId, onTorrent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMsgTextPaste(event) {
|
onMsgTextPaste(event) {
|
||||||
const pasted = (event.clipboardData || window.clipboardData).getData('text');
|
const pasted = (event.clipboardData || window.clipboardData).getData('text');
|
||||||
const magnetRegex = /^magnet:\?xt=urn:btih:*/;
|
const magnetRegex = /^magnet:\?xt=urn:btih:*/;
|
||||||
if (pasted !== this.state.torrentId && pasted.indexOf('.torrent') > -1 || pasted.match(magnetRegex)) {
|
if (pasted !== this.state.torrentId && pasted.indexOf('.torrent') > -1 || pasted.match(magnetRegex)) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.setState({torrentId: pasted});
|
this.setState({torrentId: pasted});
|
||||||
|
this.openAttachmentsPreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,6 +144,7 @@ class ChatMessageForm extends Component {
|
|||||||
Session.channels[this.props.activeChat].attachments = null;
|
Session.channels[this.props.activeChat].attachments = null;
|
||||||
}
|
}
|
||||||
Helpers.scrollToMessageListBottom();
|
Helpers.scrollToMessageListBottom();
|
||||||
|
this.setState({torrentId:null});
|
||||||
}
|
}
|
||||||
|
|
||||||
async webPush(msg) {
|
async webPush(msg) {
|
||||||
@ -206,7 +191,9 @@ class ChatMessageForm extends Component {
|
|||||||
<input name="attachment-input" type="file" class="hidden attachment-input" accept="image/*" multiple onChange=${() => this.openAttachmentsPreview()}/>
|
<input name="attachment-input" type="file" class="hidden attachment-input" accept="image/*" multiple onChange=${() => this.openAttachmentsPreview()}/>
|
||||||
<input onPaste=${e => this.onMsgTextPaste(e)} onInput=${e => this.onMsgTextInput(e)} class="new-msg" type="text" placeholder="${t('type_a_message')}" autocomplete="off" autocorrect="off" autocapitalize="sentences" spellcheck="off"/>
|
<input onPaste=${e => this.onMsgTextPaste(e)} onInput=${e => this.onMsgTextInput(e)} class="new-msg" type="text" placeholder="${t('type_a_message')}" autocomplete="off" autocorrect="off" autocapitalize="sentences" spellcheck="off"/>
|
||||||
${submitButton}
|
${submitButton}
|
||||||
<div id="webtorrent"></div>
|
<div id="webtorrent">
|
||||||
|
${this.state.torrentId ? html`<${Torrent} preview=${true} torrentId=${this.state.torrentId}/>` : ''}
|
||||||
|
</div>
|
||||||
</form>`;
|
</form>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
68
src/js/components/Menu.js
Normal file
68
src/js/components/Menu.js
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import Component from "../BaseComponent";
|
||||||
|
import State from "../State";
|
||||||
|
import Session from "../Session";
|
||||||
|
import {html} from "htm/preact";
|
||||||
|
import Helpers from "../Helpers";
|
||||||
|
import logo from "../../assets/img/icon128.png";
|
||||||
|
import logoType from "../../assets/img/iris_logotype.png";
|
||||||
|
import {Link} from "preact-router/match";
|
||||||
|
import Identicon from "./Identicon";
|
||||||
|
import {translate as t} from "../Translation";
|
||||||
|
import Icons from "../Icons";
|
||||||
|
|
||||||
|
const APPLICATIONS = [ // TODO: move editable shortcuts to localState gun
|
||||||
|
{url: '/', text: t('home'), icon: Icons.home},
|
||||||
|
{url: '/media', text: t('media'), icon: Icons.play},
|
||||||
|
{url: '/chat', text: t('messages'), icon: Icons.chat},
|
||||||
|
{url: '/store', text: t('market'), icon: Icons.store},
|
||||||
|
{url: '/contacts', text: t('contacts'), icon: Icons.user},
|
||||||
|
{url: '/settings', text: t('settings'), icon: Icons.settings},
|
||||||
|
{url: '/explorer', text: t('explorer'), icon: Icons.folder},
|
||||||
|
{url: '/about', text: t('about')},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default class Menu extends Component {
|
||||||
|
componentDidMount() {
|
||||||
|
State.local.get('unseenTotal').on(this.inject());
|
||||||
|
}
|
||||||
|
|
||||||
|
menuLinkClicked() {
|
||||||
|
State.local.get('toggleMenu').put(false);
|
||||||
|
State.local.get('scrollUp').put(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const pub = Session.getPubKey();
|
||||||
|
return html`
|
||||||
|
<div class="application-list">
|
||||||
|
${Helpers.isElectron ? html`<div class="electron-padding"/>` : html`
|
||||||
|
<a href="/" onClick=${() => this.menuLinkClicked()} class="hidden-xs" tabindex="0" class="logo">
|
||||||
|
<img class="hidden-xs" src=${logo} width=40 height=40/>
|
||||||
|
<img src=${logoType} height=23 width=41 />
|
||||||
|
</a>
|
||||||
|
`}
|
||||||
|
<div class="visible-xs-block">
|
||||||
|
<${Link} onClick=${() => this.menuLinkClicked()} activeClassName="active" href="/profile/${pub}">
|
||||||
|
<span class="icon"><${Identicon} str=${pub} width=40/></span>
|
||||||
|
<span class="text" style="font-size: 1.2em;border:0;margin-left: 7px;"><iris-text user="${pub}" path="profile/name" editable="false"/></span>
|
||||||
|
<//>
|
||||||
|
<br/><br/>
|
||||||
|
</div>
|
||||||
|
${APPLICATIONS.map(a => {
|
||||||
|
if (a.url) {
|
||||||
|
return html`
|
||||||
|
<${a.native ? 'a' : Link} onClick=${() => this.menuLinkClicked()} activeClassName="active" href=${a.url}>
|
||||||
|
<span class="icon">
|
||||||
|
${a.text === t('messages') && this.state.unseenTotal ? html`<span class="unseen unseen-total">${this.state.unseenTotal}</span>`: ''}
|
||||||
|
${a.icon || Icons.circle}
|
||||||
|
</span>
|
||||||
|
<span class="text">${a.text}</span>
|
||||||
|
<//>`;
|
||||||
|
}
|
||||||
|
return html`<br/><br/>`;
|
||||||
|
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
@ -261,9 +261,7 @@ class Chat extends View {
|
|||||||
${this.props.id && this.props.id.length > 20 ? html`
|
${this.props.id && this.props.id.length > 20 ? html`
|
||||||
<div class="main-view" id="message-view" onScroll=${e => this.onMessageViewScroll(e)}>
|
<div class="main-view" id="message-view" onScroll=${e => this.onMessageViewScroll(e)}>
|
||||||
<div id="message-list">
|
<div id="message-list">
|
||||||
<div id="topsentinel"></div>
|
|
||||||
${msgListContent}
|
${msgListContent}
|
||||||
<div id="bottomsentinel"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div id="attachment-preview" class="attachment-preview" style="display:none"></div>
|
<div id="attachment-preview" class="attachment-preview" style="display:none"></div>
|
||||||
</div>` : html`<${NewChat}/>`
|
</div>` : html`<${NewChat}/>`
|
||||||
|
Loading…
Reference in New Issue
Block a user