Pārlūkot izejas kodu

feat(dropbox): For mobile.

This involves redesign of the web recording dialog in order to look the
same as the mobile one.
master
hristoterezov 6 gadus atpakaļ
vecāks
revīzija
af37141e3d

+ 17
- 2
css/_recording.scss Parādīt failu

@@ -3,8 +3,23 @@
3 3
 }
4 4
 
5 5
 .recording-dialog {
6
+    flex: 0;
7
+    flex-direction: column;
8
+
9
+    .recording-header {
10
+        display: flex;
11
+        flex: 0;
12
+        flex-direction: row;
13
+        justify-content: space-between;
14
+        align-items: center;
15
+
16
+        .recording-title {
17
+            font-size: 16px;
18
+            font-weight: bold;
19
+        }
20
+    }
21
+
6 22
     .authorization-panel {
7
-        border-bottom: 2px solid rgba(0, 0, 0, 0.3);
8 23
         display: flex;
9 24
         flex-direction: column;
10 25
         margin-bottom: 10px;
@@ -32,7 +47,7 @@
32 47
             }
33 48
         }
34 49
 
35
-        .logged-in-pannel {
50
+        .logged-in-panel {
36 51
             padding: 10px;
37 52
         }
38 53
     }

+ 1
- 2
lang/main.json Parādīt failu

@@ -468,8 +468,7 @@
468 468
         "on": "Recording",
469 469
         "pending": "Preparing to record the meeting...",
470 470
         "rec": "REC",
471
-        "authDropboxText": "Upload your recording to Dropbox.",
472
-        "authDropboxCompletedText": "Your recording file will appear in your Dropbox shortly after the recording has finished.",
471
+        "authDropboxText": "Upload to Dropbox",
473 472
         "serviceName": "Recording service",
474 473
         "signOut": "Sign Out",
475 474
         "signIn": "sign in",

+ 6
- 42
react/features/dropbox/actions.js Parādīt failu

@@ -1,40 +1,9 @@
1 1
 // @flow
2 2
 
3
-import { Dropbox } from 'dropbox';
4
-
5
-import {
6
-    getJitsiMeetGlobalNS,
7
-    getLocationContextRoot,
8
-    parseStandardURIString
9
-} from '../base/util';
10
-import { parseURLParams } from '../base/config';
3
+import { getLocationContextRoot } from '../base/util';
11 4
 
12 5
 import { UPDATE_DROPBOX_TOKEN } from './actionTypes';
13
-
14
-/**
15
- * Executes the oauth flow.
16
- *
17
- * @param {string} authUrl - The URL to oauth service.
18
- * @returns {Promise<string>} - The URL with the authorization details.
19
- */
20
-function authorize(authUrl: string): Promise<string> {
21
-    const windowName = `oauth${Date.now()}`;
22
-    const gloabalNS = getJitsiMeetGlobalNS();
23
-
24
-    gloabalNS.oauthCallbacks = gloabalNS.oauthCallbacks || {};
25
-
26
-    return new Promise(resolve => {
27
-        const popup = window.open(authUrl, windowName);
28
-
29
-        gloabalNS.oauthCallbacks[windowName] = () => {
30
-            const returnURL = popup.location.href;
31
-
32
-            popup.close();
33
-            delete gloabalNS.oauthCallbacks.windowName;
34
-            resolve(returnURL);
35
-        };
36
-    });
37
-}
6
+import { _authorizeDropbox } from './functions';
38 7
 
39 8
 /**
40 9
  * Action to authorize the Jitsi Recording app in dropbox.
@@ -45,18 +14,13 @@ export function authorizeDropbox() {
45 14
     return (dispatch: Function, getState: Function) => {
46 15
         const state = getState();
47 16
         const { locationURL } = state['features/base/connection'];
48
-        const { dropbox } = state['features/base/config'];
17
+        const { dropbox = {} } = state['features/base/config'];
49 18
         const redirectURI = `${locationURL.origin
50 19
             + getLocationContextRoot(locationURL)}static/oauth.html`;
51
-        const dropboxAPI = new Dropbox({ clientId: dropbox.clientId });
52
-        const url = dropboxAPI.getAuthenticationUrl(redirectURI);
53
-
54
-        authorize(url).then(returnUrl => {
55
-            const params
56
-                = parseURLParams(parseStandardURIString(returnUrl), true) || {};
57 20
 
58
-            dispatch(updateDropboxToken(params.access_token));
59
-        });
21
+        _authorizeDropbox(dropbox.clientId, redirectURI)
22
+            .then(
23
+                token => dispatch(updateDropboxToken(token)));
60 24
     };
61 25
 }
62 26
 

+ 50
- 0
react/features/dropbox/functions.any.js Parādīt failu

@@ -0,0 +1,50 @@
1
+// @flow
2
+export * from './functions';
3
+
4
+import { getDisplayName, getSpaceUsage } from './functions';
5
+
6
+const logger = require('jitsi-meet-logger').getLogger(__filename);
7
+
8
+/**
9
+ * Information related to the user's dropbox account.
10
+ */
11
+type DropboxUserData = {
12
+
13
+    /**
14
+     * The available space left in MB into the user's Dropbox account.
15
+     */
16
+    spaceLeft: number,
17
+
18
+    /**
19
+     * The display name of the user in Dropbox.
20
+     */
21
+    userName: string
22
+};
23
+
24
+/**
25
+ * Fetches information about the user's dropbox account.
26
+ *
27
+ * @param {string} token - The dropbox access token.
28
+ * @param {string} clientId - The Jitsi Recorder dropbox app ID.
29
+ * @returns {Promise<DropboxUserData|undefined>}
30
+ */
31
+export function getDropboxData(
32
+        token: string,
33
+        clientId: string
34
+): Promise<?DropboxUserData> {
35
+    return Promise.all(
36
+        [ getDisplayName(token, clientId), getSpaceUsage(token, clientId) ]
37
+    ).then(([ userName, space ]) => {
38
+        const { allocated, used } = space;
39
+
40
+        return {
41
+            userName,
42
+            spaceLeft: Math.floor((allocated - used) / 1048576)// 1MiB=1048576B
43
+        };
44
+
45
+    }, error => {
46
+        logger.error(error);
47
+
48
+        return undefined;
49
+    });
50
+}

+ 0
- 39
react/features/dropbox/functions.js Parādīt failu

@@ -1,39 +0,0 @@
1
-// @flow
2
-
3
-import { Dropbox } from 'dropbox';
4
-
5
-const logger = require('jitsi-meet-logger').getLogger(__filename);
6
-
7
-/**
8
- * Fetches information about the user's dropbox account.
9
- *
10
- * @param {string} token - The dropbox access token.
11
- * @param {string} clientId - The Jitsi Recorder dropbox app ID.
12
- * @returns {Promise<Object|undefined>}
13
- */
14
-export function getDropboxData(
15
-        token: string,
16
-        clientId: string
17
-): Promise<?Object> {
18
-    const dropboxAPI = new Dropbox({
19
-        accessToken: token,
20
-        clientId
21
-    });
22
-
23
-    return Promise.all(
24
-        [ dropboxAPI.usersGetCurrentAccount(), dropboxAPI.usersGetSpaceUsage() ]
25
-    ).then(([ account, space ]) => {
26
-        const { allocation, used } = space;
27
-        const { allocated } = allocation;
28
-
29
-        return {
30
-            userName: account.name.display_name,
31
-            spaceLeft: Math.floor((allocated - used) / 1048576)// 1MiB=1048576B
32
-        };
33
-
34
-    }, error => {
35
-        logger.error(error);
36
-
37
-        return undefined;
38
-    });
39
-}

+ 52
- 0
react/features/dropbox/functions.native.js Parādīt failu

@@ -0,0 +1,52 @@
1
+// @flow
2
+
3
+import { NativeModules } from 'react-native';
4
+
5
+const { Dropbox } = NativeModules;
6
+
7
+/**
8
+ * Returns the display name for the current dropbox account.
9
+ *
10
+ * @param {string} token - The dropbox access token.
11
+ * @returns {Promise<string>} - The promise will be resolved with the display
12
+ * name or rejected with an error.
13
+ */
14
+export function getDisplayName(token: string) {
15
+    return Dropbox.getDisplayName(token);
16
+}
17
+
18
+/**
19
+ * Returns information about the space usage for the current dropbox account.
20
+ *
21
+ * @param {string} token - The dropbox access token.
22
+ * @returns {Promise<{ used: number, allocated: number}>} - The promise will be
23
+ * resolved with the object with information about the space usage (the used
24
+ * space and the allocated space) for the current dropbox account or rejected
25
+ * with an error.
26
+ */
27
+export function getSpaceUsage(token: string) {
28
+    return Dropbox.getSpaceUsage(token);
29
+}
30
+
31
+
32
+/**
33
+ * Action to authorize the Jitsi Recording app in dropbox.
34
+ *
35
+ * @param {string} clientId - The Jitsi Recorder dropbox app ID.
36
+ * @param {string} redirectURI - The return URL.
37
+ * @returns {Promise<string>} - The promise will be resolved with the dropbox
38
+ * access token or rejected with an error.
39
+ */
40
+export function _authorizeDropbox(): Promise<string> {
41
+    return Dropbox.authorize();
42
+}
43
+
44
+/**
45
+ * Returns <tt>true</tt> if the dropbox features is enabled and <tt>false</tt>
46
+ * otherwise.
47
+ *
48
+ * @returns {boolean}
49
+ */
50
+export function isEnabled() {
51
+    return Dropbox.ENABLED;
52
+}

+ 112
- 0
react/features/dropbox/functions.web.js Parādīt failu

@@ -0,0 +1,112 @@
1
+// @flow
2
+
3
+import { Dropbox } from 'dropbox';
4
+
5
+import {
6
+    getJitsiMeetGlobalNS,
7
+    parseStandardURIString
8
+} from '../base/util';
9
+import { parseURLParams } from '../base/config';
10
+
11
+/**
12
+ * Returns the display name for the current dropbox account.
13
+ *
14
+ * @param {string} token - The dropbox access token.
15
+ * @param {string} clientId - The Jitsi Recorder dropbox app ID.
16
+ * @returns {Promise<string>}
17
+ */
18
+export function getDisplayName(token: string, clientId: string) {
19
+    const dropboxAPI = new Dropbox({
20
+        accessToken: token,
21
+        clientId
22
+    });
23
+
24
+    return (
25
+        dropboxAPI.usersGetCurrentAccount()
26
+            .then(account => account.name.display_name));
27
+}
28
+
29
+/**
30
+ * Returns information about the space usage for the current dropbox account.
31
+ *
32
+ * @param {string} token - The dropbox access token.
33
+ * @param {string} clientId - The Jitsi Recorder dropbox app ID.
34
+ * @returns {Promise<Object>}
35
+ */
36
+export function getSpaceUsage(token: string, clientId: string) {
37
+    const dropboxAPI = new Dropbox({
38
+        accessToken: token,
39
+        clientId
40
+    });
41
+
42
+    return dropboxAPI.usersGetSpaceUsage().then(space => {
43
+        const { allocation, used } = space;
44
+        const { allocated } = allocation;
45
+
46
+        return {
47
+            used,
48
+            allocated
49
+        };
50
+    });
51
+}
52
+
53
+
54
+/**
55
+ * Executes the oauth flow.
56
+ *
57
+ * @param {string} authUrl - The URL to oauth service.
58
+ * @returns {Promise<string>} - The URL with the authorization details.
59
+ */
60
+function authorize(authUrl: string): Promise<string> {
61
+    const windowName = `oauth${Date.now()}`;
62
+    const gloabalNS = getJitsiMeetGlobalNS();
63
+
64
+    gloabalNS.oauthCallbacks = gloabalNS.oauthCallbacks || {};
65
+
66
+    return new Promise(resolve => {
67
+        const popup = window.open(authUrl, windowName);
68
+
69
+        gloabalNS.oauthCallbacks[windowName] = () => {
70
+            const returnURL = popup.location.href;
71
+
72
+            popup.close();
73
+            delete gloabalNS.oauthCallbacks.windowName;
74
+            resolve(returnURL);
75
+        };
76
+    });
77
+}
78
+
79
+/**
80
+ * Action to authorize the Jitsi Recording app in dropbox.
81
+ *
82
+ * @param {string} clientId - The Jitsi Recorder dropbox app ID.
83
+ * @param {string} redirectURI - The return URL.
84
+ * @returns {Promise<string>}
85
+ */
86
+export function _authorizeDropbox(
87
+        clientId: string,
88
+        redirectURI: string
89
+): Promise<string> {
90
+    const dropboxAPI = new Dropbox({ clientId });
91
+    const url = dropboxAPI.getAuthenticationUrl(redirectURI);
92
+
93
+    return authorize(url).then(returnUrl => {
94
+        const params
95
+            = parseURLParams(parseStandardURIString(returnUrl), true) || {};
96
+
97
+        return params.access_token;
98
+    });
99
+}
100
+
101
+/**
102
+ * Returns <tt>true</tt> if the dropbox features is enabled and <tt>false</tt>
103
+ * otherwise.
104
+ *
105
+ * @param {Object} state - The redux state.
106
+ * @returns {boolean}
107
+ */
108
+export function isEnabled(state: Object) {
109
+    const { dropbox = {} } = state['features/base/config'];
110
+
111
+    return typeof dropbox.clientId === 'string';
112
+}

+ 1
- 1
react/features/dropbox/index.js Parādīt failu

@@ -1,4 +1,4 @@
1 1
 export * from './actions';
2
-export * from './functions';
2
+export * from './functions.any';
3 3
 
4 4
 import './reducer';

+ 2
- 2
react/features/recording/components/Recording/AbstractRecordButton.js Parādīt failu

@@ -11,6 +11,7 @@ import {
11 11
     getLocalParticipant,
12 12
     isLocalParticipantModerator
13 13
 } from '../../../base/participants';
14
+import { isEnabled as isDropboxEnabled } from '../../../dropbox';
14 15
 import {
15 16
     AbstractButton,
16 17
     type AbstractButtonProps
@@ -123,7 +124,6 @@ export function _mapStateToProps(state: Object, ownProps: Props): Object {
123 124
         // its own to be visible or not.
124 125
         const isModerator = isLocalParticipantModerator(state);
125 126
         const {
126
-            dropbox = {},
127 127
             enableFeaturesBasedOnToken,
128 128
             fileRecordingsEnabled
129 129
         } = state['features/base/config'];
@@ -131,7 +131,7 @@ export function _mapStateToProps(state: Object, ownProps: Props): Object {
131 131
 
132 132
         visible = isModerator
133 133
             && fileRecordingsEnabled
134
-            && typeof dropbox.clientId === 'string';
134
+            && isDropboxEnabled(state);
135 135
 
136 136
         if (enableFeaturesBasedOnToken) {
137 137
             visible = visible && String(features.recording) === 'true';

+ 3
- 1
react/features/recording/components/Recording/StartRecordingDialog.js Parādīt failu

@@ -222,8 +222,10 @@ class StartRecordingDialog extends Component<Props, State> {
222 222
  * }}
223 223
  */
224 224
 function mapStateToProps(state: Object) {
225
+    const { dropbox = {} } = state['features/base/config'];
226
+
225 227
     return {
226
-        _clientId: state['features/base/config'].dropbox.clientId,
228
+        _clientId: dropbox.clientId,
227 229
         _conference: state['features/base/conference'].conference,
228 230
         _token: state['features/dropbox'].token
229 231
     };

+ 216
- 0
react/features/recording/components/Recording/StartRecordingDialogContent.js Parādīt failu

@@ -0,0 +1,216 @@
1
+// @flow
2
+
3
+import React, { Component } from 'react';
4
+import { connect } from 'react-redux';
5
+
6
+import {
7
+    createRecordingDialogEvent,
8
+    sendAnalytics
9
+} from '../../../analytics';
10
+import { translate } from '../../../base/i18n';
11
+import {
12
+    Container,
13
+    LoadingIndicator,
14
+    Switch,
15
+    Text
16
+} from '../../../base/react';
17
+import { authorizeDropbox, updateDropboxToken } from '../../../dropbox';
18
+
19
+import styles from './styles';
20
+import { getRecordingDurationEstimation } from '../../functions';
21
+
22
+type Props = {
23
+
24
+    /**
25
+     * The redux dispatch function.
26
+     */
27
+    dispatch: Function,
28
+
29
+    /**
30
+     * <tt>true</tt> if we have valid oauth token.
31
+     */
32
+    isTokenValid: boolean,
33
+
34
+    /**
35
+     * <tt>true</tt> if we are in process of validating the oauth token.
36
+     */
37
+    isValidating: boolean,
38
+
39
+    /**
40
+     * Number of MiB of available space in user's Dropbox account.
41
+     */
42
+    spaceLeft: ?number,
43
+
44
+    /**
45
+     * The translate function.
46
+     */
47
+    t: Function,
48
+
49
+    /**
50
+     * The display name of the user's Dropbox account.
51
+     */
52
+    userName: ?string,
53
+};
54
+
55
+/**
56
+ * React Component for getting confirmation to start a file recording session.
57
+ *
58
+ * @extends Component
59
+ */
60
+class StartRecordingDialogContent extends Component<Props> {
61
+    /**
62
+     * Initializes a new {@code StartRecordingDialogContent} instance.
63
+     *
64
+     * @inheritdoc
65
+     */
66
+    constructor(props) {
67
+        super(props);
68
+
69
+        // Bind event handler so it is only bound once for every instance.
70
+        this._signIn = this._signIn.bind(this);
71
+        this._signOut = this._signOut.bind(this);
72
+        this._onSwitchChange = this._onSwitchChange.bind(this);
73
+    }
74
+
75
+    /**
76
+     * Renders the component.
77
+     *
78
+     * @protected
79
+     * @returns {React$Component}
80
+     */
81
+    render() {
82
+        const { isTokenValid, isValidating, t } = this.props;
83
+
84
+        let content = null;
85
+
86
+        if (isValidating) {
87
+            content = this._renderSpinner();
88
+        } else if (isTokenValid) {
89
+            content = this._renderSignOut();
90
+        }
91
+
92
+        // else { // Sign in screen:
93
+        // We don't need to render any additional information.
94
+        // }
95
+
96
+        return (
97
+            <Container
98
+                className = 'recording-dialog'
99
+                style = { styles.container }>
100
+                <Container
101
+                    className = 'recording-header'
102
+                    style = { styles.header }>
103
+                    <Text
104
+                        className = 'recording-title'
105
+                        style = { styles.title }>
106
+                        { t('recording.authDropboxText') }
107
+                    </Text>
108
+                    <Switch
109
+                        disabled = { isValidating }
110
+                        onValueChange = { this._onSwitchChange }
111
+                        style = { styles.switch }
112
+                        value = { isTokenValid } />
113
+                </Container>
114
+                <Container
115
+                    className = 'authorization-panel'>
116
+                    { content }
117
+                </Container>
118
+            </Container>
119
+        );
120
+    }
121
+
122
+    _onSwitchChange: boolean => void;
123
+
124
+    /**
125
+     * Handler for onValueChange events from the Switch component.
126
+     *
127
+     * @returns {void}
128
+     */
129
+    _onSwitchChange() {
130
+        if (this.props.isTokenValid) {
131
+            this._signOut();
132
+        } else {
133
+            this._signIn();
134
+        }
135
+    }
136
+
137
+    /**
138
+     * Renders a spinner component.
139
+     *
140
+     * @returns {React$Component}
141
+     */
142
+    _renderSpinner() {
143
+        return (
144
+            <LoadingIndicator
145
+                isCompleting = { false }
146
+                size = 'medium' />
147
+        );
148
+    }
149
+
150
+    /**
151
+     * Renders the screen with the account information of a logged in user.
152
+     *
153
+     * @returns {React$Component}
154
+     */
155
+    _renderSignOut() {
156
+        const { spaceLeft, t, userName } = this.props;
157
+        const duration = getRecordingDurationEstimation(spaceLeft);
158
+
159
+        return (
160
+            <Container>
161
+                <Container
162
+                    className = 'logged-in-panel'
163
+                    style = { styles.loggedIn }>
164
+                    <Container>
165
+                        <Text>
166
+                            { t('recording.loggedIn', { userName }) }
167
+                        </Text>
168
+                    </Container>
169
+                    <Container>
170
+                        <Text>
171
+                            {
172
+                                t('recording.availableSpace', {
173
+                                    spaceLeft,
174
+                                    duration
175
+                                })
176
+                            }
177
+                        </Text>
178
+                    </Container>
179
+                </Container>
180
+                <Container style = { styles.startRecordingText }>
181
+                    <Text>{ t('recording.startRecordingBody') }</Text>
182
+                </Container>
183
+            </Container>
184
+        );
185
+    }
186
+
187
+    _signIn: () => {};
188
+
189
+    /**
190
+     * Sings in a user.
191
+     *
192
+     * @returns {void}
193
+     */
194
+    _signIn() {
195
+        sendAnalytics(
196
+            createRecordingDialogEvent('start', 'signIn.button')
197
+        );
198
+        this.props.dispatch(authorizeDropbox());
199
+    }
200
+
201
+    _signOut: () => {};
202
+
203
+    /**
204
+     * Sings out an user from dropbox.
205
+     *
206
+     * @returns {void}
207
+     */
208
+    _signOut() {
209
+        sendAnalytics(
210
+            createRecordingDialogEvent('start', 'signOut.button')
211
+        );
212
+        this.props.dispatch(updateDropboxToken());
213
+    }
214
+}
215
+
216
+export default translate(connect()(StartRecordingDialogContent));

+ 0
- 38
react/features/recording/components/Recording/StartRecordingDialogContent.native.js Parādīt failu

@@ -1,38 +0,0 @@
1
-// @flow
2
-
3
-import React, { Component } from 'react';
4
-
5
-import { DialogContent } from '../../../base/dialog';
6
-import { translate } from '../../../base/i18n';
7
-
8
-type Props = {
9
-
10
-    /**
11
-     * Invoked to obtain translated strings.
12
-     */
13
-    t: Function
14
-};
15
-
16
-/**
17
- * React Component for getting confirmation to start a file recording session.
18
- *
19
- * @extends Component
20
- */
21
-class StartRecordingDialogContent extends Component<Props> {
22
-    /**
23
-     * Renders the platform specific dialog content.
24
-     *
25
-     * @returns {void}
26
-     */
27
-    render() {
28
-        const { t } = this.props;
29
-
30
-        return (
31
-            <DialogContent>
32
-                { t('recording.startRecordingBody') }
33
-            </DialogContent>
34
-        );
35
-    }
36
-}
37
-
38
-export default translate(StartRecordingDialogContent);

+ 0
- 194
react/features/recording/components/Recording/StartRecordingDialogContent.web.js Parādīt failu

@@ -1,194 +0,0 @@
1
-// @flow
2
-
3
-import Spinner from '@atlaskit/spinner';
4
-import React, { Component } from 'react';
5
-import { connect } from 'react-redux';
6
-
7
-import {
8
-    createRecordingDialogEvent,
9
-    sendAnalytics
10
-} from '../../../analytics';
11
-import { translate } from '../../../base/i18n';
12
-import { authorizeDropbox, updateDropboxToken } from '../../../dropbox';
13
-
14
-type Props = {
15
-
16
-    /**
17
-     * The redux dispatch function.
18
-     */
19
-    dispatch: Function,
20
-
21
-    /**
22
-     * <tt>true</tt> if we have valid oauth token.
23
-     */
24
-    isTokenValid: boolean,
25
-
26
-    /**
27
-     * <tt>true</tt> if we are in process of validating the oauth token.
28
-     */
29
-    isValidating: boolean,
30
-
31
-    /**
32
-     * Number of MiB of available space in user's Dropbox account.
33
-     */
34
-    spaceLeft: ?number,
35
-
36
-    /**
37
-     * The translate function.
38
-     */
39
-    t: Function,
40
-
41
-    /**
42
-     * The display name of the user's Dropbox account.
43
-     */
44
-    userName: ?string,
45
-};
46
-
47
-/**
48
- * React Component for getting confirmation to start a file recording session.
49
- *
50
- * @extends Component
51
- */
52
-class StartRecordingDialogContent extends Component<Props> {
53
-    /**
54
-     * Initializes a new {@code StartRecordingDialogContent} instance.
55
-     *
56
-     * @inheritdoc
57
-     */
58
-    constructor(props) {
59
-        super(props);
60
-
61
-        // Bind event handler so it is only bound once for every instance.
62
-        this._onSignInClick = this._onSignInClick.bind(this);
63
-        this._onSignOutClick = this._onSignOutClick.bind(this);
64
-    }
65
-
66
-    /**
67
-     * Renders the platform specific dialog content.
68
-     *
69
-     * @protected
70
-     * @returns {React$Component}
71
-     */
72
-    render() {
73
-        const { isTokenValid, isValidating, t } = this.props;
74
-
75
-        let content = null;
76
-
77
-        if (isValidating) {
78
-            content = this._renderSpinner();
79
-        } else if (isTokenValid) {
80
-            content = this._renderSignOut();
81
-        } else {
82
-            content = this._renderSignIn();
83
-        }
84
-
85
-        return (
86
-            <div className = 'recording-dialog'>
87
-                <div className = 'authorization-panel'>
88
-                    { content }
89
-                </div>
90
-                <div>{ t('recording.startRecordingBody') }</div>
91
-            </div>
92
-        );
93
-    }
94
-
95
-    /**
96
-     * Renders a spinner component.
97
-     *
98
-     * @returns {React$Component}
99
-     */
100
-    _renderSpinner() {
101
-        return (
102
-            <Spinner
103
-                isCompleting = { false }
104
-                size = 'medium' />
105
-        );
106
-    }
107
-
108
-    /**
109
-     * Renders the sign in screen.
110
-     *
111
-     * @returns {React$Component}
112
-     */
113
-    _renderSignIn() {
114
-        const { t } = this.props;
115
-
116
-        return (
117
-            <div>
118
-                <div>{ t('recording.authDropboxText') }</div>
119
-                <div
120
-                    className = 'dropbox-sign-in'
121
-                    onClick = { this._onSignInClick }>
122
-                    <img
123
-                        className = 'dropbox-logo'
124
-                        src = 'images/dropboxLogo.svg' />
125
-                    <span>{ t('recording.signIn') }</span>
126
-                </div>
127
-            </div>
128
-        );
129
-    }
130
-
131
-    /**
132
-     * Renders the screen with the account information of a logged in user.
133
-     *
134
-     * @returns {React$Component}
135
-     */
136
-    _renderSignOut() {
137
-        const { spaceLeft, t, userName } = this.props;
138
-
139
-        return (
140
-            <div>
141
-                <div>{ t('recording.authDropboxCompletedText') }</div>
142
-                <div className = 'logged-in-panel'>
143
-                    <div>
144
-                        { t('recording.loggedIn', { userName }) }&nbsp;(&nbsp;
145
-                        <a onClick = { this._onSignOutClick }>
146
-                            { t('recording.signOut') }
147
-                        </a>
148
-                        &nbsp;)
149
-                    </div>
150
-                    <div>
151
-                        {
152
-                            t('recording.availableSpace', {
153
-                                spaceLeft,
154
-
155
-                                // assuming 1min -> 10MB recording:
156
-                                duration: Math.floor((spaceLeft || 0) / 10)
157
-                            })
158
-                        }
159
-                    </div>
160
-                </div>
161
-            </div>
162
-        );
163
-    }
164
-
165
-    _onSignInClick: () => {};
166
-
167
-    /**
168
-     * Handles click events for the dropbox sign in button.
169
-     *
170
-     * @returns {void}
171
-     */
172
-    _onSignInClick() {
173
-        sendAnalytics(
174
-            createRecordingDialogEvent('start', 'signIn.button')
175
-        );
176
-        this.props.dispatch(authorizeDropbox());
177
-    }
178
-
179
-    _onSignOutClick: () => {};
180
-
181
-    /**
182
-     * Sings out an user from dropbox.
183
-     *
184
-     * @returns {void}
185
-     */
186
-    _onSignOutClick() {
187
-        sendAnalytics(
188
-            createRecordingDialogEvent('start', 'signOut.button')
189
-        );
190
-        this.props.dispatch(updateDropboxToken());
191
-    }
192
-}
193
-
194
-export default translate(connect()(StartRecordingDialogContent));

+ 43
- 0
react/features/recording/components/Recording/styles.native.js Parādīt failu

@@ -0,0 +1,43 @@
1
+// @flow
2
+
3
+import { BoxModel, createStyleSheet } from '../../../base/styles';
4
+
5
+// XXX The "standard" {@code BoxModel.padding} has been deemed insufficient in
6
+// the special case(s) of the recording feature bellow.
7
+const _PADDING = BoxModel.padding * 1.5;
8
+
9
+/**
10
+ * The styles of the React {@code Components} of the feature recording.
11
+ */
12
+export default createStyleSheet({
13
+    container: {
14
+        flex: 0,
15
+        flexDirection: 'column'
16
+    },
17
+
18
+    header: {
19
+        alignItems: 'center',
20
+        flex: 0,
21
+        flexDirection: 'row',
22
+        justifyContent: 'space-between',
23
+        paddingBottom: _PADDING,
24
+        paddingTop: _PADDING
25
+    },
26
+
27
+    loggedIn: {
28
+        paddingBottom: _PADDING
29
+    },
30
+
31
+    startRecordingText: {
32
+        paddingBottom: _PADDING
33
+    },
34
+
35
+    switch: {
36
+        paddingRight: BoxModel.padding
37
+    },
38
+
39
+    title: {
40
+        fontSize: 16,
41
+        fontWeight: 'bold'
42
+    }
43
+});

+ 3
- 0
react/features/recording/components/Recording/styles.web.js Parādīt failu

@@ -0,0 +1,3 @@
1
+// XXX CSS is used on Web, JavaScript styles are use only for mobile. Export an
2
+// (empty) object so that styles[*] statements on Web don't trigger errors.
3
+export default {};

+ 12
- 0
react/features/recording/functions.js Parādīt failu

@@ -19,6 +19,18 @@ export function getActiveSession(state: Object, mode: string) {
19 19
             || sessionData.status === statusConstants.PENDING));
20 20
 }
21 21
 
22
+/**
23
+ * Returns an estimated recording duration based on the size of the video file
24
+ * in MB. The estimate is calculated under the assumption that 1 min of recorded
25
+ * video needs 10MB of storage on avarage.
26
+ *
27
+ * @param {number} size - The size in MB of the recorded video.
28
+ * @returns {number} - The estimated duration in minutes.
29
+ */
30
+export function getRecordingDurationEstimation(size: ?number) {
31
+    return Math.floor((size || 0) / 10);
32
+}
33
+
22 34
 /**
23 35
  * Searches in the passed in redux state for a recording session that matches
24 36
  * the passed in recording session ID.

Notiek ielāde…
Atcelt
Saglabāt