Merge pull request #1 from antobinary/test-ghazi-pr

Extra commit for html5 client emojis
This commit is contained in:
Ghazi Triki 2017-04-06 17:41:04 +02:00 committed by GitHub
commit fd6092e5a8
16 changed files with 196 additions and 116 deletions

View File

@ -10,8 +10,6 @@ import {
getCaptionsStatus,
} from './service';
import { setDefaultSettings } from '../settings/service';
import Auth from '/imports/ui/services/auth';
import Users from '/imports/api/users';
import Breakouts from '/imports/api/breakouts';
@ -53,7 +51,6 @@ class AppContainer extends Component {
const APP_CONFIG = Meteor.settings.public.app;
const init = () => {
setDefaultSettings();
if (APP_CONFIG.autoJoinAudio) {
showModal(<AudioModalContainer />);
}

View File

@ -1,5 +1,5 @@
import Breakouts from '/imports/api/breakouts';
import SettingsService from '/imports/ui/components/settings/service';
import Settings from '/imports/ui/services/settings';
let currentModal = {
component: null,
@ -23,13 +23,13 @@ const clearModal = () => {
};
const getCaptionsStatus = () => {
const settings = SettingsService.getSettingsFor('cc');
return settings ? settings.closedCaptions : false;
const ccSettings = Settings.cc;
return ccSettings ? ccSettings.enabled : false;
};
const getFontSize = () => {
const settings = SettingsService.getSettingsFor('application');
return settings ? settings.fontSize : '16px';
const applicationSettings = Settings.application;
return applicationSettings ? applicationSettings.fontSize : '16px';
};
function meetingIsBreakout() {

View File

@ -6,6 +6,7 @@ import styles from './styles';
import MessageFormActions from './message-form-actions/component';
import TextareaAutosize from 'react-autosize-textarea';
import Button from '../../button/component';
const propTypes = {
};
@ -42,9 +43,12 @@ class MessageForm extends Component {
this.handleMessageChange = this.handleMessageChange.bind(this);
this.handleMessageKeyDown = this.handleMessageKeyDown.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleMessageKeyDown(e) {
//TODO Prevent send message pressing enter on mobile and/or virtual keyboard
if (e.keyCode === 13 && !e.shiftKey) {
e.preventDefault();
@ -104,9 +108,9 @@ class MessageForm extends Component {
<TextareaAutosize
className={styles.input}
id="message-input"
placeholder={ intl.formatMessage(messages.inputPlaceholder, { name: chatName }) }
placeholder={intl.formatMessage(messages.inputPlaceholder, { name: chatName })}
aria-controls={this.props.chatAreaId}
aria-label={ intl.formatMessage(messages.inputLabel, { name: chatTitle }) }
aria-label={intl.formatMessage(messages.inputLabel, { name: chatTitle })}
autoCorrect="off"
autoComplete="off"
spellCheck="true"
@ -115,13 +119,16 @@ class MessageForm extends Component {
onChange={this.handleMessageChange}
onKeyDown={this.handleMessageKeyDown}
/>
<input
ref="btnSubmit"
className={'sr-only'}
<Button
className={styles.sendButton}
aria-label={intl.formatMessage(messages.submitLabel)}
type="submit"
disabled={disabled}
value={ intl.formatMessage(messages.submitLabel) }
/>
label={intl.formatMessage(messages.submitLabel)}
hideLabel={true}
icon={"right_arrow"}
onClick={()=>{}}
/>
</form>
);
}

View File

@ -61,3 +61,14 @@
background-color: fade-out($color-gray-lighter, .75);
}
}
.sendButton {
@extend .input;
border-left: 0px;
min-width: 1rem;
max-width: 2.5rem;
> [class*=" icon-bbb-"] {
color: $color-gray-light;
}
}

View File

@ -4,7 +4,7 @@ import _ from 'lodash';
import Auth from '/imports/ui/services/auth';
import UserListService from '/imports/ui/components/user-list/service';
import SettingsService from '/imports/ui/components/settings/service';
import Settings from '/imports/ui/services/settings';
class ChatNotificationContainer extends Component {
constructor(props) {
@ -30,7 +30,7 @@ class ChatNotificationContainer extends Component {
}
export default createContainer(({ currentChatID }) => {
const AppSettings = SettingsService.getSettingsFor('application');
const AppSettings = Settings.application;
const unreadMessagesCount = UserListService.getOpenChats()
.map(chat => chat.unreadCounter)

View File

@ -1,13 +1,13 @@
import Captions from '/imports/api/captions';
import Auth from '/imports/ui/services/auth';
import Storage from '/imports/ui/services/storage/session';
import Settings from '/imports/ui/services/settings';
let getCCData = () => {
const meetingID = Auth.meetingID;
const ccSettings = Storage.getItem('settings_cc');
const ccSettings = Settings.cc;
let CCEnabled = ccSettings.closedCaptions;
let CCEnabled = ccSettings.enabled;
//associative array that keeps locales with arrays of string objects related to those locales
let captions = [];

View File

@ -7,6 +7,7 @@ import Audio from '/imports/ui/components/settings/submenus/audio/component';
import Application from '/imports/ui/components/settings/submenus/application/container';
import Participants from '/imports/ui/components/settings/submenus/participants/component';
import Video from '/imports/ui/components/settings/submenus/video/component';
import _ from 'lodash';
import Icon from '../icon/component';
import styles from './styles';
@ -26,11 +27,11 @@ export default class Settings extends Component {
this.state = {
current: {
audio,
video,
application,
cc,
participants,
audio: _.clone(audio),
video: _.clone(video),
application: _.clone(application),
cc: _.clone(cc),
participants: _.clone(participants),
},
saved: {
audio: _.clone(audio),
@ -42,7 +43,7 @@ export default class Settings extends Component {
selectedTab: 0,
};
this.handleSettingsApply = props.updateSettings;
this.updateSettings = props.updateSettings;
this.handleUpdateSettings = this.handleUpdateSettings.bind(this);
this.handleSelectTab = this.handleSelectTab.bind(this);
}
@ -57,7 +58,7 @@ export default class Settings extends Component {
title="Settings"
confirm={{
callback: (() => {
this.handleSettingsApply(this.state.current);
this.updateSettings(this.state.current);
}),
label: 'Save',
description: 'Saves the changes and close the settings menu',

View File

@ -2,11 +2,12 @@ import React, { Component, PropTypes } from 'react';
import { createContainer } from 'meteor/react-meteor-data';
import _ from 'lodash';
import Settings from './component';
import SettingsService from '/imports/ui/services/settings';
import {
getSettingsFor,
updateSettings,
getClosedCaptionLocales,
getUserRoles,
updateSettings,
} from './service';
class SettingsContainer extends Component {
@ -19,11 +20,11 @@ class SettingsContainer extends Component {
export default createContainer(() => {
return {
audio: getSettingsFor('audio'),
video: getSettingsFor('video'),
application: getSettingsFor('application'),
cc: getSettingsFor('cc'),
participants: getSettingsFor('participants'),
audio: SettingsService.audio,
video: SettingsService.video,
application: SettingsService.application,
cc: SettingsService.cc,
participants: SettingsService.participants,
updateSettings,
locales: getClosedCaptionLocales(),
isModerator: getUserRoles() === 'MODERATOR',

View File

@ -1,18 +1,8 @@
import Storage from '/imports/ui/services/storage/session';
import Users from '/imports/api/users';
import Captions from '/imports/api/captions';
import Auth from '/imports/ui/services/auth';
import _ from 'lodash';
const updateSettings = (obj) => {
Object.keys(obj).forEach(k => Storage.setItem(`settings_${k}`, obj[k]));
};
const getSettingsFor = (key) => {
const setting = Storage.getItem(`settings_${key}`);
return setting;
};
import Settings from '/imports/ui/services/settings';
const getClosedCaptionLocales = () => {
//list of unique locales in the Captions Collection
@ -34,61 +24,13 @@ const getUserRoles = () => {
return user.role;
};
const setDefaultSettings = () => {
const defaultSettings = {
application: {
chatAudioNotifications: false,
chatPushNotifications: false,
fontSize: '16px',
},
audio: {
inputDeviceId: undefined,
outputDeviceId: undefined,
},
video: {
viewParticipantsWebcams: true,
},
cc: {
backgroundColor: '#FFFFFF',
fontColor: '#000000',
closedCaptions: false,
fontFamily: 'Calibri',
fontSize: -1,
locale: undefined,
takeOwnership: false,
},
participants: {
muteAll: false,
lockAll: false,
lockAll: false,
microphone: false,
publicChat: false,
privateChat: false,
layout: false,
},
};
const savedSettings = {
application: getSettingsFor('application'),
audio: getSettingsFor('audio'),
video: getSettingsFor('video'),
cc: getSettingsFor('cc'),
participants: getSettingsFor('participants'),
};
let settings = {};
Object.keys(defaultSettings).forEach(key => {
settings[key] = _.extend(defaultSettings[key], savedSettings[key]);
});
updateSettings(settings);
const updateSettings = (obj) => {
Object.keys(obj).forEach(k => Settings[k] = obj[k]);
Settings.save();
};
export {
updateSettings,
getSettingsFor,
getClosedCaptionLocales,
getUserRoles,
setDefaultSettings,
updateSettings,
};

View File

@ -28,7 +28,7 @@ export default class ClosedCaptionsMenu extends BaseMenu {
settings: {
backgroundColor: props.settings ? props.settings.backgroundColor : '#f3f6f9',
fontColor: props.settings ? props.settings.fontColor : '#000000',
closedCaptions: props.settings ? props.settings.closedCaptions : false,
enabled: props.settings ? props.settings.enabled : false,
fontFamily: props.settings ? props.settings.fontFamily : 'Calibri',
fontSize: props.settings ? props.settings.fontSize : -1,
locale: props.settings ? props.settings.locale : -1,
@ -99,8 +99,8 @@ export default class ClosedCaptionsMenu extends BaseMenu {
<div className={cx(styles.formElement, styles.pullContentRight)}>
<Toggle
icons={false}
defaultChecked={this.state.settings.closedCaptions}
onChange={() => this.handleToggle('closedCaptions')} />
defaultChecked={this.state.settings.enabled}
onChange={() => this.handleToggle('enabled')} />
</div>
</div>
</div>

View File

@ -48,7 +48,28 @@ export default class UserAvatar extends Component {
let content = user.name.slice(0, 2);
if (user.emoji.status !== 'none') {
content = <Icon iconName={user.emoji.status}/>;
let iconEmoji = undefined;
switch (user.emoji.status) {
case 'thumbsUp':
iconEmoji = 'thumbs_up';
break;
case 'thumbsDown':
iconEmoji = 'thumbs_down';
break;
case 'raiseHand':
iconEmoji = 'hand';
break;
case 'away':
iconEmoji = 'time';
break;
case 'neutral':
iconEmoji = 'undecided';
break;
default:
iconEmoji = user.emoji.status;
}
content = <Icon iconName={iconEmoji}/>;
}
return content;

View File

@ -10,7 +10,12 @@ import { defineMessages, injectIntl } from 'react-intl';
const intlMessages = defineMessages({
titlePublic: {
id: 'app.chat.titlePublic',
defaultMessage: "Public Chat",
},
unreadPlural: {
id: 'app.userlist.chatlistitem.unreadPlural',
},
unreadSingular: {
id: 'app.userlist.chatlistitem.unreadSingular',
},
});
@ -38,9 +43,11 @@ class ChatListItem extends Component {
} = this.props;
const linkPath = [PRIVATE_CHAT_PATH, chat.id].join('');
const isCurrentChat = chat.id === openChat;
let isSingleMessage = chat.unreadCounter === 1;
let linkClasses = {};
linkClasses[styles.active] = chat.id === openChat;
linkClasses[styles.active] = isCurrentChat;
if (chat.name === 'Public Chat') {
chat.name = intl.formatMessage(intlMessages.titlePublic);
@ -48,18 +55,26 @@ class ChatListItem extends Component {
return (
<li className={cx(styles.chatListItem, linkClasses)}>
<Link to={linkPath} className={styles.chatListItemLink}>
{chat.icon ? this.renderChatIcon() : this.renderChatAvatar()}
<div className={styles.chatName}>
{!compact ? <h3 className={styles.chatNameMain}>{chat.name}</h3> : null }
</div>
{(chat.unreadCounter > 0) ?
<div className={styles.unreadMessages}>
<p className={styles.unreadMessagesText}>
{chat.unreadCounter}
</p>
<Link
to={linkPath}
className={styles.chatListItemLink}
role="button"
aria-expanded={isCurrentChat}>
{chat.icon ? this.renderChatIcon() : this.renderChatAvatar()}
<div className={styles.chatName}>
{!compact ? <span className={styles.chatNameMain}>{chat.name}</span> : null }
</div>
: null}
{(chat.unreadCounter > 0) ?
<div
className={styles.unreadMessages}
aria-label={isSingleMessage
? intl.formatMessage(intlMessages.unreadSingular, { count: chat.unreadCounter })
: intl.formatMessage(intlMessages.unreadPlural, { count: chat.unreadCounter })}>
<div className={styles.unreadMessagesText} aria-hidden="true">
{chat.unreadCounter}
</div>
</div>
: null}
</Link>
</li>
);

View File

@ -0,0 +1,56 @@
import Storage from '/imports/ui/services/storage/session';
import _ from 'lodash';
const SETTINGS = [
'application',
'audio',
'video',
'cc',
'participants',
];
class Settings {
constructor(defaultValues = {}) {
SETTINGS.forEach(p => {
const privateProp = `_${p}`;
this[privateProp] = {
tracker: new Tracker.Dependency,
value: undefined,
};
Object.defineProperty(this, p, {
get: () => {
this[privateProp].tracker.depend();
return this[privateProp].value;
},
set: v => {
this[privateProp].value = v;
this[privateProp].tracker.changed();
},
});
});
this.setDefault(defaultValues);
}
setDefault(defaultValues) {
const savedSettings = {};
SETTINGS.forEach(s => {
savedSettings[s] = Storage.getItem(`settings_${s}`);
});
Object.keys(defaultValues).forEach(key => {
this[key] = _.extend(defaultValues[key], savedSettings[key]);
});
this.save();
};
save() {
Object.keys(this).forEach(k => Storage.setItem(`settings${k}`, this[k].value));
}
}
const SettingsSingleton = new Settings(Meteor.settings.public.app.defaultSettings);
export default SettingsSingleton;

View File

@ -1,4 +1,4 @@
const EMOJI_STATUSES = ['time', 'hand', 'undecided', 'confused', 'sad',
'happy', 'applause', 'thumbs_up', 'thumbs_down'];
const EMOJI_STATUSES = ['away', 'raiseHand', 'neutral', 'confused', 'sad',
'happy', 'applause', 'thumbsUp', 'thumbsDown'];
export { EMOJI_STATUSES };

View File

@ -25,3 +25,30 @@ app:
basename: '/html5client'
defaultLocale: 'en'
#default settings for session storage
defaultSettings:
application:
chatAudioNotifications: false
chatPushNotifications: false
fontSize: "16px"
audio:
inputDeviceId: undefined
outputDeviceId: undefined
video:
viewParticipantsWebcams: true
cc:
backgroundColor: "#FFFFFF"
fontColor: "#000000"
enabled: false
fontFamily: "Calibri"
fontSize: '16px'
# locale: undefined
takeOwnership: false
participants:
muteAll: false
lockAll: false
lockAll: false
microphone: false
publicChat: false
privateChat: false
layout: false

View File

@ -14,6 +14,8 @@
"app.chat.partnerDisconnected": "{name} has left the meeting",
"app.chat.closeChatLabel": "Close {title}",
"app.chat.moreMessages": "More messages below",
"app.userlist.chatlistitem.unreadSingular": "{count} New Message",
"app.userlist.chatlistitem.unreadPlural": "{count} New Messages",
"app.chat.Label": "Chat",
"app.media.Label": "Media",
"app.presentation.presentationToolbar.prevSlideLabel": "Previous slide",