@@ -49,7 +77,7 @@ const SharingModal = ({
Copy Link
Invite with a link copied to your clipboard.
-
+
+
+
+
+ QR Code
+
+
+ {showQRCode && }
diff --git a/src/index.js b/src/index.js
index fb6e375..e3e1b99 100644
--- a/src/index.js
+++ b/src/index.js
@@ -8,6 +8,7 @@ import rootReducer from './store/reducers';
import rootEpic from './store/epics';
import 'bootstrap/dist/css/bootstrap.css';
+import './utils/vh_fix';
import './static/sass/main.scss';
import './static/fonts/Lato.ttf';
import './static/audio/notification_gertz.wav';
diff --git a/src/static/sass/_layout.scss b/src/static/sass/_layout.scss
index 0f302d2..4d8007b 100644
--- a/src/static/sass/_layout.scss
+++ b/src/static/sass/_layout.scss
@@ -1,3 +1,14 @@
+html, body {
+ /* iOS viewport bug fix (bottom of screen covered by control bar) */
+ /* CSS var `--vh` set in JS; see `src/utils/vh_fix.js` */
+ min-height: 100vh;
+ min-height: fill-available;
+ min-height: calc(var(--vh, 1vh) * 100);
+ height: 100vh;
+ height: fill-available;
+ height: calc(var(--vh, 1vh) * 100);
+}
+
html, body, ul {
padding: 0;
margin: 0; }
@@ -14,7 +25,7 @@ body {
display: flex;
flex-direction: row;
max-width: 100vw;
- max-height: 100vh;
+ max-height: calc(var(--vh, 1vh) * 100);
}
}
@@ -23,14 +34,8 @@ body {
#page {
display: flex;
flex-direction: column;
- max-height: 100vh;
- min-height: 100vh;
- header {
- flex: 1;
- }
- main {
- flex: 1;
- }
+ max-height: calc(var(--vh, 1vh) * 100);
+ min-height: calc(var(--vh, 1vh) * 100);
}
}
@@ -81,7 +86,8 @@ header {
}
.invite-users {
- margin-top: 15px;
+ height: 100%;
+ margin-top: 48px;
button {
color: white;
@@ -91,6 +97,38 @@ header {
}
}
+ $light-purple: #aa6fe3;
+
+ .room-list {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ margin-top: 48px;
+
+ ul {
+ li {
+ width: 100%;
+ color: white;
+ cursor: pointer;
+ font-size: 1.2em;
+
+ &:hover {
+ text-decoration: underline;
+ }
+
+ &.current-room {
+ color: $light-purple;
+ cursor: default;
+ font-weight: bold;
+
+ &:hover {
+ text-decoration: none;
+ }
+ }
+ }
+ }
+ }
+
.logo-container {
display: flex;
justify-content: space-between;
@@ -114,7 +152,7 @@ header {
max-width: 306px;
flex-direction: column;
justify-content: start;
- height: 100vh;
+ height: calc(var(--vh, 1vh) * 100);
.logo-container {
margin-bottom: 15px;
@@ -174,6 +212,12 @@ header {
color: $funky-purple;
}
+.modal-content {
+ .qr-code {
+ margin-top: 20px;
+ }
+}
+
// Sharing overlay - desktop settings
@media (min-width: 768px) {
.share-copy-link {
@@ -184,12 +228,21 @@ header {
}
// Sharing overlay - mobile settings
-@media (max-width: 768px) {
+@media (max-width: 999px) {
.share-copy-link {
.current-href {
width: 100%;
+ border-radius: 7px !important;
margin-bottom: 5px;
}
+ .icon-button {
+ display: flex;
+ flex-direction: row;
+ justify-content: center;
+ align-items: center;
+ border-radius: 7px !important;
+ width: 100%;
+ }
}
}
@@ -248,7 +301,12 @@ main {
// for now, message box is viewport height
// less display height of message form
// + display height of header
- height: calc(100vh - 120px);
+ //
+ // 157px is a magic number -- and one that works well on 2 desktop
+ // browsers, the Android native app (Capacitor), and the Android
+ // emulator. We need to explicitly set the heights set more heights
+ // of things to avoid the magic number, methinks. --@elimisteve
+ height: calc(var(--vh, 1vh) * 100 - 157px - var(--androidTopBar, 0));
overflow-y: scroll;
padding-top: 5px;
@@ -321,7 +379,7 @@ main {
.search-results {
height: auto;
- max-height: calc(50vh);
+ max-height: calc(var(--vh, 1vh) * 50);
padding-right: 10px;
}
@@ -333,7 +391,7 @@ main {
flex: 1;
flex-direction: row;
justify-content: start;
- height: 100vh;
+ height: calc(var(--vh, 1vh) * 100);
width: 50vw !important;
.content {
@@ -342,7 +400,7 @@ main {
// scroll with flexbox needs revisiting
// for now, message box is viewport height
// less display height of message form
- height: calc(100vh - 70px);
+ height: calc(var(--vh, 1vh) * 100 - 70px);
box-shadow: inset 2px 2px 2px #aaa;
}
}
diff --git a/src/store/epics/chatEpics.js b/src/store/epics/chatEpics.js
index e79216d..9f8277c 100644
--- a/src/store/epics/chatEpics.js
+++ b/src/store/epics/chatEpics.js
@@ -28,8 +28,14 @@ import {
import ChatHandler from './helpers/ChatHandler';
import { combineEpics } from 'redux-observable';
import createDetectVisibilityObservable from './helpers/createDetectPageVisibilityObservable';
+import { Capacitor } from '@capacitor/core';
+
+let wsUrl = `${window.location.origin.replace('http', 'ws')}/api/ws/messages/all`;
+if (Capacitor.isNativePlatform()) {
+ // wsUrl = 'wss://www.leapchat.org/api/ws/messages/all'
+ wsUrl = 'ws://10.0.2.2:8080/api/ws/messages/all';
+}
-const wsUrl = `${window.location.origin.replace('http', 'ws')}/api/ws/messages/all`;
export const chatHandler = new ChatHandler(wsUrl);
import { Observable } from 'rxjs/Observable';
@@ -137,7 +143,6 @@ const ownUserStatusEpic = (action$, store) =>
.map(() => userStatusSent())
)
.catch(error => {
- console.error(error);
return Observable.of(alertWarning('Error sending user status.'));
});
diff --git a/src/utils/sessions.js b/src/utils/sessions.js
index f6fb821..4169d70 100644
--- a/src/utils/sessions.js
+++ b/src/utils/sessions.js
@@ -1,19 +1,46 @@
import { getEmail, getPassphrase } from '../utils/encrypter';
import miniLock from '../utils/miniLock';
+import { Capacitor } from '@capacitor/core';
+import { CapacitorHttp } from '@capacitor/core';
// TODO: will be different host from a mobile device, probably if (!window)
-const authUrl = `${window.location.origin}/api/login`;
+let authUrl = `${window.location.origin}/api/login`;
+if (Capacitor.isNativePlatform()) {
+ // authUrl = "https://www.leapchat.org/api/login";
+ authUrl = "http://10.0.2.2:8080/api/login";
+}
+
+// Helper for parsing response from Go API
+//
+// From https://stackoverflow.com/a/36183085
+const b64toBlob = (base64, type = 'application/octet-stream') =>
+ fetch(`data:${type};base64,${base64}`).then(res => res.blob());
async function connectWithAuthRequest(initiateConnection, mID, secretKey, isNewPassphrase) {
- const response = await fetch(authUrl, {
- method: "GET",
- headers: {
- 'X-Minilock-Id': mID
- }
- });
+ let response, message;
+ if (Capacitor.isNativePlatform()) {
+ response = await CapacitorHttp.request({
+ url: authUrl,
+ headers: {
+ 'X-Minilock-Id': mID
+ },
+ method: 'GET',
+ responseType: 'blob' // Makes `response.data` base64-encoded binary data
+ });
+
+ message = await b64toBlob(response.data);
+ } else {
+ response = await fetch(authUrl, {
+ method: "GET",
+ headers: {
+ 'X-Minilock-Id': mID
+ }
+ });
+
+ message = await response.blob();
+ }
- const message = await response.blob();
miniLock.crypto.decryptFile(message, mID, secretKey,
function (fileBlob, saveName, senderID) {
const reader = new FileReader();
diff --git a/src/utils/vh_fix.js b/src/utils/vh_fix.js
new file mode 100644
index 0000000..50d245e
--- /dev/null
+++ b/src/utils/vh_fix.js
@@ -0,0 +1,22 @@
+import { Capacitor } from '@capacitor/core';
+
+function vh() {
+ return (window.innerHeight * 0.01) + 'px';
+}
+document.documentElement.style.setProperty('--vh', vh());
+
+var lastHeight = window.innerHeight;
+
+window.addEventListener('resize', () => {
+ if (window.innerWidth > window.innerHeight ||
+ Math.abs(lastHeight - window.innerHeight) > 100) {
+ document.documentElement.style.setProperty(`--vh`, vh());
+ lastHeight = window.innerHeight;
+ }
+});
+
+
+document.documentElement.style.setProperty('--androidTopBar', '0px');
+if (Capacitor.isNativePlatform()) {
+ document.documentElement.style.setProperty('--androidTopBar', '36px');
+}