Przeglądaj źródła

[RN] Add invite function to calendar

master
Bettenbuk Zoltan 6 lat temu
rodzic
commit
2d87757aaa

+ 2
- 0
lang/main.json Wyświetl plik

@@ -648,6 +648,8 @@
648 648
     },
649 649
     "calendarSync": {
650 650
         "addMeetingURL": "Add a meeting link",
651
+        "confirmAddLink": "Do you want to add a Jitsi link to this event?",
652
+        "confirmAddLinkTitle": "Calendar",
651 653
         "join": "Join",
652 654
         "joinTooltip": "Join the meeting",
653 655
         "nextMeeting": "next meeting",

+ 39
- 0
react/features/base/dialog/components/DialogContent.native.js Wyświetl plik

@@ -0,0 +1,39 @@
1
+// @flow
2
+
3
+import React, { Component } from 'react';
4
+import { Text, View } from 'react-native';
5
+
6
+import { dialog as styles } from './styles';
7
+
8
+type Props = {
9
+
10
+    /**
11
+     * Children of the component.
12
+     */
13
+    children: string | React$Node
14
+};
15
+
16
+/**
17
+ * Generic dialog content container to provide the same styling for all custom
18
+ * dialogs.
19
+ */
20
+export default class DialogContent extends Component<Props> {
21
+    /**
22
+     * Implements {@code Component#render}.
23
+     *
24
+     * @inheritdoc
25
+     */
26
+    render() {
27
+        const { children } = this.props;
28
+
29
+        const childrenComponent = typeof children === 'string'
30
+            ? <Text>{ children }</Text>
31
+            : children;
32
+
33
+        return (
34
+            <View style = { styles.dialogContainer }>
35
+                { childrenComponent }
36
+            </View>
37
+        );
38
+    }
39
+}

+ 0
- 0
react/features/base/dialog/components/DialogContent.web.js Wyświetl plik


+ 2
- 1
react/features/base/dialog/components/index.js Wyświetl plik

@@ -1,8 +1,9 @@
1 1
 // @flow
2 2
 
3 3
 export { default as BottomSheet } from './BottomSheet';
4
-export { default as DialogContainer } from './DialogContainer';
5 4
 export { default as Dialog } from './Dialog';
5
+export { default as DialogContainer } from './DialogContainer';
6
+export { default as DialogContent } from './DialogContent';
6 7
 export { default as StatelessDialog } from './StatelessDialog';
7 8
 export { default as DialogWithTabs } from './DialogWithTabs';
8 9
 export { default as AbstractDialogTab } from './AbstractDialogTab';

+ 9
- 1
react/features/base/dialog/components/styles.js Wyświetl plik

@@ -1,6 +1,6 @@
1 1
 import { StyleSheet } from 'react-native';
2 2
 
3
-import { ColorPalette, createStyleSheet } from '../../styles';
3
+import { BoxModel, ColorPalette, createStyleSheet } from '../../styles';
4 4
 
5 5
 /**
6 6
  * The React {@code Component} styles of {@code Dialog}.
@@ -13,6 +13,14 @@ export const dialog = createStyleSheet({
13 13
         color: ColorPalette.blue
14 14
     },
15 15
 
16
+    /**
17
+     * Unified container for a consistent Dialog style.
18
+     */
19
+    dialogContainer: {
20
+        paddingHorizontal: BoxModel.padding,
21
+        paddingVertical: 1.5 * BoxModel.padding
22
+    },
23
+
16 24
     /**
17 25
      * The style of the {@code Text} in a {@code Dialog} button which is
18 26
      * disabled.

+ 27
- 2
react/features/base/react/components/NavigateSectionList.js Wyświetl plik

@@ -29,6 +29,12 @@ type Props = {
29 29
      */
30 30
     onRefresh: Function,
31 31
 
32
+    /**
33
+     * Function to be invoked when a secondary action is performed on an item.
34
+     * The item's ID is passed.
35
+     */
36
+    onSecondaryAction: Function,
37
+
32 38
     /**
33 39
      * Function to override the rendered default empty list component.
34 40
      */
@@ -153,6 +159,23 @@ class NavigateSectionList extends Component<Props> {
153 159
         }
154 160
     }
155 161
 
162
+    _onSecondaryAction: Object => Function;
163
+
164
+    /**
165
+     * Returns a function that is used in the secondaryAction callback of the
166
+     * items.
167
+     *
168
+     * @param {string} id - The id of the item that secondary action was
169
+     * performed on.
170
+     * @private
171
+     * @returns {Function}
172
+     */
173
+    _onSecondaryAction(id) {
174
+        return () => {
175
+            this.props.onSecondaryAction(id);
176
+        };
177
+    }
178
+
156 179
     _renderItem: Object => Object;
157 180
 
158 181
     /**
@@ -165,7 +188,7 @@ class NavigateSectionList extends Component<Props> {
165 188
      */
166 189
     _renderItem(listItem, key: string = '') {
167 190
         const { item } = listItem;
168
-        const { url } = item;
191
+        const { id, url } = item;
169 192
 
170 193
         // XXX The value of title cannot be undefined; otherwise, react-native
171 194
         // will throw a TypeError: Cannot read property of undefined. While it's
@@ -180,7 +203,9 @@ class NavigateSectionList extends Component<Props> {
180 203
             <NavigateSectionListItem
181 204
                 item = { item }
182 205
                 key = { key }
183
-                onPress = { this._onPress(url) } />
206
+                onPress = { url ? this._onPress(url) : undefined }
207
+                secondaryAction = {
208
+                    url ? undefined : this._onSecondaryAction(id) } />
184 209
         );
185 210
     }
186 211
 

+ 25
- 1
react/features/base/react/components/native/NavigateSectionListItem.js Wyświetl plik

@@ -17,7 +17,12 @@ type Props = {
17 17
     /**
18 18
      * Function to be invoked when an Item is pressed. The Item's URL is passed.
19 19
      */
20
-    onPress: Function
20
+    onPress: ?Function,
21
+
22
+    /**
23
+     * Function to be invoked when secondary action was performed on an Item.
24
+     */
25
+    secondaryAction: ?Function
21 26
 }
22 27
 
23 28
 /**
@@ -100,6 +105,24 @@ export default class NavigateSectionListItem extends Component<Props> {
100 105
         return lines && lines.length ? lines.map(this._renderItemLine) : null;
101 106
     }
102 107
 
108
+    /**
109
+     * Renders the secondary action label.
110
+     *
111
+     * @private
112
+     * @returns {React$Node}
113
+     */
114
+    _renderSecondaryAction() {
115
+        const { secondaryAction } = this.props;
116
+
117
+        return (
118
+            <Container
119
+                onClick = { secondaryAction }
120
+                style = { styles.secondaryActionContainer }>
121
+                <Text style = { styles.secondaryActionLabel }>+</Text>
122
+            </Container>
123
+        );
124
+    }
125
+
103 126
     /**
104 127
      * Renders the content of this component.
105 128
      *
@@ -135,6 +158,7 @@ export default class NavigateSectionListItem extends Component<Props> {
135 158
                     </Text>
136 159
                     {this._renderItemLines(lines)}
137 160
                 </Container>
161
+                { this.props.secondaryAction && this._renderSecondaryAction() }
138 162
             </Container>
139 163
         );
140 164
     }

+ 16
- 0
react/features/base/react/components/native/styles.js Wyświetl plik

@@ -11,6 +11,7 @@ const HEADER_COLOR = ColorPalette.blue;
11 11
 // Header height is from Android guidelines. Also, this looks good.
12 12
 const HEADER_HEIGHT = 56;
13 13
 const OVERLAY_FONT_COLOR = 'rgba(255, 255, 255, 0.6)';
14
+const SECONDARY_ACTION_BUTTON_SIZE = 30;
14 15
 
15 16
 export const HEADER_PADDING = BoxModel.padding;
16 17
 export const STATUSBAR_COLOR = ColorPalette.blueHighlight;
@@ -266,6 +267,21 @@ const SECTION_LIST_STYLES = {
266 267
         color: OVERLAY_FONT_COLOR
267 268
     },
268 269
 
270
+    secondaryActionContainer: {
271
+        alignItems: 'center',
272
+        backgroundColor: ColorPalette.blue,
273
+        borderRadius: 3,
274
+        height: SECONDARY_ACTION_BUTTON_SIZE,
275
+        justifyContent: 'center',
276
+        margin: BoxModel.margin * 0.5,
277
+        marginRight: BoxModel.margin,
278
+        width: SECONDARY_ACTION_BUTTON_SIZE
279
+    },
280
+
281
+    secondaryActionLabel: {
282
+        color: ColorPalette.white
283
+    },
284
+
269 285
     touchableView: {
270 286
         flexDirection: 'row'
271 287
     }

+ 63
- 0
react/features/calendar-sync/actions.any.js Wyświetl plik

@@ -0,0 +1,63 @@
1
+// @flow
2
+
3
+import {
4
+    REFRESH_CALENDAR,
5
+    SET_CALENDAR_AUTHORIZATION,
6
+    SET_CALENDAR_EVENTS
7
+} from './actionTypes';
8
+
9
+/**
10
+ * Sends an action to refresh the entry list (fetches new data).
11
+ *
12
+ * @param {boolean} forcePermission - Whether to force to re-ask for
13
+ * the permission or not.
14
+ * @param {boolean} isInteractive - If true this refresh was caused by
15
+ * direct user interaction, false otherwise.
16
+ * @returns {{
17
+ *     type: REFRESH_CALENDAR,
18
+ *     forcePermission: boolean,
19
+ *     isInteractive: boolean
20
+ * }}
21
+ */
22
+export function refreshCalendar(
23
+        forcePermission: boolean = false, isInteractive: boolean = true) {
24
+    return {
25
+        type: REFRESH_CALENDAR,
26
+        forcePermission,
27
+        isInteractive
28
+    };
29
+}
30
+
31
+/**
32
+ * Sends an action to signal that a calendar access has been requested. For more
33
+ * info, see {@link SET_CALENDAR_AUTHORIZATION}.
34
+ *
35
+ * @param {string | undefined} authorization - The result of the last calendar
36
+ * authorization request.
37
+ * @returns {{
38
+ *     type: SET_CALENDAR_AUTHORIZATION,
39
+ *     authorization: ?string
40
+ * }}
41
+ */
42
+export function setCalendarAuthorization(authorization: ?string) {
43
+    return {
44
+        type: SET_CALENDAR_AUTHORIZATION,
45
+        authorization
46
+    };
47
+}
48
+
49
+/**
50
+ * Sends an action to update the current calendar list in redux.
51
+ *
52
+ * @param {Array<Object>} events - The new list.
53
+ * @returns {{
54
+ *     type: SET_CALENDAR_EVENTS,
55
+ *     events: Array<Object>
56
+ * }}
57
+ */
58
+export function setCalendarEvents(events: Array<Object>) {
59
+    return {
60
+        type: SET_CALENDAR_EVENTS,
61
+        events
62
+    };
63
+}

+ 47
- 0
react/features/calendar-sync/actions.native.js Wyświetl plik

@@ -0,0 +1,47 @@
1
+// @flow
2
+
3
+import { getDefaultURL } from '../app';
4
+import { openDialog } from '../base/dialog';
5
+import { generateRoomWithoutSeparator } from '../welcome';
6
+
7
+import { refreshCalendar } from './actions';
8
+import { addLinkToCalendarEntry } from './functions.native';
9
+
10
+import {
11
+    UpdateCalendarEventDialog
12
+} from './components';
13
+
14
+export * from './actions.any';
15
+
16
+/**
17
+ * Asks confirmation from the user to add a Jitsi link to the calendar event.
18
+ *
19
+ * @param {string} eventId - The event id.
20
+ * @returns {{
21
+ *     type: OPEN_DIALOG,
22
+ *     component: React.Component,
23
+ *     componentProps: (Object | undefined)
24
+ * }}
25
+ */
26
+export function openUpdateCalendarEventDialog(eventId: string) {
27
+    return openDialog(UpdateCalendarEventDialog, { eventId });
28
+}
29
+
30
+/**
31
+ * Updates calendar event by generating new invite URL and editing the event
32
+ * adding some descriptive text and location.
33
+ *
34
+ * @param {string} eventId - The event id.
35
+ * @returns {Function}
36
+ */
37
+export function updateCalendarEvent(eventId: string) {
38
+    return (dispatch: Dispatch<*>, getState: Function) => {
39
+        const defaultUrl = getDefaultURL(getState);
40
+        const roomName = generateRoomWithoutSeparator();
41
+
42
+        addLinkToCalendarEntry(getState(), eventId, `${defaultUrl}/${roomName}`)
43
+        .finally(() => {
44
+            dispatch(refreshCalendar(false, false));
45
+        });
46
+    };
47
+}

react/features/calendar-sync/actions.js → react/features/calendar-sync/actions.web.js Wyświetl plik

@@ -2,14 +2,12 @@
2 2
 
3 3
 import { loadGoogleAPI } from '../google-api';
4 4
 
5
+import { refreshCalendar, setCalendarEvents } from './actions';
5 6
 import { createCalendarConnectedEvent, sendAnalytics } from '../analytics';
6 7
 
7 8
 import {
8 9
     CLEAR_CALENDAR_INTEGRATION,
9
-    REFRESH_CALENDAR,
10 10
     SET_CALENDAR_AUTH_STATE,
11
-    SET_CALENDAR_AUTHORIZATION,
12
-    SET_CALENDAR_EVENTS,
13 11
     SET_CALENDAR_INTEGRATION,
14 12
     SET_CALENDAR_PROFILE_EMAIL,
15 13
     SET_LOADING_CALENDAR_EVENTS
@@ -17,6 +15,8 @@ import {
17 15
 import { _getCalendarIntegration, isCalendarEnabled } from './functions';
18 16
 import { generateRoomWithoutSeparator } from '../welcome';
19 17
 
18
+export * from './actions.any';
19
+
20 20
 const logger = require('jitsi-meet-logger').getLogger(__filename);
21 21
 
22 22
 /**
@@ -88,25 +88,18 @@ export function clearCalendarIntegration() {
88 88
 }
89 89
 
90 90
 /**
91
- * Sends an action to refresh the entry list (fetches new data).
91
+ * Asks confirmation from the user to add a Jitsi link to the calendar event.
92 92
  *
93
- * @param {boolean} forcePermission - Whether to force to re-ask for
94
- * the permission or not.
95
- * @param {boolean} isInteractive - If true this refresh was caused by
96
- * direct user interaction, false otherwise.
97
- * @returns {{
98
- *     type: REFRESH_CALENDAR,
99
- *     forcePermission: boolean,
100
- *     isInteractive: boolean
101
- * }}
93
+ * NOTE: Currently there is no confirmation prompted on web, so this is just
94
+ * a relaying method to avoid flow problems.
95
+ *
96
+ * @param {string} eventId - The event id.
97
+ * @param {string} calendarId - The calendar id.
98
+ * @returns {Function}
102 99
  */
103
-export function refreshCalendar(
104
-        forcePermission: boolean = false, isInteractive: boolean = true) {
105
-    return {
106
-        type: REFRESH_CALENDAR,
107
-        forcePermission,
108
-        isInteractive
109
-    };
100
+export function openUpdateCalendarEventDialog(
101
+        eventId: string, calendarId: string) {
102
+    return updateCalendarEvent(eventId, calendarId);
110 103
 }
111 104
 
112 105
 /**
@@ -126,40 +119,6 @@ export function setCalendarAPIAuthState(newState: ?Object) {
126 119
     };
127 120
 }
128 121
 
129
-/**
130
- * Sends an action to signal that a calendar access has been requested. For more
131
- * info, see {@link SET_CALENDAR_AUTHORIZATION}.
132
- *
133
- * @param {string | undefined} authorization - The result of the last calendar
134
- * authorization request.
135
- * @returns {{
136
- *     type: SET_CALENDAR_AUTHORIZATION,
137
- *     authorization: ?string
138
- * }}
139
- */
140
-export function setCalendarAuthorization(authorization: ?string) {
141
-    return {
142
-        type: SET_CALENDAR_AUTHORIZATION,
143
-        authorization
144
-    };
145
-}
146
-
147
-/**
148
- * Sends an action to update the current calendar list in redux.
149
- *
150
- * @param {Array<Object>} events - The new list.
151
- * @returns {{
152
- *     type: SET_CALENDAR_EVENTS,
153
- *     events: Array<Object>
154
- * }}
155
- */
156
-export function setCalendarEvents(events: Array<Object>) {
157
-    return {
158
-        type: SET_CALENDAR_EVENTS,
159
-        events
160
-    };
161
-}
162
-
163 122
 /**
164 123
  * Sends an action to update the current calendar profile email state in redux.
165 124
  *
@@ -243,29 +202,6 @@ export function signIn(calendarType: string): Function {
243 202
     };
244 203
 }
245 204
 
246
-/**
247
- * Signals to get current profile data linked to the current calendar
248
- * integration that is in use.
249
- *
250
- * @param {string} calendarType - The calendar integration to which the profile
251
- * should be updated.
252
- * @returns {Function}
253
- */
254
-export function updateProfile(calendarType: string): Function {
255
-    return (dispatch: Dispatch<*>) => {
256
-        const integration = _getCalendarIntegration(calendarType);
257
-
258
-        if (!integration) {
259
-            return Promise.reject('No integration found');
260
-        }
261
-
262
-        return dispatch(integration.getCurrentEmail())
263
-            .then(email => {
264
-                dispatch(setCalendarProfileEmail(email));
265
-            });
266
-    };
267
-}
268
-
269 205
 /**
270 206
  * Updates calendar event by generating new invite URL and editing the event
271 207
  * adding some descriptive text and location.
@@ -312,3 +248,26 @@ export function updateCalendarEvent(id: string, calendarId: string): Function {
312 248
             });
313 249
     };
314 250
 }
251
+
252
+/**
253
+ * Signals to get current profile data linked to the current calendar
254
+ * integration that is in use.
255
+ *
256
+ * @param {string} calendarType - The calendar integration to which the profile
257
+ * should be updated.
258
+ * @returns {Function}
259
+ */
260
+export function updateProfile(calendarType: string): Function {
261
+    return (dispatch: Dispatch<*>) => {
262
+        const integration = _getCalendarIntegration(calendarType);
263
+
264
+        if (!integration) {
265
+            return Promise.reject('No integration found');
266
+        }
267
+
268
+        return dispatch(integration.getCurrentEmail())
269
+            .then(email => {
270
+                dispatch(setCalendarProfileEmail(email));
271
+            });
272
+    };
273
+}

+ 18
- 1
react/features/calendar-sync/components/BaseCalendarList.js Wyświetl plik

@@ -12,7 +12,7 @@ import {
12 12
 import { getLocalizedDateFormatter, translate } from '../../base/i18n';
13 13
 import { NavigateSectionList } from '../../base/react';
14 14
 
15
-import { refreshCalendar } from '../actions';
15
+import { refreshCalendar, openUpdateCalendarEventDialog } from '../actions';
16 16
 
17 17
 import { isCalendarEnabled } from '../functions';
18 18
 
@@ -93,6 +93,7 @@ class BaseCalendarList extends Component<Props> {
93 93
         this._onJoinPress = this._onJoinPress.bind(this);
94 94
         this._onPress = this._onPress.bind(this);
95 95
         this._onRefresh = this._onRefresh.bind(this);
96
+        this._onSecondaryAction = this._onSecondaryAction.bind(this);
96 97
         this._toDateString = this._toDateString.bind(this);
97 98
         this._toDisplayableItem = this._toDisplayableItem.bind(this);
98 99
         this._toDisplayableList = this._toDisplayableList.bind(this);
@@ -123,6 +124,7 @@ class BaseCalendarList extends Component<Props> {
123 124
                 disabled = { disabled }
124 125
                 onPress = { this._onPress }
125 126
                 onRefresh = { this._onRefresh }
127
+                onSecondaryAction = { this._onSecondaryAction }
126 128
                 renderListEmptyComponent
127 129
                     = { renderListEmptyComponent }
128 130
                 sections = { this._toDisplayableList() } />
@@ -174,6 +176,20 @@ class BaseCalendarList extends Component<Props> {
174 176
         this.props.dispatch(refreshCalendar(true));
175 177
     }
176 178
 
179
+    _onSecondaryAction: string => void;
180
+
181
+    /**
182
+     * Handles the list's secondary action.
183
+     *
184
+     * @private
185
+     * @param {string} id - The ID of the item on which the secondary action was
186
+     * performed.
187
+     * @returns {void}
188
+     */
189
+    _onSecondaryAction(id) {
190
+        this.props.dispatch(openUpdateCalendarEventDialog(id, ''));
191
+    }
192
+
177 193
     _toDateString: Object => string;
178 194
 
179 195
     /**
@@ -208,6 +224,7 @@ class BaseCalendarList extends Component<Props> {
208 224
                 : (<AddMeetingUrlButton
209 225
                     calendarId = { event.calendarId }
210 226
                     eventId = { event.id } />),
227
+            id: event.id,
211 228
             key: `${event.id}-${event.startDate}`,
212 229
             lines: [
213 230
                 event.url,

+ 3
- 2
react/features/calendar-sync/components/ConferenceNotification.native.js Wyświetl plik

@@ -237,9 +237,10 @@ class ConferenceNotification extends Component<Props, State> {
237 237
 
238 238
             for (const event of _eventList) {
239 239
                 const eventUrl
240
-                    = getURLWithoutParamsNormalized(new URL(event.url));
240
+                    = event.url
241
+                        && getURLWithoutParamsNormalized(new URL(event.url));
241 242
 
242
-                if (eventUrl !== _currentConferenceURL) {
243
+                if (eventUrl && eventUrl !== _currentConferenceURL) {
243 244
                     if ((!eventToShow
244 245
                                 && event.startDate > now
245 246
                                 && event.startDate < now + ALERT_MILLISECONDS)

+ 79
- 0
react/features/calendar-sync/components/UpdateCalendarEventDialog.native.js Wyświetl plik

@@ -0,0 +1,79 @@
1
+// @flow
2
+
3
+import React, { Component } from 'react';
4
+import { connect } from 'react-redux';
5
+
6
+import { Dialog, DialogContent } from '../../base/dialog';
7
+import { translate } from '../../base/i18n';
8
+
9
+import { updateCalendarEvent } from '../actions';
10
+
11
+type Props = {
12
+
13
+    /**
14
+     * The Redux dispatch function.
15
+     */
16
+    dispatch: Function,
17
+
18
+    /**
19
+     * The ID of the event to be updated.
20
+     */
21
+    eventId: string,
22
+
23
+    /**
24
+     * Function to translate i18n labels.
25
+     */
26
+    t: Function
27
+};
28
+
29
+/**
30
+ * Component for the add Jitsi link confirm dialog.
31
+ */
32
+class UpdateCalendarEventDialog extends Component<Props> {
33
+    /**
34
+     * Initializes a new {@code UpdateCalendarEventDialog} instance.
35
+     *
36
+     * @inheritdoc
37
+     */
38
+    constructor(props: Props) {
39
+        super(props);
40
+
41
+        this._onSubmit = this._onSubmit.bind(this);
42
+    }
43
+
44
+    /**
45
+     * Implements React's {@link Component#render()}.
46
+     *
47
+     * @inheritdoc
48
+     * @returns {ReactElement}
49
+     */
50
+    render() {
51
+        return (
52
+            <Dialog
53
+                okTitleKey = 'dialog.confirm'
54
+                onSubmit = { this._onSubmit }
55
+                titleKey = 'calendarSync.confirmAddLinkTitle'
56
+                width = 'small'>
57
+                <DialogContent>
58
+                    { this.props.t('calendarSync.confirmAddLink') }
59
+                </DialogContent>
60
+            </Dialog>
61
+        );
62
+    }
63
+
64
+    _onSubmit: () => boolean;
65
+
66
+    /**
67
+     * Callback for the confirm button.
68
+     *
69
+     * @private
70
+     * @returns {boolean} - True (to note that the modal should be closed).
71
+     */
72
+    _onSubmit() {
73
+        this.props.dispatch(updateCalendarEvent(this.props.eventId, ''));
74
+
75
+        return true;
76
+    }
77
+}
78
+
79
+export default translate(connect()(UpdateCalendarEventDialog));

+ 0
- 0
react/features/calendar-sync/components/UpdateCalendarEventDialog.web.js Wyświetl plik


+ 3
- 0
react/features/calendar-sync/components/index.js Wyświetl plik

@@ -1,3 +1,6 @@
1 1
 export { default as ConferenceNotification } from './ConferenceNotification';
2 2
 export { default as CalendarList } from './CalendarList';
3 3
 export { default as MicrosoftSignInButton } from './MicrosoftSignInButton';
4
+export {
5
+    default as UpdateCalendarEventDialog
6
+} from './UpdateCalendarEventDialog';

+ 29
- 34
react/features/calendar-sync/functions.any.js Wyświetl plik

@@ -89,40 +89,35 @@ export function _updateCalendarEntries(events: Array<Object>) {
89 89
 function _parseCalendarEntry(event, knownDomains) {
90 90
     if (event) {
91 91
         const url = _getURLFromEvent(event, knownDomains);
92
-
93
-        // we only filter events without url on mobile, this is temporary
94
-        // till we implement event edit on mobile
95
-        if (url || navigator.product !== 'ReactNative') {
96
-            const startDate = Date.parse(event.startDate);
97
-            const endDate = Date.parse(event.endDate);
98
-
99
-            // we want to hide all events that
100
-            // - has no start or end date
101
-            // - for web, if there is no url and we cannot edit the event (has
102
-            // no calendarId)
103
-            if (isNaN(startDate)
104
-                || isNaN(endDate)
105
-                || (navigator.product !== 'ReactNative'
106
-                        && !url
107
-                        && !event.calendarId)) {
108
-                logger.debug(
109
-                    'Skipping invalid calendar event',
110
-                    event.title,
111
-                    event.startDate,
112
-                    event.endDate,
113
-                    url,
114
-                    event.calendarId
115
-                );
116
-            } else {
117
-                return {
118
-                    calendarId: event.calendarId,
119
-                    endDate,
120
-                    id: event.id,
121
-                    startDate,
122
-                    title: event.title,
123
-                    url
124
-                };
125
-            }
92
+        const startDate = Date.parse(event.startDate);
93
+        const endDate = Date.parse(event.endDate);
94
+
95
+        // we want to hide all events that
96
+        // - has no start or end date
97
+        // - for web, if there is no url and we cannot edit the event (has
98
+        // no calendarId)
99
+        if (isNaN(startDate)
100
+            || isNaN(endDate)
101
+            || (navigator.product !== 'ReactNative'
102
+                    && !url
103
+                    && !event.calendarId)) {
104
+            logger.debug(
105
+                'Skipping invalid calendar event',
106
+                event.title,
107
+                event.startDate,
108
+                event.endDate,
109
+                url,
110
+                event.calendarId
111
+            );
112
+        } else {
113
+            return {
114
+                calendarId: event.calendarId,
115
+                endDate,
116
+                id: event.id,
117
+                startDate,
118
+                title: event.title,
119
+                url
120
+            };
126 121
         }
127 122
     }
128 123
 

+ 38
- 1
react/features/calendar-sync/functions.native.js Wyświetl plik

@@ -1,6 +1,10 @@
1
-import { NativeModules } from 'react-native';
1
+// @flow
2
+
3
+import { NativeModules, Platform } from 'react-native';
2 4
 import RNCalendarEvents from 'react-native-calendar-events';
3 5
 
6
+import { getShareInfoText } from '../invite';
7
+
4 8
 import { setCalendarAuthorization } from './actions';
5 9
 import { FETCH_END_DAYS, FETCH_START_DAYS } from './constants';
6 10
 import { _updateCalendarEntries } from './functions';
@@ -9,6 +13,39 @@ export * from './functions.any';
9 13
 
10 14
 const logger = require('jitsi-meet-logger').getLogger(__filename);
11 15
 
16
+/**
17
+ * Adds a Jitsi link to a calendar entry.
18
+ *
19
+ * @param {Object} state - The Redux state.
20
+ * @param {string} id - The ID of the calendar entry.
21
+ * @param {string} link - The link to add info with.
22
+ * @returns {Promise<*>}
23
+ */
24
+export function addLinkToCalendarEntry(
25
+        state: Object, id: string, link: string) {
26
+    return new Promise((resolve, reject) => {
27
+        getShareInfoText(state, link, true).then(shareInfoText => {
28
+            RNCalendarEvents.findEventById(id).then(event => {
29
+                const updateText = `${event.description}\n\n${shareInfoText}`;
30
+                const updateObject = {
31
+                    id: event.id,
32
+                    ...Platform.select({
33
+                        ios: {
34
+                            notes: updateText
35
+                        },
36
+                        android: {
37
+                            description: updateText
38
+                        }
39
+                    })
40
+                };
41
+
42
+                RNCalendarEvents.saveEvent(event.title, updateObject)
43
+                .then(resolve, reject);
44
+            }, reject);
45
+        }, reject);
46
+    });
47
+}
48
+
12 49
 /**
13 50
  * Determines whether the calendar feature is enabled by the app. For
14 51
  * example, Apple through its App Store requires

+ 1
- 1
react/features/invite/functions.js Wyświetl plik

@@ -438,7 +438,7 @@ export function getShareInfoText(
438 438
 
439 439
             if (!dialInConfCodeUrl || !dialInNumbersUrl || !mucURL) {
440 440
                 // URLs for fetching dial in numbers not defined
441
-                return Promise.reject();
441
+                return Promise.resolve(infoText);
442 442
             }
443 443
 
444 444
             numbersPromise = Promise.all([

Ładowanie…
Anuluj
Zapisz