瀏覽代碼

feat: new invite layout

j8
Bettenbuk Zoltan 5 年之前
父節點
當前提交
a93bd422d3

+ 6
- 0
css/_font.scss 查看文件

@@ -25,6 +25,12 @@
25 25
     -moz-osx-font-smoothing: grayscale;
26 26
 }
27 27
 
28
+.icon-cancel:before {
29
+  content: "\e91c";
30
+}
31
+.icon-check:before {
32
+  content: "\e91b";
33
+}
28 34
 .icon-send:before {
29 35
   content: "\e911";
30 36
 }

二進制
fonts/jitsi.eot 查看文件


+ 2
- 0
fonts/jitsi.svg 查看文件

@@ -54,6 +54,8 @@
54 54
 <glyph unicode="&#xe918;" glyph-name="camera" d="M726 576l170 170v-468l-170 170v-150c0-24-20-42-44-42h-512c-24 0-42 18-42 42v428c0 24 18 42 42 42h512c24 0 44-18 44-42v-150z" />
55 55
 <glyph unicode="&#xe919;" glyph-name="camera-disabled" d="M140 938l756-756-54-54-136 136c-6-4-16-8-24-8h-512c-24 0-42 18-42 42v428c0 24 18 42 42 42h32l-116 116zM896 746v-456l-478 478h264c24 0 44-18 44-42v-150z" />
56 56
 <glyph unicode="&#xe91a;" glyph-name="volume" d="M598 886c172-38 298-192 298-374s-126-336-298-374v88c124 36 212 150 212 286s-88 250-212 286v88zM704 512c0-76-42-140-106-172v344c64-32 106-96 106-172zM128 640h170l214 214v-684l-214 214h-170v256z" />
57
+<glyph unicode="&#xe91b;" glyph-name="check" d="M384 334l452 452 60-60-512-512-238 238 60 60z" />
58
+<glyph unicode="&#xe91c;" glyph-name="cancel" d="M726 358l-154 154 154 154-60 60-154-154-154 154-60-60 154-154-154-154 60-60 154 154 154-154zM512 938q176 0 301-125t125-301-125-301-301-125-301 125-125 301 125 301 301 125z" />
57 59
 <glyph unicode="&#xe91d;" glyph-name="feedback" d="M42.667 128h170.667v512h-170.667v-512zM981.333 597.333c0 46.933-38.4 85.333-85.333 85.333h-269.227l40.533 194.987 1.28 13.653c0 17.493-7.253 33.707-18.773 45.227l-45.227 44.8-280.747-281.173c-15.787-15.36-25.173-36.693-25.173-60.16v-426.667c0-46.933 38.4-85.333 85.333-85.333h384c35.413 0 65.707 21.333 78.507 52.053l128.853 300.8c3.84 9.813 5.973 20.053 5.973 31.147v81.493l-0.427 0.427 0.427 3.413z" />
58 60
 <glyph unicode="&#xe91e;" glyph-name="raised-hand" d="M982 790v-620c0-94-78-170-172-170h-310c-46 0-90 18-122 50l-336 342s54 52 56 52c10 8 22 12 34 12 10 0 18-2 26-6 2 0 184-104 184-104v508c0 36 28 64 64 64s64-28 64-64v-300h42v406c0 36 28 64 64 64s64-28 64-64v-406h42v364c0 36 28 64 64 64s64-28 64-64v-364h44v236c0 36 28 64 64 64s64-28 64-64z" />
59 61
 <glyph unicode="&#xe91f;" glyph-name="menu-up" d="M512 682l256-256-60-60-196 196-196-196-60 60z" />

二進制
fonts/jitsi.ttf 查看文件


二進制
fonts/jitsi.woff 查看文件


+ 1
- 1
fonts/selection.json
文件差異過大導致無法顯示
查看文件


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

@@ -13,6 +13,11 @@ import styles, { AVATAR_SIZE, UNDERLAY_COLOR } from './styles';
13 13
 
14 14
 type Props = {
15 15
 
16
+    /**
17
+     * If true, only the avatar gets rendered, no lines of text.
18
+     */
19
+    avatarOnly?: boolean,
20
+
16 21
     /**
17 22
      * Preferred size of the avatar.
18 23
      */
@@ -76,6 +81,7 @@ export default class AvatarListItem extends Component<Props> {
76 81
      */
77 82
     render() {
78 83
         const {
84
+            avatarOnly,
79 85
             avatarSize = AVATAR_SIZE,
80 86
             avatarStyle
81 87
         } = this.props;
@@ -92,7 +98,7 @@ export default class AvatarListItem extends Component<Props> {
92 98
                     size = { avatarSize }
93 99
                     style = { avatarStyle }
94 100
                     url = { avatar } />
95
-                <Container style = { styles.listItemDetails }>
101
+                { avatarOnly || <Container style = { styles.listItemDetails }>
96 102
                     <Text
97 103
                         numberOfLines = { 1 }
98 104
                         style = { [
@@ -103,7 +109,7 @@ export default class AvatarListItem extends Component<Props> {
103 109
                         { title }
104 110
                     </Text>
105 111
                     {this._renderItemLines(lines)}
106
-                </Container>
112
+                </Container>}
107 113
                 { this.props.children }
108 114
             </Container>
109 115
         );

+ 99
- 55
react/features/invite/components/add-people-dialog/native/AddPeopleDialog.js 查看文件

@@ -106,6 +106,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
106 106
         this.state = this.defaultState;
107 107
 
108 108
         this._keyExtractor = this._keyExtractor.bind(this);
109
+        this._renderInvitedItem = this._renderInvitedItem.bind(this);
109 110
         this._renderItem = this._renderItem.bind(this);
110 111
         this._renderSeparator = this._renderSeparator.bind(this);
111 112
         this._onClearField = this._onClearField.bind(this);
@@ -138,7 +139,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
138 139
             _addPeopleEnabled,
139 140
             _dialOutEnabled
140 141
         } = this.props;
141
-        const { inviteItems } = this.state;
142
+        const { inviteItems, selectableItems } = this.state;
142 143
 
143 144
         let placeholderKey = 'searchPlaceholder';
144 145
 
@@ -187,14 +188,23 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
187 188
                                 value = { this.state.fieldValue } />
188 189
                             { this._renderAndroidClearButton() }
189 190
                         </View>
190
-                        <FlatList
191
-                            ItemSeparatorComponent = { this._renderSeparator }
192
-                            data = { this.state.selectableItems }
193
-                            extraData = { inviteItems }
194
-                            keyExtractor = { this._keyExtractor }
195
-                            keyboardShouldPersistTaps = 'always'
196
-                            renderItem = { this._renderItem }
197
-                            style = { styles.resultList } />
191
+                        { Boolean(inviteItems.length) && <View style = { styles.invitedList }>
192
+                            <FlatList
193
+                                data = { inviteItems }
194
+                                horizontal = { true }
195
+                                keyExtractor = { this._keyExtractor }
196
+                                keyboardShouldPersistTaps = 'always'
197
+                                renderItem = { this._renderInvitedItem } />
198
+                        </View> }
199
+                        <View style = { styles.resultList }>
200
+                            <FlatList
201
+                                ItemSeparatorComponent = { this._renderSeparator }
202
+                                data = { selectableItems }
203
+                                extraData = { inviteItems }
204
+                                keyExtractor = { this._keyExtractor }
205
+                                keyboardShouldPersistTaps = 'always'
206
+                                renderItem = { this._renderItem } />
207
+                        </View>
198 208
                     </SafeAreaView>
199 209
                 </KeyboardAvoidingView>
200 210
             </SlidingView>
@@ -210,6 +220,33 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
210 220
         this.setState(this.defaultState);
211 221
     }
212 222
 
223
+    /**
224
+     * Returns an object capable of being rendered by an {@code AvatarListItem}.
225
+     *
226
+     * @param {Object} flatListItem - An item of the data array of the {@code FlatList}.
227
+     * @returns {?Object}
228
+     */
229
+    _getRenderableItem(flatListItem) {
230
+        const { item } = flatListItem;
231
+
232
+        switch (item.type) {
233
+        case 'phone':
234
+            return {
235
+                avatar: 'icon://phone',
236
+                key: item.number,
237
+                title: item.number
238
+            };
239
+        case 'user':
240
+            return {
241
+                avatar: item.avatar,
242
+                key: item.id || item.user_id,
243
+                title: item.name
244
+            };
245
+        default:
246
+            return null;
247
+        }
248
+    }
249
+
213 250
     _invite: Array<Object> => Promise<Array<Object>>
214 251
 
215 252
     _isAddDisabled: () => boolean;
@@ -303,7 +340,7 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
303 340
                 });
304 341
             } else {
305 342
                 // Item is not selected yet, need to add to the list.
306
-                const items: Array<*> = inviteItems.concat(item);
343
+                const items: Array<Object> = inviteItems.concat(item);
307 344
 
308 345
                 this.setState({
309 346
                     inviteItems: _.sortBy(items, [ 'name', 'number' ])
@@ -344,27 +381,8 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
344 381
      */
345 382
     _performSearch(query) {
346 383
         this._query(query).then(results => {
347
-            const { inviteItems } = this.state;
348
-
349
-            let selectableItems = results.filter(result => {
350
-                switch (result.type) {
351
-                case 'phone':
352
-                    return result.allowed && result.number
353
-                        && !inviteItems.find(
354
-                            _.matchesProperty('number', result.number));
355
-                case 'user':
356
-                    return !inviteItems.find(
357
-                        (result.user_id && _.matchesProperty('id', result.id))
358
-                        || (result.user_id && _.matchesProperty('user_id', result.user_id)));
359
-                default:
360
-                    return false;
361
-                }
362
-            });
363
-
364
-            selectableItems = _.sortBy(selectableItems, [ 'name', 'number' ]);
365
-
366 384
             this.setState({
367
-                selectableItems: this.state.inviteItems.concat(selectableItems)
385
+                selectableItems: _.sortBy(results, [ 'name', 'number' ])
368 386
             });
369 387
         })
370 388
         .finally(() => {
@@ -378,8 +396,6 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
378 396
 
379 397
     _query: (string) => Promise<Array<Object>>;
380 398
 
381
-    _renderItem: Object => ?React$Element<*>
382
-
383 399
     /**
384 400
      * Renders a button to clear the text field on Android.
385 401
      *
@@ -405,8 +421,46 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
405 421
         );
406 422
     }
407 423
 
424
+    _renderInvitedItem: Object => ?React$Element<*>
425
+
426
+    /**
427
+     * Renders a single item in the invited {@code FlatList}.
428
+     *
429
+     * @param {Object} flatListItem - An item of the data array of the
430
+     * {@code FlatList}.
431
+     * @param {number} index - The index of the currently rendered item.
432
+     * @returns {?React$Element<*>}
433
+     */
434
+    _renderInvitedItem(flatListItem, index) {
435
+        const { item } = flatListItem;
436
+        const renderableItem = this._getRenderableItem(flatListItem);
437
+
438
+        return (
439
+            <TouchableOpacity onPress = { this._onPressItem(item) } >
440
+                <View
441
+                    pointerEvents = 'box-only'
442
+                    style = { styles.itemWrapper }>
443
+                    <AvatarListItem
444
+                        avatarOnly = { true }
445
+                        avatarSize = { AVATAR_SIZE }
446
+                        avatarStyle = { styles.avatar }
447
+                        avatarTextStyle = { styles.avatarText }
448
+                        item = { renderableItem }
449
+                        key = { index }
450
+                        linesStyle = { styles.itemLinesStyle }
451
+                        titleStyle = { styles.itemText } />
452
+                    <Icon
453
+                        name = 'cancel'
454
+                        style = { styles.unselectIcon } />
455
+                </View>
456
+            </TouchableOpacity>
457
+        );
458
+    }
459
+
460
+    _renderItem: Object => ?React$Element<*>
461
+
408 462
     /**
409
-     * Renders a single item in the {@code FlatList}.
463
+     * Renders a single item in the search result {@code FlatList}.
410 464
      *
411 465
      * @param {Object} flatListItem - An item of the data array of the
412 466
      * {@code FlatList}.
@@ -417,28 +471,20 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
417 471
         const { item } = flatListItem;
418 472
         const { inviteItems } = this.state;
419 473
         let selected = false;
420
-        let renderableItem;
474
+        const renderableItem = this._getRenderableItem(flatListItem);
475
+
476
+        if (!renderableItem) {
477
+            return null;
478
+        }
421 479
 
422 480
         switch (item.type) {
423 481
         case 'phone':
424
-            selected
425
-                = inviteItems.find(_.matchesProperty('number', item.number));
426
-            renderableItem = {
427
-                avatar: 'icon://phone',
428
-                key: item.number,
429
-                title: item.number
430
-            };
482
+            selected = inviteItems.find(_.matchesProperty('number', item.number));
431 483
             break;
432 484
         case 'user':
433
-            selected
434
-                = item.id
435
-                    ? inviteItems.find(_.matchesProperty('id', item.id))
436
-                    : inviteItems.find(_.matchesProperty('user_id', item.user_id));
437
-            renderableItem = {
438
-                avatar: item.avatar,
439
-                key: item.id || item.user_id,
440
-                title: item.name
441
-            };
485
+            selected = item.id
486
+                ? inviteItems.find(_.matchesProperty('id', item.id))
487
+                : inviteItems.find(_.matchesProperty('user_id', item.user_id));
442 488
             break;
443 489
         default:
444 490
             return null;
@@ -449,11 +495,6 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
449 495
                 <View
450 496
                     pointerEvents = 'box-only'
451 497
                     style = { styles.itemWrapper }>
452
-                    <Icon
453
-                        name = { selected
454
-                            ? 'radio_button_checked'
455
-                            : 'radio_button_unchecked' }
456
-                        style = { styles.radioButton } />
457 498
                     <AvatarListItem
458 499
                         avatarSize = { AVATAR_SIZE }
459 500
                         avatarStyle = { styles.avatar }
@@ -462,6 +503,9 @@ class AddPeopleDialog extends AbstractAddPeopleDialog<Props, State> {
462 503
                         key = { index }
463 504
                         linesStyle = { styles.itemLinesStyle }
464 505
                         titleStyle = { styles.itemText } />
506
+                    { selected && <Icon
507
+                        name = 'check'
508
+                        style = { styles.selectedIcon } /> }
465 509
                 </View>
466 510
             </TouchableOpacity>
467 511
         );

+ 24
- 9
react/features/invite/components/add-people-dialog/native/styles.js 查看文件

@@ -1,6 +1,6 @@
1 1
 // @flow
2 2
 
3
-import { ColorPalette } from '../../../../base/styles';
3
+import { BoxModel, ColorPalette } from '../../../../base/styles';
4 4
 
5 5
 export const AVATAR_SIZE = 40;
6 6
 export const DARK_GREY = 'rgb(28, 32, 37)';
@@ -15,7 +15,7 @@ export default {
15 15
     },
16 16
 
17 17
     avatarText: {
18
-        color: 'rgb(28, 32, 37)',
18
+        color: DARK_GREY,
19 19
         fontSize: 12
20 20
     },
21 21
 
@@ -48,7 +48,12 @@ export default {
48 48
         alignItems: 'stretch',
49 49
         backgroundColor: ColorPalette.white,
50 50
         flex: 1,
51
-        flexDirection: 'column'
51
+        flexDirection: 'column',
52
+        justifyContent: 'flex-start'
53
+    },
54
+
55
+    invitedList: {
56
+        padding: 3
52 57
     },
53 58
 
54 59
     itemLinesStyle: {
@@ -68,13 +73,8 @@ export default {
68 73
         paddingLeft: 5
69 74
     },
70 75
 
71
-    radioButton: {
72
-        color: DARK_GREY,
73
-        fontSize: 16,
74
-        padding: 2
75
-    },
76
-
77 76
     resultList: {
77
+        flex: 1,
78 78
         padding: 5
79 79
     },
80 80
 
@@ -88,6 +88,13 @@ export default {
88 88
         paddingVertical: 7
89 89
     },
90 90
 
91
+    selectedIcon: {
92
+        color: DARK_GREY,
93
+        fontSize: 20,
94
+        marginRight: BoxModel.margin,
95
+        padding: 2
96
+    },
97
+
91 98
     separator: {
92 99
         borderBottomColor: LIGHT_GREY,
93 100
         borderBottomWidth: 1,
@@ -115,5 +122,13 @@ export default {
115 122
         flexDirection: 'row',
116 123
         justifyContent: 'center',
117 124
         width: ICON_SIZE + 16
125
+    },
126
+
127
+    unselectIcon: {
128
+        color: LIGHT_GREY,
129
+        fontSize: 16,
130
+        left: AVATAR_SIZE / -3,
131
+        position: 'relative',
132
+        top: AVATAR_SIZE / -3
118 133
     }
119 134
 };

Loading…
取消
儲存