瀏覽代碼

rn,recent-list: replace swipe options with long-press sheet

This change serves 2 purposes:

- (Hopefully) make the recent list entry options easier to discover
- Remove the (now unmaintained) swipeout dependency
j8
Saúl Ibarra Corretgé 4 年之前
父節點
當前提交
63fe1de789

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

@@ -366,7 +366,7 @@
366 366
         "password": "$t(lockRoomPasswordUppercase):",
367 367
         "title": "Share",
368 368
         "tooltip": "Share link and dial-in info for this meeting",
369
-        "label": "Meeting info"
369
+        "label": "Dial-in info"
370 370
     },
371 371
     "inviteDialog": {
372 372
         "alertText": "Failed to invite some participants.",
@@ -876,12 +876,12 @@
876 876
         "getHelp": "Get help",
877 877
         "go": "GO",
878 878
         "goSmall": "GO",
879
-        "info": "Info",
879
+        "info": "Dial-in info",
880 880
         "join": "CREATE / JOIN",
881 881
         "moderatedMessage": "Or <a href=\"{{url}}\" rel=\"noopener noreferrer\" target=\"_blank\">book a meeting URL</a> in advance where you are the only moderator.",
882 882
         "privacy": "Privacy",
883 883
         "recentList": "Recent",
884
-        "recentListDelete": "Delete",
884
+        "recentListDelete": "Delete entry",
885 885
         "recentListEmpty": "Your recent list is currently empty. Chat with your team and you will find all your recent meetings here.",
886 886
         "reducedUIText": "Welcome to {{app}}!",
887 887
         "roomNameAllowedChars": "Meeting name should not contain any of these characters: ?, &, :, ', \", %, #.",

+ 0
- 1
package.json 查看文件

@@ -81,7 +81,6 @@
81 81
     "react-native-sound": "github:jitsi/react-native-sound#3fe5480fce935e888d5089d94a191c7c7e3aa190",
82 82
     "react-native-svg": "9.7.1",
83 83
     "react-native-svg-transformer": "0.13.0",
84
-    "react-native-swipeout": "2.3.6",
85 84
     "react-native-watch-connectivity": "0.4.3",
86 85
     "react-native-webrtc": "1.84.0",
87 86
     "react-native-webview": "10.9.0",

+ 1
- 0
react/features/base/icons/svg/index.js 查看文件

@@ -91,6 +91,7 @@ export { default as IconShareVideo } from './shared-video.svg';
91 91
 export { default as IconSwitchCamera } from './switch-camera.svg';
92 92
 export { default as IconTileView } from './tiles-many.svg';
93 93
 export { default as IconToggleRecording } from './camera-take-picture.svg';
94
+export { default as IconTrash } from './trash.svg';
94 95
 export { default as IconVideoQualityAudioOnly } from './AUD.svg';
95 96
 export { default as IconVideoQualityHD } from './HD.svg';
96 97
 export { default as IconVideoQualityLD } from './LD.svg';

+ 1
- 0
react/features/base/icons/svg/trash.svg 查看文件

@@ -0,0 +1 @@
1
+<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="trash-alt" class="svg-inline--fa fa-trash-alt fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm272-256a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z"></path></svg>

+ 29
- 11
react/features/base/react/components/NavigateSectionList.js 查看文件

@@ -20,6 +20,11 @@ type Props = {
20 20
      */
21 21
     disabled: boolean,
22 22
 
23
+    /**
24
+     * Function to be invoked when an item is long pressed. The item is passed.
25
+     */
26
+    onLongPress: Function,
27
+
23 28
     /**
24 29
      * Function to be invoked when an item is pressed. The item's URL is passed.
25 30
      */
@@ -44,13 +49,7 @@ type Props = {
44 49
     /**
45 50
      * An array of sections
46 51
      */
47
-    sections: Array<Section>,
48
-
49
-    /**
50
-     * Optional array of on-slide actions this list should support. For details
51
-     * see https://github.com/dancormier/react-native-swipeout.
52
-     */
53
-    slideActions?: Array<Object>
52
+    sections: Array<Section>
54 53
 };
55 54
 
56 55
 /**
@@ -83,11 +82,11 @@ class NavigateSectionList extends Component<Props> {
83 82
     constructor(props: Props) {
84 83
         super(props);
85 84
         this._getItemKey = this._getItemKey.bind(this);
85
+        this._onLongPress = this._onLongPress.bind(this);
86 86
         this._onPress = this._onPress.bind(this);
87 87
         this._onRefresh = this._onRefresh.bind(this);
88 88
         this._renderItem = this._renderItem.bind(this);
89
-        this._renderListEmptyComponent
90
-            = this._renderListEmptyComponent.bind(this);
89
+        this._renderListEmptyComponent = this._renderListEmptyComponent.bind(this);
91 90
         this._renderSectionHeader = this._renderSectionHeader.bind(this);
92 91
     }
93 92
 
@@ -131,6 +130,25 @@ class NavigateSectionList extends Component<Props> {
131 130
         return `${index}-${item.key}`;
132 131
     }
133 132
 
133
+    _onLongPress: string => Function;
134
+
135
+    /**
136
+     * Returns a function that is used in the onLongPress callback of the items.
137
+     *
138
+     * @param {Object} item - The item that was long-pressed.
139
+     * @private
140
+     * @returns {Function}
141
+     */
142
+    _onLongPress(item) {
143
+        const { disabled, onLongPress } = this.props;
144
+
145
+        if (!disabled && typeof onLongPress === 'function') {
146
+            return () => onLongPress(item);
147
+        }
148
+
149
+        return null;
150
+    }
151
+
134 152
     _onPress: string => Function;
135 153
 
136 154
     /**
@@ -210,10 +228,10 @@ class NavigateSectionList extends Component<Props> {
210 228
             <NavigateSectionListItem
211 229
                 item = { item }
212 230
                 key = { key }
231
+                onLongPress = { url ? this._onLongPress(item) : undefined }
213 232
                 onPress = { url ? this._onPress(url) : undefined }
214 233
                 secondaryAction = {
215
-                    url ? undefined : this._onSecondaryAction(id) }
216
-                slideActions = { this.props.slideActions } />
234
+                    url ? undefined : this._onSecondaryAction(id) } />
217 235
         );
218 236
     }
219 237
 

+ 10
- 2
react/features/base/react/components/native/AvatarListItem.js 查看文件

@@ -52,6 +52,11 @@ type Props = {
52 52
      */
53 53
     linesStyle?: StyleType,
54 54
 
55
+    /**
56
+     * Function to invoke on long press.
57
+     */
58
+    onLongPress: ?Function,
59
+
55 60
     /**
56 61
      * Function to invoke on press.
57 62
      */
@@ -88,13 +93,16 @@ export default class AvatarListItem extends Component<Props> {
88 93
             avatarOnly,
89 94
             avatarSize = AVATAR_SIZE,
90 95
             avatarStatus,
91
-            avatarStyle
96
+            avatarStyle,
97
+            onLongPress,
98
+            onPress
92 99
         } = this.props;
93 100
         const { avatar, colorBase, lines, title } = this.props.item;
94 101
 
95 102
         return (
96 103
             <Container
97
-                onClick = { this.props.onPress }
104
+                onClick = { onPress }
105
+                onLongPress = { onLongPress }
98 106
                 style = { styles.listItem }
99 107
                 underlayColor = { UNDERLAY_COLOR }>
100 108
                 <Avatar

+ 13
- 38
react/features/base/react/components/native/NavigateSectionListItem.js 查看文件

@@ -1,9 +1,7 @@
1 1
 // @flow
2 2
 
3 3
 import React, { Component } from 'react';
4
-import Swipeout from 'react-native-swipeout';
5 4
 
6
-import { ColorPalette } from '../../../styles';
7 5
 import type { Item } from '../../Types';
8 6
 
9 7
 import AvatarListItem from './AvatarListItem';
@@ -19,20 +17,19 @@ type Props = {
19 17
     item: Item,
20 18
 
21 19
     /**
22
-     * Function to be invoked when an Item is pressed. The Item's URL is passed.
20
+     * Function to be invoked when an item is long pressed. The item is passed.
23 21
      */
24
-    onPress: ?Function,
22
+    onLongPress: ?Function,
25 23
 
26 24
     /**
27
-     * Function to be invoked when secondary action was performed on an Item.
25
+     * Function to be invoked when an Item is pressed. The Item's URL is passed.
28 26
      */
29
-    secondaryAction: ?Function,
27
+    onPress: ?Function,
30 28
 
31 29
     /**
32
-     * Optional array of on-slide actions this list should support. For details
33
-     * see https://github.com/dancormier/react-native-swipeout.
30
+     * Function to be invoked when secondary action was performed on an Item.
34 31
      */
35
-    slideActions?: Array<Object>
32
+    secondaryAction: ?Function
36 33
 }
37 34
 
38 35
 /**
@@ -116,37 +113,15 @@ export default class NavigateSectionListItem extends Component<Props> {
116 113
      * @returns {ReactElement}
117 114
      */
118 115
     render() {
119
-        const { item, slideActions } = this.props;
120
-        const { id } = item;
121
-        let right;
122
-
123
-        // NOTE: The {@code Swipeout} component has an onPress prop encapsulated
124
-        // in the {@code right} array, but we need to bind it to the ID of the
125
-        // item too.
126
-
127
-        if (slideActions) {
128
-            right = [];
129
-            for (const slideAction of slideActions) {
130
-                right.push({
131
-                    backgroundColor: slideAction.backgroundColor,
132
-                    onPress: slideAction.onPress.bind(undefined, id),
133
-                    text: slideAction.text
134
-                });
135
-            }
136
-        }
116
+        const { item, onLongPress, onPress, secondaryAction } = this.props;
137 117
 
138 118
         return (
139
-            <Swipeout
140
-                autoClose = { true }
141
-                backgroundColor = { ColorPalette.transparent }
142
-                right = { right }>
143
-                <AvatarListItem
144
-                    item = { item }
145
-                    onPress = { this.props.onPress } >
146
-                    { this.props.secondaryAction
147
-                            && this._renderSecondaryAction() }
148
-                </AvatarListItem>
149
-            </Swipeout>
119
+            <AvatarListItem
120
+                item = { item }
121
+                onLongPress = { onLongPress }
122
+                onPress = { onPress } >
123
+                { secondaryAction && this._renderSecondaryAction() }
124
+            </AvatarListItem>
150 125
         );
151 126
     }
152 127
 }

+ 2
- 4
react/features/calendar-sync/components/CalendarListContent.native.js 查看文件

@@ -106,7 +106,7 @@ class CalendarListContent extends Component<Props> {
106 106
         );
107 107
     }
108 108
 
109
-    _onPress: (string, ?string) => Function;
109
+    _onPress: (string, ?string) => void;
110 110
 
111 111
     /**
112 112
      * Handles the list's navigate action.
@@ -259,9 +259,7 @@ class CalendarListContent extends Component<Props> {
259 259
  * Maps redux state to component props.
260 260
  *
261 261
  * @param {Object} state - The redux state.
262
- * @returns {{
263
- *     _eventList: Array<Object>
264
- * }}
262
+ * @returns {Props}
265 263
  */
266 264
 function _mapStateToProps(state: Object) {
267 265
     return {

+ 48
- 0
react/features/recent-list/components/DeleteItemButton.native.js 查看文件

@@ -0,0 +1,48 @@
1
+// @flow
2
+
3
+import { translate } from '../../base/i18n';
4
+import { IconTrash } from '../../base/icons';
5
+import { connect } from '../../base/redux';
6
+import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
7
+import { deleteRecentListEntry } from '../actions';
8
+
9
+export type Props = AbstractButtonProps & {
10
+
11
+    /**
12
+     * The redux {@code dispatch} function.
13
+     */
14
+    dispatch: Function,
15
+
16
+    /**
17
+     * The ID of the entry to be deleted.
18
+     */
19
+    itemId: Object,
20
+
21
+    /**
22
+     * The function to be used to translate i18n labels.
23
+     */
24
+    t: Function
25
+};
26
+
27
+/**
28
+ * A recent list menu button which deletes the selected entry.
29
+ */
30
+class DeleteItemButton extends AbstractButton<Props, *> {
31
+    accessibilityLabel = 'welcomepage.recentListDelete';
32
+    icon = IconTrash;
33
+    label = 'welcomepage.recentListDelete';
34
+
35
+    /**
36
+     * Handles clicking / pressing the button.
37
+     *
38
+     * @private
39
+     * @returns {void}
40
+     */
41
+    _handleClick() {
42
+        const { dispatch, itemId } = this.props;
43
+
44
+        dispatch(deleteRecentListEntry(itemId));
45
+    }
46
+}
47
+
48
+export default translate(connect()(DeleteItemButton));

+ 13
- 39
react/features/recent-list/components/RecentList.native.js 查看文件

@@ -4,16 +4,14 @@ import React from 'react';
4 4
 import type { Dispatch } from 'redux';
5 5
 
6 6
 import { getDefaultURL } from '../../app/functions';
7
+import { openDialog } from '../../base/dialog/actions';
7 8
 import { translate } from '../../base/i18n';
8
-import { setActiveModalId } from '../../base/modal';
9 9
 import { NavigateSectionList, type Section } from '../../base/react';
10 10
 import { connect } from '../../base/redux';
11
-import { ColorPalette } from '../../base/styles';
12
-import { DIAL_IN_SUMMARY_VIEW_ID } from '../../invite/constants';
13
-import { deleteRecentListEntry } from '../actions';
14 11
 import { isRecentListEnabled, toDisplayableList } from '../functions';
15 12
 
16 13
 import AbstractRecentList from './AbstractRecentList';
14
+import RecentListItemMenu from './RecentListItemMenu.native';
17 15
 
18 16
 /**
19 17
  * The type of the React {@code Component} props of {@link RecentList}
@@ -62,8 +60,8 @@ class RecentList extends AbstractRecentList<Props> {
62 60
     constructor(props: Props) {
63 61
         super(props);
64 62
 
65
-        this._onDelete = this._onDelete.bind(this);
66
-        this._onShowDialInInfo = this._onShowDialInInfo.bind(this);
63
+        // Bind event handlers so they are only bound once per instance.
64
+        this._onLongPress = this._onLongPress.bind(this);
67 65
     }
68 66
 
69 67
     /**
@@ -82,50 +80,29 @@ class RecentList extends AbstractRecentList<Props> {
82 80
             _recentList
83 81
         } = this.props;
84 82
         const recentList = toDisplayableList(_recentList, t, _defaultServerURL);
85
-        const slideActions = [ {
86
-            backgroundColor: ColorPalette.blue,
87
-            onPress: this._onShowDialInInfo,
88
-            text: t('welcomepage.info')
89
-        }, {
90
-            backgroundColor: 'red',
91
-            onPress: this._onDelete,
92
-            text: t('welcomepage.recentListDelete')
93
-        } ];
94 83
 
95 84
         return (
96 85
             <NavigateSectionList
97 86
                 disabled = { disabled }
87
+                onLongPress = { this._onLongPress }
98 88
                 onPress = { this._onPress }
99 89
                 renderListEmptyComponent
100 90
                     = { this._getRenderListEmptyComponent() }
101
-                sections = { recentList }
102
-                slideActions = { slideActions } />
91
+                sections = { recentList } />
103 92
         );
104 93
     }
105 94
 
106
-    _onDelete: Object => void
95
+    _onLongPress: (Object) => void;
107 96
 
108 97
     /**
109
-     * Callback for the delete action of the list.
98
+     * Handles the list's navigate action.
110 99
      *
111
-     * @param {Object} itemId - The ID of the entry thats deletion is
112
-     * requested.
100
+     * @private
101
+     * @param {Object} item - The item which was long pressed.
113 102
      * @returns {void}
114 103
      */
115
-    _onDelete(itemId) {
116
-        this.props.dispatch(deleteRecentListEntry(itemId));
117
-    }
118
-
119
-    _onShowDialInInfo: Object => void
120
-
121
-    /**
122
-     * Callback for the dial-in info action of the list.
123
-     *
124
-     * @param {Object} itemId - The ID of the entry for which we'd like to show the dial in numbers.
125
-     * @returns {void}
126
-     */
127
-    _onShowDialInInfo(itemId) {
128
-        this.props.dispatch(setActiveModalId(DIAL_IN_SUMMARY_VIEW_ID, { summaryUrl: itemId.url }));
104
+    _onLongPress(item) {
105
+        this.props.dispatch(openDialog(RecentListItemMenu, { item }));
129 106
     }
130 107
 }
131 108
 
@@ -133,10 +110,7 @@ class RecentList extends AbstractRecentList<Props> {
133 110
  * Maps redux state to component props.
134 111
  *
135 112
  * @param {Object} state - The redux state.
136
- * @returns {{
137
- *     _defaultServerURL: string,
138
- *     _recentList: Array
139
- * }}
113
+ * @returns {Props}
140 114
  */
141 115
 export function _mapStateToProps(state: Object) {
142 116
     return {

+ 143
- 0
react/features/recent-list/components/RecentListItemMenu.native.js 查看文件

@@ -0,0 +1,143 @@
1
+// @flow
2
+
3
+import React, { PureComponent } from 'react';
4
+import { Text, View } from 'react-native';
5
+
6
+import { ColorSchemeRegistry } from '../../base/color-scheme';
7
+import { BottomSheet, hideDialog, isDialogOpen } from '../../base/dialog';
8
+import { type Item } from '../../base/react/Types';
9
+import { connect } from '../../base/redux';
10
+import { StyleType } from '../../base/styles';
11
+
12
+import DeleteItemButton from './DeleteItemButton.native';
13
+import ShowDialInInfoButton from './ShowDialInInfoButton.native';
14
+import styles from './styles';
15
+
16
+type Props = {
17
+
18
+    /**
19
+     * The Redux dispatch function.
20
+     */
21
+    dispatch: Function,
22
+
23
+    /**
24
+     * Item being rendered in this menu.
25
+     */
26
+    item: Item,
27
+
28
+    /**
29
+     * The color-schemed stylesheet of the BottomSheet.
30
+     */
31
+    _bottomSheetStyles: StyleType,
32
+
33
+    /**
34
+     * True if the menu is currently open, false otherwise.
35
+     */
36
+    _isOpen: boolean
37
+}
38
+
39
+// eslint-disable-next-line prefer-const
40
+let RecentListItemMenu_;
41
+
42
+/**
43
+ * Class to implement a popup menu that opens upon long pressing a recent list item.
44
+ */
45
+class RecentListItemMenu extends PureComponent<Props> {
46
+    /**
47
+     * Constructor of the component.
48
+     *
49
+     * @inheritdoc
50
+     */
51
+    constructor(props: Props) {
52
+        super(props);
53
+
54
+        this._onCancel = this._onCancel.bind(this);
55
+        this._renderMenuHeader = this._renderMenuHeader.bind(this);
56
+    }
57
+
58
+    /**
59
+     * Implements {@code Component#render}.
60
+     *
61
+     * @inheritdoc
62
+     */
63
+    render() {
64
+        const { _bottomSheetStyles, item } = this.props;
65
+        const buttonProps = {
66
+            afterClick: this._onCancel,
67
+            itemId: item.id,
68
+            showLabel: true,
69
+            styles: _bottomSheetStyles.buttons
70
+        };
71
+
72
+        return (
73
+            <BottomSheet
74
+                onCancel = { this._onCancel }
75
+                renderHeader = { this._renderMenuHeader }>
76
+                <DeleteItemButton { ...buttonProps } />
77
+                <ShowDialInInfoButton { ...buttonProps } />
78
+            </BottomSheet>
79
+        );
80
+    }
81
+
82
+    _onCancel: () => boolean;
83
+
84
+    /**
85
+     * Callback to hide this menu.
86
+     *
87
+     * @private
88
+     * @returns {boolean}
89
+     */
90
+    _onCancel() {
91
+        if (this.props._isOpen) {
92
+            this.props.dispatch(hideDialog(RecentListItemMenu_));
93
+
94
+            return true;
95
+        }
96
+
97
+        return false;
98
+    }
99
+
100
+    _renderMenuHeader: () => React$Element<any>;
101
+
102
+    /**
103
+     * Function to render the menu's header.
104
+     *
105
+     * @returns {React$Element}
106
+     */
107
+    _renderMenuHeader() {
108
+        const { _bottomSheetStyles, item } = this.props;
109
+
110
+        return (
111
+            <View
112
+                style = { [
113
+                    _bottomSheetStyles.sheet,
114
+                    styles.entryNameContainer
115
+                ] }>
116
+                <Text
117
+                    ellipsizeMode = { 'middle' }
118
+                    numberOfLines = { 1 }
119
+                    style = { styles.entryNameLabel }>
120
+                    { item.title }
121
+                </Text>
122
+            </View>
123
+        );
124
+    }
125
+}
126
+
127
+/**
128
+ * Function that maps parts of Redux state tree into component props.
129
+ *
130
+ * @param {Object} state - Redux state.
131
+ * @private
132
+ * @returns {Props}
133
+ */
134
+function _mapStateToProps(state) {
135
+    return {
136
+        _bottomSheetStyles: ColorSchemeRegistry.get(state, 'BottomSheet'),
137
+        _isOpen: isDialogOpen(state, RecentListItemMenu_)
138
+    };
139
+}
140
+
141
+RecentListItemMenu_ = connect(_mapStateToProps)(RecentListItemMenu);
142
+
143
+export default RecentListItemMenu_;

+ 49
- 0
react/features/recent-list/components/ShowDialInInfoButton.native.js 查看文件

@@ -0,0 +1,49 @@
1
+// @flow
2
+
3
+import { translate } from '../../base/i18n';
4
+import { IconInfo } from '../../base/icons';
5
+import { setActiveModalId } from '../../base/modal';
6
+import { connect } from '../../base/redux';
7
+import { AbstractButton, type AbstractButtonProps } from '../../base/toolbox/components';
8
+import { DIAL_IN_SUMMARY_VIEW_ID } from '../../invite/constants';
9
+
10
+export type Props = AbstractButtonProps & {
11
+
12
+    /**
13
+     * The redux {@code dispatch} function.
14
+     */
15
+    dispatch: Function,
16
+
17
+    /**
18
+     * The ID of the entry to be deleted.
19
+     */
20
+    itemId: Object,
21
+
22
+    /**
23
+     * The function to be used to translate i18n labels.
24
+     */
25
+    t: Function
26
+};
27
+
28
+/**
29
+ * A recent list menu button which opens the dial-in info dialog.
30
+ */
31
+class ShowDialInInfoButton extends AbstractButton<Props, *> {
32
+    accessibilityLabel = 'welcomepage.info';
33
+    icon = IconInfo;
34
+    label = 'welcomepage.info';
35
+
36
+    /**
37
+     * Handles clicking / pressing the button.
38
+     *
39
+     * @private
40
+     * @returns {void}
41
+     */
42
+    _handleClick() {
43
+        const { dispatch, itemId } = this.props;
44
+
45
+        dispatch(setActiveModalId(DIAL_IN_SUMMARY_VIEW_ID, { summaryUrl: itemId.url }));
46
+    }
47
+}
48
+
49
+export default translate(connect()(ShowDialInInfoButton));

+ 19
- 1
react/features/recent-list/components/styles.native.js 查看文件

@@ -1,4 +1,4 @@
1
-import { createStyleSheet } from '../../base/styles';
1
+import { ColorPalette, createStyleSheet } from '../../base/styles';
2 2
 
3 3
 /**
4 4
  * The styles of the React {@code Component}s of the feature recent-list i.e.
@@ -22,5 +22,23 @@ export default createStyleSheet({
22 22
         alignItems: 'center',
23 23
         justifyContent: 'center',
24 24
         padding: 20
25
+    },
26
+
27
+    entryNameContainer: {
28
+        alignItems: 'center',
29
+        borderBottomColor: ColorPalette.lightGrey,
30
+        borderBottomWidth: 1,
31
+        borderTopLeftRadius: 16,
32
+        borderTopRightRadius: 16,
33
+        flexDirection: 'row',
34
+        justifyContent: 'center',
35
+        height: 48
36
+    },
37
+
38
+    entryNameLabel: {
39
+        color: ColorPalette.lightGrey,
40
+        flexShrink: 1,
41
+        fontSize: 16,
42
+        opacity: 0.90
25 43
     }
26 44
 });

Loading…
取消
儲存