瀏覽代碼

feat)rn,sdk) introduce a "ready to close" event

This event is the event host applications need to listen to for knowing when to
dispose the SDK from now on.

Since the introduction of breakout rooms it's possible that we navigate from one
meeting to another, so there will be several conference join / terminations.

In addition, local track destruction is now moved to SET_ROOM when there is no
room, aka, we are going back to the welcome page or to the black page.
master
Saúl Ibarra Corretgé 3 年之前
父節點
當前提交
d7b581e338

+ 0
- 5
android/app/src/main/java/org/jitsi/meet/MainActivity.java 查看文件

182
         }
182
         }
183
     }
183
     }
184
 
184
 
185
-    @Override
186
-    protected void onConferenceTerminated(HashMap<String, Object> extraData) {
187
-        Log.d(TAG, "Conference terminated: " + extraData);
188
-    }
189
-
190
     // Activity lifecycle method overrides
185
     // Activity lifecycle method overrides
191
     //
186
     //
192
 
187
 

+ 4
- 1
android/sdk/src/main/java/org/jitsi/meet/sdk/BroadcastEvent.java 查看文件

87
         CHAT_MESSAGE_RECEIVED("org.jitsi.meet.CHAT_MESSAGE_RECEIVED"),
87
         CHAT_MESSAGE_RECEIVED("org.jitsi.meet.CHAT_MESSAGE_RECEIVED"),
88
         CHAT_TOGGLED("org.jitsi.meet.CHAT_TOGGLED"),
88
         CHAT_TOGGLED("org.jitsi.meet.CHAT_TOGGLED"),
89
         VIDEO_MUTED_CHANGED("org.jitsi.meet.VIDEO_MUTED_CHANGED");
89
         VIDEO_MUTED_CHANGED("org.jitsi.meet.VIDEO_MUTED_CHANGED");
90
-
90
+        READY_TO_CLOSE("org.jitsi.meet.READY_TO_CLOSE");
91
 
91
 
92
         private static final String CONFERENCE_WILL_JOIN_NAME = "CONFERENCE_WILL_JOIN";
92
         private static final String CONFERENCE_WILL_JOIN_NAME = "CONFERENCE_WILL_JOIN";
93
         private static final String CONFERENCE_JOINED_NAME = "CONFERENCE_JOINED";
93
         private static final String CONFERENCE_JOINED_NAME = "CONFERENCE_JOINED";
101
         private static final String CHAT_MESSAGE_RECEIVED_NAME = "CHAT_MESSAGE_RECEIVED";
101
         private static final String CHAT_MESSAGE_RECEIVED_NAME = "CHAT_MESSAGE_RECEIVED";
102
         private static final String CHAT_TOGGLED_NAME = "CHAT_TOGGLED";
102
         private static final String CHAT_TOGGLED_NAME = "CHAT_TOGGLED";
103
         private static final String VIDEO_MUTED_CHANGED_NAME = "VIDEO_MUTED_CHANGED";
103
         private static final String VIDEO_MUTED_CHANGED_NAME = "VIDEO_MUTED_CHANGED";
104
+        private static final String READY_TO_CLOSE_NAME = "READY_TO_CLOSE";
104
 
105
 
105
         private final String action;
106
         private final String action;
106
 
107
 
147
                     return CHAT_TOGGLED;
148
                     return CHAT_TOGGLED;
148
                 case VIDEO_MUTED_CHANGED_NAME:
149
                 case VIDEO_MUTED_CHANGED_NAME:
149
                     return VIDEO_MUTED_CHANGED;
150
                     return VIDEO_MUTED_CHANGED;
151
+                case READY_TO_CLOSE_NAME:
152
+                    return READY_TO_CLOSE;
150
             }
153
             }
151
 
154
 
152
             return null;
155
             return null;

+ 8
- 1
android/sdk/src/main/java/org/jitsi/meet/sdk/JitsiMeetActivity.java 查看文件

194
 
194
 
195
     protected void onConferenceTerminated(HashMap<String, Object> extraData) {
195
     protected void onConferenceTerminated(HashMap<String, Object> extraData) {
196
         JitsiMeetLogger.i("Conference terminated: " + extraData);
196
         JitsiMeetLogger.i("Conference terminated: " + extraData);
197
-        finish();
198
     }
197
     }
199
 
198
 
200
     protected void onConferenceWillJoin(HashMap<String, Object> extraData) {
199
     protected void onConferenceWillJoin(HashMap<String, Object> extraData) {
217
         }
216
         }
218
     }
217
     }
219
 
218
 
219
+    protected void onReadyToClose() {
220
+        JitsiMeetLogger.i("SDK is ready to close");
221
+        finish();
222
+    }
223
+
220
     // Activity lifecycle methods
224
     // Activity lifecycle methods
221
     //
225
     //
222
 
226
 
298
                 case PARTICIPANT_LEFT:
302
                 case PARTICIPANT_LEFT:
299
                     onParticipantLeft(event.getData());
303
                     onParticipantLeft(event.getData());
300
                     break;
304
                     break;
305
+                case READY_TO_CLOSE:
306
+                    onReadyToClose();
307
+                    break;
301
             }
308
             }
302
         }
309
         }
303
     }
310
     }

+ 4
- 1
ios/app/src/ViewController.m 查看文件

91
 #if 0
91
 #if 0
92
 - (void)enterPictureInPicture:(NSDictionary *)data {
92
 - (void)enterPictureInPicture:(NSDictionary *)data {
93
     [self _onJitsiMeetViewDelegateEvent:@"ENTER_PICTURE_IN_PICTURE" withData:data];
93
     [self _onJitsiMeetViewDelegateEvent:@"ENTER_PICTURE_IN_PICTURE" withData:data];
94
-
95
 }
94
 }
96
 #endif
95
 #endif
97
 
96
 
97
+- (void)readyToClose:(NSDictionary *)data {
98
+    [self _onJitsiMeetViewDelegateEvent:@"READY_TO_CLOSE" withData:data];
99
+}
100
+
98
 - (void)participantJoined:(NSDictionary *)data {
101
 - (void)participantJoined:(NSDictionary *)data {
99
   NSLog(@"%@%@", @"Participant joined: ", data[@"participantId"]);
102
   NSLog(@"%@%@", @"Participant joined: ", data[@"participantId"]);
100
 }
103
 }

+ 5
- 0
ios/sdk/src/JitsiMeetViewDelegate.h 查看文件

111
  */
111
  */
112
 - (void)videoMutedChanged:(NSDictionary *)data;
112
 - (void)videoMutedChanged:(NSDictionary *)data;
113
 
113
 
114
+/**
115
+ * Called when the SDK is ready to be closed. No meeting is happening at this point.
116
+ */
117
+- (void)readyToClose:(NSDictionary *)data;
118
+
114
 @end
119
 @end

+ 3
- 0
lang/main.json 查看文件

39
     "audioOnly": {
39
     "audioOnly": {
40
         "audioOnly": "Low bandwidth"
40
         "audioOnly": "Low bandwidth"
41
     },
41
     },
42
+    "blankPage": {
43
+        "meetingEnded": "Meeting ended."
44
+    },
42
     "breakoutRooms": {
45
     "breakoutRooms": {
43
         "defaultName": "Breakout room #{{index}}",
46
         "defaultName": "Breakout room #{{index}}",
44
         "mainRoom": "Main room",
47
         "mainRoom": "Main room",

+ 0
- 3
react/features/base/color-scheme/defaultScheme.js 查看文件

43
     'LargeVideo': {
43
     'LargeVideo': {
44
         background: '#040404'
44
         background: '#040404'
45
     },
45
     },
46
-    'LoadConfigOverlay': {
47
-        background: 'rgb(249, 249, 249)'
48
-    },
49
     'Thumbnail': {
46
     'Thumbnail': {
50
         activeParticipantHighlight: 'rgb(81, 214, 170)',
47
         activeParticipantHighlight: 'rgb(81, 214, 170)',
51
         activeParticipantTint: 'rgba(49, 183, 106, 0.3)',
48
         activeParticipantTint: 'rgba(49, 183, 106, 0.3)',

+ 10
- 1
react/features/base/media/middleware.js 查看文件

14
 import { getLocalParticipant } from '../participants';
14
 import { getLocalParticipant } from '../participants';
15
 import { MiddlewareRegistry } from '../redux';
15
 import { MiddlewareRegistry } from '../redux';
16
 import { getPropertyValue } from '../settings';
16
 import { getPropertyValue } from '../settings';
17
-import { isLocalVideoTrackDesktop, setTrackMuted, TRACK_ADDED } from '../tracks';
17
+import {
18
+    destroyLocalTracks,
19
+    isLocalVideoTrackDesktop,
20
+    setTrackMuted,
21
+    TRACK_ADDED
22
+} from '../tracks';
18
 
23
 
19
 import { SET_AUDIO_MUTED, SET_VIDEO_MUTED } from './actionTypes';
24
 import { SET_AUDIO_MUTED, SET_VIDEO_MUTED } from './actionTypes';
20
 import { setAudioMuted, setCameraFacingMode, setVideoMuted } from './actions';
25
 import { setAudioMuted, setCameraFacingMode, setVideoMuted } from './actions';
217
 
222
 
218
     dispatch(setAudioOnly(audioOnly, false));
223
     dispatch(setAudioOnly(audioOnly, false));
219
 
224
 
225
+    if (!roomIsValid) {
226
+        dispatch(destroyLocalTracks());
227
+    }
228
+
220
     return next(action);
229
     return next(action);
221
 }
230
 }
222
 
231
 

+ 9
- 0
react/features/mobile/external-api/actionTypes.js 查看文件

1
+/**
2
+ * The type of the action which indicates the SDK is ready to be closed.
3
+ *
4
+ * @returns {{
5
+ *     type: READY_TO_CLOSE
6
+ * }}
7
+ */
8
+export const READY_TO_CLOSE = 'READY_TO_CLOSE';
9
+
1
 /**
10
 /**
2
  * The type of the action which sets the list of known participant IDs which
11
  * The type of the action which sets the list of known participant IDs which
3
  * have an active screen share.
12
  * have an active screen share.

+ 21
- 5
react/features/mobile/external-api/actions.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
-import { SCREEN_SHARE_PARTICIPANTS_UPDATED } from './actionTypes';
3
+import {
4
+    READY_TO_CLOSE,
5
+    SCREEN_SHARE_PARTICIPANTS_UPDATED
6
+} from './actionTypes';
7
+
8
+/**
9
+ * Creates a (redux) action which signals that the SDK is ready to be closed.
10
+ *
11
+ * @returns {{
12
+ *     type: READY_TO_CLOSE
13
+ * }}
14
+ */
15
+export function readyToClose() {
16
+    return {
17
+        type: READY_TO_CLOSE
18
+    };
19
+}
4
 
20
 
5
 /**
21
 /**
6
  * Creates a (redux) action which signals that the list of known participants
22
  * Creates a (redux) action which signals that the list of known participants
9
  * @param {string} participantIds - The participants which currently have active
25
  * @param {string} participantIds - The participants which currently have active
10
  * screen share streams.
26
  * screen share streams.
11
  * @returns {{
27
  * @returns {{
12
-    *     type: SCREEN_SHARE_PARTICIPANTS_UPDATED,
13
-    *     participantId: string
14
-    * }}
15
-    */
28
+ *     type: SCREEN_SHARE_PARTICIPANTS_UPDATED,
29
+ *     participantId: string
30
+ * }}
31
+ */
16
 export function setParticipantsWithScreenShare(participantIds: Array<string>) {
32
 export function setParticipantsWithScreenShare(participantIds: Array<string>) {
17
     return {
33
     return {
18
         type: SCREEN_SHARE_PARTICIPANTS_UPDATED,
34
         type: SCREEN_SHARE_PARTICIPANTS_UPDATED,

+ 6
- 3
react/features/mobile/external-api/middleware.js 查看文件

24
     getURLWithoutParams
24
     getURLWithoutParams
25
 } from '../../base/connection';
25
 } from '../../base/connection';
26
 import {
26
 import {
27
-    isFatalJitsiConferenceError,
28
-    isFatalJitsiConnectionError,
29
     JitsiConferenceEvents } from '../../base/lib-jitsi-meet';
27
     JitsiConferenceEvents } from '../../base/lib-jitsi-meet';
30
 import { MEDIA_TYPE } from '../../base/media';
28
 import { MEDIA_TYPE } from '../../base/media';
31
 import { SET_AUDIO_MUTED, SET_VIDEO_MUTED } from '../../base/media/actionTypes';
29
 import { SET_AUDIO_MUTED, SET_VIDEO_MUTED } from '../../base/media/actionTypes';
45
 import { muteLocal } from '../../video-menu/actions';
43
 import { muteLocal } from '../../video-menu/actions';
46
 import { ENTER_PICTURE_IN_PICTURE } from '../picture-in-picture';
44
 import { ENTER_PICTURE_IN_PICTURE } from '../picture-in-picture';
47
 
45
 
46
+import { READY_TO_CLOSE } from './actionTypes';
48
 import { setParticipantsWithScreenShare } from './actions';
47
 import { setParticipantsWithScreenShare } from './actions';
49
 import { sendEvent } from './functions';
48
 import { sendEvent } from './functions';
50
 import logger from './logger';
49
 import logger from './logger';
116
         // counterpart of the External API (or at least not in the
115
         // counterpart of the External API (or at least not in the
117
         // fatality/finality semantics attributed to
116
         // fatality/finality semantics attributed to
118
         // conferenceFailed:/onConferenceFailed).
117
         // conferenceFailed:/onConferenceFailed).
119
-        if (!error.recoverable && !isFatalJitsiConnectionError(error) && !isFatalJitsiConferenceError(error)) {
118
+        if (!error.recoverable) {
120
             _sendConferenceEvent(store, /* action */ {
119
             _sendConferenceEvent(store, /* action */ {
121
                 error: _toErrorString(error),
120
                 error: _toErrorString(error),
122
                 ...data
121
                 ...data
190
         break;
189
         break;
191
     }
190
     }
192
 
191
 
192
+    case READY_TO_CLOSE:
193
+        sendEvent(store, type, /* data */ {});
194
+        break;
195
+
193
     case SET_ROOM:
196
     case SET_ROOM:
194
         _maybeTriggerEarlyConferenceWillJoin(store, action);
197
         _maybeTriggerEarlyConferenceWillJoin(store, action);
195
         break;
198
         break;

+ 7
- 32
react/features/overlay/components/native/LoadConfigOverlay.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
-import React, { Component } from 'react';
3
+import React, { PureComponent } from 'react';
4
 import { SafeAreaView, Text, View } from 'react-native';
4
 import { SafeAreaView, Text, View } from 'react-native';
5
 
5
 
6
-import { ColorSchemeRegistry } from '../../../base/color-scheme';
7
 import { translate } from '../../../base/i18n';
6
 import { translate } from '../../../base/i18n';
8
 import { LoadingIndicator } from '../../../base/react';
7
 import { LoadingIndicator } from '../../../base/react';
9
-import { connect } from '../../../base/redux';
10
 import { StyleType } from '../../../base/styles';
8
 import { StyleType } from '../../../base/styles';
11
 
9
 
12
 import OverlayFrame from './OverlayFrame';
10
 import OverlayFrame from './OverlayFrame';
13
-import styles from './styles';
11
+import styles, { TEXT_COLOR } from './styles';
14
 
12
 
15
 type Props = {
13
 type Props = {
16
 
14
 
29
  * Implements an overlay to tell the user that there is an operation in progress in the background during connect
27
  * Implements an overlay to tell the user that there is an operation in progress in the background during connect
30
  * so then the app doesn't seem hung.
28
  * so then the app doesn't seem hung.
31
  */
29
  */
32
-class LoadConfigOverlay extends Component<Props> {
30
+class LoadConfigOverlay extends PureComponent<Props> {
33
     /**
31
     /**
34
      * Determines whether this overlay needs to be rendered (according to a
32
      * Determines whether this overlay needs to be rendered (according to a
35
      * specific redux state). Called by {@link OverlayContainer}.
33
      * specific redux state). Called by {@link OverlayContainer}.
49
      * @returns {ReactElement}
47
      * @returns {ReactElement}
50
      */
48
      */
51
     render() {
49
     render() {
52
-        const { _styles } = this.props;
53
-
54
         return (
50
         return (
55
             <OverlayFrame>
51
             <OverlayFrame>
56
-                <View
57
-                    style = { [
58
-                        styles.loadingOverlayWrapper,
59
-                        _styles.loadingOverlayWrapper
60
-                    ] }>
52
+                <View style = { styles.loadingOverlayWrapper }>
61
                     <SafeAreaView>
53
                     <SafeAreaView>
62
                         <LoadingIndicator
54
                         <LoadingIndicator
63
-                            color = { _styles.indicatorColor }
55
+                            color = { TEXT_COLOR }
64
                             size = 'large'
56
                             size = 'large'
65
                             style = { styles.connectIndicator } />
57
                             style = { styles.connectIndicator } />
66
-                        <Text
67
-                            style = { [
68
-                                styles.loadingOverlayText,
69
-                                _styles.loadingOverlayText
70
-                            ] }>
58
+                        <Text style = { styles.loadingOverlayText }>
71
                             { this.props.t('connectingOverlay.joiningRoom') }
59
                             { this.props.t('connectingOverlay.joiningRoom') }
72
                         </Text>
60
                         </Text>
73
                     </SafeAreaView>
61
                     </SafeAreaView>
77
     }
65
     }
78
 }
66
 }
79
 
67
 
80
-/**
81
- * Maps part of the Redux state to the props of this component.
82
- *
83
- * @param {Object} state - The Redux state.
84
- * @returns {{
85
- *     _styles: StyleType
86
- * }}
87
- */
88
-function _mapStateToProps(state) {
89
-    return {
90
-        _styles: ColorSchemeRegistry.get(state, 'LoadConfigOverlay')
91
-    };
92
-}
93
 
68
 
94
-export default translate(connect(_mapStateToProps)(LoadConfigOverlay));
69
+export default translate(LoadConfigOverlay);

+ 5
- 17
react/features/overlay/components/native/styles.js 查看文件

2
 
2
 
3
 import { StyleSheet } from 'react-native';
3
 import { StyleSheet } from 'react-native';
4
 
4
 
5
-import { ColorSchemeRegistry, schemeColor } from '../../../base/color-scheme';
6
 import { BoxModel, ColorPalette } from '../../../base/styles';
5
 import { BoxModel, ColorPalette } from '../../../base/styles';
6
+import BaseTheme from '../../../base/ui/components/BaseTheme.native';
7
+
8
+export const TEXT_COLOR = BaseTheme.palette.text01;
7
 
9
 
8
 /**
10
 /**
9
  * The React {@code Component} styles of the overlay feature.
11
  * The React {@code Component} styles of the overlay feature.
23
     },
25
     },
24
 
26
 
25
     loadingOverlayText: {
27
     loadingOverlayText: {
26
-        color: ColorPalette.white
28
+        color: TEXT_COLOR
27
     },
29
     },
28
 
30
 
29
     loadingOverlayWrapper: {
31
     loadingOverlayWrapper: {
30
         ...StyleSheet.absoluteFillObject,
32
         ...StyleSheet.absoluteFillObject,
31
         alignItems: 'center',
33
         alignItems: 'center',
34
+        backgroundColor: BaseTheme.palette.uiBackground,
32
         flex: 1,
35
         flex: 1,
33
         flexDirection: 'column',
36
         flexDirection: 'column',
34
         justifyContent: 'center'
37
         justifyContent: 'center'
38
         flex: 1
41
         flex: 1
39
     }
42
     }
40
 };
43
 };
41
-
42
-/**
43
- * Color schemed styles for all the component based on the abstract dialog.
44
- */
45
-ColorSchemeRegistry.register('LoadConfigOverlay', {
46
-    indicatorColor: schemeColor('text'),
47
-
48
-    loadingOverlayText: {
49
-        color: schemeColor('text')
50
-    },
51
-
52
-    loadingOverlayWrapper: {
53
-        backgroundColor: schemeColor('background')
54
-    }
55
-});

+ 21
- 67
react/features/welcome/components/BlankPage.native.js 查看文件

1
 // @flow
1
 // @flow
2
 
2
 
3
-import React, { Component } from 'react';
4
-import { View } from 'react-native';
5
-import type { Dispatch } from 'redux';
3
+import React, { useEffect } from 'react';
4
+import { useTranslation } from 'react-i18next';
5
+import { Text, View } from 'react-native';
6
+import { useDispatch } from 'react-redux';
6
 
7
 
7
-import { ColorSchemeRegistry } from '../../base/color-scheme';
8
-import { LoadingIndicator } from '../../base/react';
9
-import { connect } from '../../base/redux';
10
-import { StyleType } from '../../base/styles';
11
-import { destroyLocalTracks } from '../../base/tracks';
8
+import { readyToClose } from '../../mobile/external-api/actions';
12
 
9
 
13
 import styles from './styles';
10
 import styles from './styles';
14
 
11
 
15
-/**
16
- * The type of React {@code Component} props of {@link BlankPage}.
17
- */
18
-type Props = {
19
 
12
 
20
-    /**
21
-     * The color schemed style of the component.
22
-     */
23
-    _styles: StyleType,
13
+const BlankPage = () => {
14
+    const dispatch = useDispatch();
15
+    const { t } = useTranslation();
24
 
16
 
25
-    dispatch: Dispatch<any>
26
-};
27
-
28
-/**
29
- * The React {@code Component} displayed by {@code AbstractApp} when it has no
30
- * {@code Route} to render. Renders a progress indicator when there are ongoing
31
- * network requests.
32
- */
33
-class BlankPage extends Component<Props> {
34
     /**
17
     /**
35
      * Destroys the local tracks (if any) since no media is desired when this
18
      * Destroys the local tracks (if any) since no media is desired when this
36
      * component is rendered.
19
      * component is rendered.
37
-     *
38
-     * @inheritdoc
39
-     * @returns {void}
40
-     */
41
-    componentDidMount() {
42
-        this.props.dispatch(destroyLocalTracks());
43
-    }
44
-
45
-    /**
46
-     * Implements React's {@link Component#render()}.
47
-     *
48
-     * @inheritdoc
49
-     * @returns {ReactElement}
50
      */
20
      */
51
-    render() {
52
-        const { _styles } = this.props;
53
-
54
-        return (
55
-            <View
56
-                style = { [
57
-                    styles.blankPageWrapper,
58
-                    _styles.loadingOverlayWrapper
59
-                ] }>
60
-                <LoadingIndicator
61
-                    color = { _styles.indicatorColor }
62
-                    size = 'large' />
63
-            </View>
64
-        );
65
-    }
66
-}
67
-
68
-/**
69
- * Maps part of the Redux state to the props of this component.
70
- *
71
- * @param {Object} state - The Redux state.
72
- * @returns {Props}
73
- */
74
-function _mapStateToProps(state) {
75
-    return {
76
-        _styles: ColorSchemeRegistry.get(state, 'LoadConfigOverlay')
77
-    };
78
-}
21
+    useEffect(() => {
22
+        dispatch(readyToClose());
23
+    }, []);
24
+
25
+    return (
26
+        <View style = { styles.blankPageWrapper }>
27
+            <Text style = { styles.blankPageText }>
28
+                { t('blankPage.meetingEnded') }
29
+            </Text>
30
+        </View>
31
+    );
32
+};
79
 
33
 
80
-export default connect(_mapStateToProps)(BlankPage);
34
+export default BlankPage;

+ 0
- 4
react/features/welcome/components/WelcomePage.native.js 查看文件

18
 import JitsiStatusBar from '../../base/modal/components/JitsiStatusBar';
18
 import JitsiStatusBar from '../../base/modal/components/JitsiStatusBar';
19
 import { LoadingIndicator, Text } from '../../base/react';
19
 import { LoadingIndicator, Text } from '../../base/react';
20
 import { connect } from '../../base/redux';
20
 import { connect } from '../../base/redux';
21
-import { destroyLocalTracks } from '../../base/tracks';
22
 import BaseTheme from '../../base/ui/components/BaseTheme.native';
21
 import BaseTheme from '../../base/ui/components/BaseTheme.native';
23
 
22
 
24
 import {
23
 import {
108
 
107
 
109
         const {
108
         const {
110
             _headerStyles,
109
             _headerStyles,
111
-            dispatch,
112
             navigation
110
             navigation
113
         } = this.props;
111
         } = this.props;
114
 
112
 
129
             headerRight: () =>
127
             headerRight: () =>
130
                 <VideoSwitch />
128
                 <VideoSwitch />
131
         });
129
         });
132
-
133
-        dispatch(destroyLocalTracks());
134
     }
130
     }
135
 
131
 
136
     /**
132
     /**

+ 6
- 0
react/features/welcome/components/styles.js 查看文件

42
         marginRight: BaseTheme.spacing[2]
42
         marginRight: BaseTheme.spacing[2]
43
     },
43
     },
44
 
44
 
45
+    blankPageText: {
46
+        color: TEXT_COLOR,
47
+        fontSize: 18
48
+    },
49
+
45
     /**
50
     /**
46
      * View that is rendered when there is no welcome page.
51
      * View that is rendered when there is no welcome page.
47
      */
52
      */
48
     blankPageWrapper: {
53
     blankPageWrapper: {
49
         ...StyleSheet.absoluteFillObject,
54
         ...StyleSheet.absoluteFillObject,
50
         alignItems: 'center',
55
         alignItems: 'center',
56
+        backgroundColor: BaseTheme.palette.uiBackground,
51
         flex: 1,
57
         flex: 1,
52
         flexDirection: 'column',
58
         flexDirection: 'column',
53
         justifyContent: 'center'
59
         justifyContent: 'center'

Loading…
取消
儲存