Merge branch 'master' into database-restructuring

pull/3/head
Simon Huang 5 years ago
commit fb90ca1c77

@ -76,6 +76,7 @@ const turtle = {
userId: {
name: 'Username',
},
userCount: 0,
},
},
};

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -3,38 +3,43 @@ ion-textarea {
}
.chat-card {
background: var(--ion-color-light);
height: 100%;
width: 100%;
float: right;
margin: 0;
}
.message-toolbar {
padding-left: 5px;
--background: var(--ion-color-light);
}
.footer-ios ion-toolbar:first-of-type {
padding-top: 5px;
}
.send-msg {
align-items: center;
justify-content: center;
display: flex;
padding-left: 0;
}
.send-button {
width: 100%;
}
.message-col {
white-space: normal;
padding: 10px;
align-self: center;
margin: 0 2px 0 5px;
--box-shadow: 0 3px 2px -1px rgba(0, 0, 0, 0.2), 0 2px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
.message-input {
width: 100%;
height: 100%;
border: 1px solid #999;
border-radius: 5px;
text-align: left;
}
@media (max-width: 576px) {
.message-input {
border-radius: 10px;
height: 35px;
}
.send-msg {

@ -1,16 +1,19 @@
import { IonButton, IonCard, IonCol, IonFooter, IonInput, IonRow } from '@ionic/react';
import { IonCard, IonFabButton, IonFooter, IonIcon, IonInput, IonToolbar } from '@ionic/react';
import { sendOutline } from 'ionicons/icons';
import React, { useState } from 'react';
import { db, timestamp } from '../services/firebase';
import './Chatbox.css';
import Messages from './Messages';
import OnlineList from './OnlineList';
type ChatboxProps = {
ownerId: string;
roomId: string;
userId: string;
userList: string[];
};
const Chat: React.FC<ChatboxProps> = ({ ownerId, roomId, userId }) => {
const Chat: React.FC<ChatboxProps> = ({ ownerId, roomId, userId, userList }) => {
const [message, setMessage] = useState(''); // Message to be sent
// Send message to database
@ -38,8 +41,7 @@ const Chat: React.FC<ChatboxProps> = ({ ownerId, roomId, userId }) => {
<IonCard class="chat-card">
<Messages ownerId={ownerId} roomId={roomId} userId={userId}></Messages>
<IonFooter>
<IonRow>
<IonCol size="12" sizeSm="9" class="message-col">
<IonToolbar class="message-toolbar">
<IonInput
onIonChange={(e) => setMessage(e.detail.value!)}
onKeyDown={(e) => onEnter(e)}
@ -48,13 +50,11 @@ const Chat: React.FC<ChatboxProps> = ({ ownerId, roomId, userId }) => {
enterkeyhint="send"
class="message-input"
></IonInput>
</IonCol>
<IonCol size="3" class="send-msg">
<IonButton expand="block" color="primary" onClick={sendMessage} class="send-button">
Send
</IonButton>
</IonCol>
</IonRow>
<IonFabButton slot="end" size="small" onClick={sendMessage} class="send-button">
<IonIcon icon={sendOutline}></IonIcon>
</IonFabButton>
<OnlineList userList={userList}></OnlineList>
</IonToolbar>
</IonFooter>
</IonCard>
);

@ -7,7 +7,7 @@
.message-grid {
margin-right: 0;
height: 100%;
user-select: auto;
user-select: text;
}
.right-align {

@ -0,0 +1,29 @@
.online-button {
margin: 0 4px 0 0;
align-self: center;
--box-shadow: 0 3px 2px -1px rgba(0, 0, 0, 0.2), 0 2px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
}
.popover-list {
padding-top: 2px;
}
.list-header {
font-size: 24px;
color: var(--ion-color-primary);
border-bottom: 1px solid #999;
}
.online-item {
--padding-start: 12px;
--min-height: 0;
}
.online-label {
margin-top: 8px;
margin-bottom: 0;
}
ion-backdrop {
cursor: default;
}

@ -0,0 +1,48 @@
import React, { useState } from 'react';
import { IonPopover, IonFabButton, IonIcon, IonList, IonListHeader, IonItem, IonLabel } from '@ionic/react';
import { peopleOutline } from 'ionicons/icons';
import './OnlineList.css';
type OnlineListProps = {
userList: string[];
};
const OnlineList: React.FC<OnlineListProps> = ({ userList }) => {
const [showPopover, setShowPopover] = useState<{ open: boolean; event: Event | undefined }>({
open: false,
event: undefined,
});
return (
<>
<IonPopover
cssClass="online-popover"
isOpen={showPopover.open}
event={showPopover.event}
showBackdrop={false}
onDidDismiss={(e) => setShowPopover({ open: false, event: undefined })}
>
<IonList class="popover-list">
<IonListHeader class="list-header">Online</IonListHeader>
{userList.map((user) => {
return (
<IonItem key={user} class="online-item" lines="none">
<IonLabel class="online-label">{user}</IonLabel>
</IonItem>
);
})}
</IonList>
</IonPopover>
<IonFabButton
slot="end"
size="small"
class="online-button"
onClick={(e) => setShowPopover({ open: true, event: e.nativeEvent })}
>
<IonIcon icon={peopleOutline}></IonIcon>
</IonFabButton>
</>
);
};
export default OnlineList;

@ -1,11 +1,9 @@
.title {
text-align: left;
max-width: 100px;
max-width: 110px;
padding-left: 15px;
padding-right: 15px;
color: var(--ion-color-primary);
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
font-size: 24px;
cursor: pointer;
}

@ -33,14 +33,14 @@ const RoomHeader: React.FC<RoomHeaderProps> = ({ roomId, userId, ownerId }) => {
};
const toHome = () => {
history.replace('/');
history.push('/');
history.go(0);
};
return (
<IonToolbar>
<IonTitle slot="start" onClick={toHome} class="title">
Turtle
TURTLE
</IonTitle>
{userId === ownerId ? (
<>
@ -49,7 +49,7 @@ const RoomHeader: React.FC<RoomHeaderProps> = ({ roomId, userId, ownerId }) => {
type="url"
inputmode="search"
class="input-bar"
placeholder="Upload new video by URL"
placeholder="Upload video by URL"
onIonChange={(e) => setVideoUrl(e.detail.value!)}
value={videoUrl}
onSubmit={onSubmit}

@ -2,11 +2,14 @@
width: 50%;
}
.home-content {
--background: var(--ion-color-light-shade);
}
.home-grid {
max-width: 500px;
font-family: Verdana, Geneva, Tahoma, sans-serif;
font-size: 30px;
color: var(--ion-color-secondary);
font-size: 26px;
color: var(--ion-color-primary);
text-align: center;
}
@ -15,8 +18,8 @@ ion-toolbar {
}
ion-title {
font-family: 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
font-size: 24px;
font-size: 28px;
font-style: oblique;
color: var(--ion-color-primary);
}
@ -30,7 +33,6 @@ ion-title {
}
.share-col {
margin-top: 10px;
margin-top: 8px;
font-size: 20px;
color: var(--ion-color-primary);
}

@ -57,10 +57,10 @@ const Home: React.FC = () => {
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Turtle</IonTitle>
<IonTitle>TURTLE</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent>
<IonContent class="home-content">
{loading ? (
<IonContent className="ion-padding">Loading...</IonContent>
) : (

@ -1,4 +1,5 @@
.room-grid {
background: var(--ion-color-light-shade);
margin-inline-start: 0;
margin-inline-end: 0;
height: 100%;

@ -17,6 +17,7 @@ const Room: React.FC<RouteComponentProps<{ roomId: string }>> = ({ match }) => {
const [ownerId, setOwnerId] = useState('undefined');
const [loading, setLoading] = useState(true);
const [userCount, setUserCount] = useState(0);
const [userList, setUserList] = useState<string[]>(['']);
// Handle logging in
useEffect(() => {
@ -61,9 +62,19 @@ const Room: React.FC<RouteComponentProps<{ roomId: string }>> = ({ match }) => {
// Keep track of online user presence in realtime database rooms
roomRef.on('value', async (snapshot) => {
// Populate list of users in a room
const set: string[] = [];
snapshot.forEach((childSnapshot) => {
if (childSnapshot.key !== 'userCount') {
set.push(childSnapshot.child('name').val());
}
});
setUserList(set);
if (!snapshot.hasChild(userId)) {
// Keep userId in the room as long as a connection from the client exists
await roomRef.child(userId).set({ name: 'placeholder' });
const username = (await db.collection('users').doc(userId).get()).data()?.name;
await roomRef.child(userId).set({ name: username });
await roomRef.update({ userCount: increment });
}
});
@ -142,7 +153,7 @@ const Room: React.FC<RouteComponentProps<{ roomId: string }>> = ({ match }) => {
<VideoPlayer ownerId={ownerId} userId={userId} roomId={roomId}></VideoPlayer>
</IonCol>
<IonCol size="12" sizeLg="3" class="chat-col">
<Chat ownerId={ownerId} roomId={roomId} userId={userId}></Chat>
<Chat ownerId={ownerId} roomId={roomId} userId={userId} userList={userList}></Chat>
</IonCol>
</IonRow>
</IonGrid>

@ -1,24 +1,34 @@
const adjectives = [
'Adamant',
'Instinctive',
'Abaft',
'Actually',
'Husky',
'Adamant',
'Adorable',
'Anxious',
'Bent',
'Fascinated',
'Sexual',
'Mute',
'Silent',
'Bright',
'Coherent',
'Curious',
'Diligent',
'Earthy',
'Fascinated',
'Foreign',
'Hateful',
'Husky',
'Instinctive',
'Jagged',
'Juvenile',
'Military',
'Mute',
'Naughty',
'Foreign',
'Earthy',
'Diligent',
'Anxious',
'Adorable',
'Neat',
'Nifty',
'Parallel',
'Quack',
'Unequal',
'Roomy',
'Sedate',
'Sharp',
'Silent',
'Unequal',
];
const animals = [
@ -59,7 +69,7 @@ const animals = [
// };
export const generateAnonName = (): string => {
const adj: string = adjectives[Math.floor(Math.random() * 20)];
const adj: string = adjectives[Math.floor(Math.random() * 30)];
const animal: string = animals[Math.floor(Math.random() * 20)];
return adj + ' ' + animal;
};

@ -72,8 +72,31 @@ http://ionicframework.com/docs/theming/ */
--ion-color-light-rgb: 244, 245, 248;
--ion-color-light-contrast: #000000;
--ion-color-light-contrast-rgb: 0, 0, 0;
--ion-color-light-shade: #d7d8da;
--ion-color-light-shade: #edeeef;
--ion-color-light-tint: #f5f6f9;
--ion-font-family: 'custom';
}
@font-face {
font-family: 'custom';
font-style: normal;
font-weight: normal;
src: url('../assets/OpenSans-Regular.ttf');
}
@font-face {
font-family: 'custom';
font-style: normal;
font-weight: bold;
src: url('../assets/OpenSans-SemiBold.ttf');
}
@font-face {
font-family: 'custom';
font-style: oblique;
font-weight: normal;
src: url('../assets/PathwayGothicOne-Regular.ttf');
}
@media (prefers-color-scheme: dark) {
@ -84,65 +107,65 @@ http://ionicframework.com/docs/theming/ */
body {
--ion-color-primary: #428cff;
--ion-color-primary-rgb: 66,140,255;
--ion-color-primary-rgb: 66, 140, 255;
--ion-color-primary-contrast: #ffffff;
--ion-color-primary-contrast-rgb: 255,255,255;
--ion-color-primary-contrast-rgb: 255, 255, 255;
--ion-color-primary-shade: #3a7be0;
--ion-color-primary-tint: #5598ff;
--ion-color-secondary: #50c8ff;
--ion-color-secondary-rgb: 80,200,255;
--ion-color-secondary-rgb: 80, 200, 255;
--ion-color-secondary-contrast: #ffffff;
--ion-color-secondary-contrast-rgb: 255,255,255;
--ion-color-secondary-contrast-rgb: 255, 255, 255;
--ion-color-secondary-shade: #46b0e0;
--ion-color-secondary-tint: #62ceff;
--ion-color-tertiary: #6a64ff;
--ion-color-tertiary-rgb: 106,100,255;
--ion-color-tertiary-rgb: 106, 100, 255;
--ion-color-tertiary-contrast: #ffffff;
--ion-color-tertiary-contrast-rgb: 255,255,255;
--ion-color-tertiary-contrast-rgb: 255, 255, 255;
--ion-color-tertiary-shade: #5d58e0;
--ion-color-tertiary-tint: #7974ff;
--ion-color-success: #2fdf75;
--ion-color-success-rgb: 47,223,117;
--ion-color-success-rgb: 47, 223, 117;
--ion-color-success-contrast: #000000;
--ion-color-success-contrast-rgb: 0,0,0;
--ion-color-success-contrast-rgb: 0, 0, 0;
--ion-color-success-shade: #29c467;
--ion-color-success-tint: #44e283;
--ion-color-warning: #ffd534;
--ion-color-warning-rgb: 255,213,52;
--ion-color-warning-rgb: 255, 213, 52;
--ion-color-warning-contrast: #000000;
--ion-color-warning-contrast-rgb: 0,0,0;
--ion-color-warning-contrast-rgb: 0, 0, 0;
--ion-color-warning-shade: #e0bb2e;
--ion-color-warning-tint: #ffd948;
--ion-color-danger: #ff4961;
--ion-color-danger-rgb: 255,73,97;
--ion-color-danger-rgb: 255, 73, 97;
--ion-color-danger-contrast: #ffffff;
--ion-color-danger-contrast-rgb: 255,255,255;
--ion-color-danger-contrast-rgb: 255, 255, 255;
--ion-color-danger-shade: #e04055;
--ion-color-danger-tint: #ff5b71;
--ion-color-dark: #f4f5f8;
--ion-color-dark-rgb: 244,245,248;
--ion-color-dark-rgb: 244, 245, 248;
--ion-color-dark-contrast: #000000;
--ion-color-dark-contrast-rgb: 0,0,0;
--ion-color-dark-contrast-rgb: 0, 0, 0;
--ion-color-dark-shade: #d7d8da;
--ion-color-dark-tint: #f5f6f9;
--ion-color-medium: #989aa2;
--ion-color-medium-rgb: 152,154,162;
--ion-color-medium-rgb: 152, 154, 162;
--ion-color-medium-contrast: #000000;
--ion-color-medium-contrast-rgb: 0,0,0;
--ion-color-medium-contrast-rgb: 0, 0, 0;
--ion-color-medium-shade: #86888f;
--ion-color-medium-tint: #a2a4ab;
--ion-color-light: #222428;
--ion-color-light-rgb: 34,36,40;
--ion-color-light-rgb: 34, 36, 40;
--ion-color-light-contrast: #ffffff;
--ion-color-light-contrast-rgb: 255,255,255;
--ion-color-light-contrast-rgb: 255, 255, 255;
--ion-color-light-shade: #1e2023;
--ion-color-light-tint: #383a3e;
}
@ -154,10 +177,10 @@ http://ionicframework.com/docs/theming/ */
.ios body {
--ion-background-color: #000000;
--ion-background-color-rgb: 0,0,0;
--ion-background-color-rgb: 0, 0, 0;
--ion-text-color: #ffffff;
--ion-text-color-rgb: 255,255,255;
--ion-text-color-rgb: 255, 255, 255;
--ion-color-step-50: #0d0d0d;
--ion-color-step-100: #1a1a1a;
@ -186,7 +209,6 @@ http://ionicframework.com/docs/theming/ */
--ion-card-background: #1c1c1d;
}
/*
* Material Design Dark Theme
* -------------------------------------------
@ -194,10 +216,10 @@ http://ionicframework.com/docs/theming/ */
.md body {
--ion-background-color: #121212;
--ion-background-color-rgb: 18,18,18;
--ion-background-color-rgb: 18, 18, 18;
--ion-text-color: #ffffff;
--ion-text-color-rgb: 255,255,255;
--ion-text-color-rgb: 255, 255, 255;
--ion-border-color: #222222;

Loading…
Cancel
Save