@olea-bps/views 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/Callmanager/index.js +148 -0
  2. package/Callmanager/styles.js +62 -0
  3. package/Canteens/index.js +383 -0
  4. package/Canteens/styles.js +89 -0
  5. package/Dashboard/index.js +176 -0
  6. package/Dashboard/styles.js +16 -0
  7. package/DashboardHtwk/index.js +197 -0
  8. package/DashboardHtwk/styles.js +24 -0
  9. package/Event/index.js +369 -0
  10. package/Event/styles.js +63 -0
  11. package/FeedList/index.js +165 -0
  12. package/FeedList/styles.js +15 -0
  13. package/FeedNews/index.js +243 -0
  14. package/FeedNews/styles.js +32 -0
  15. package/Flexmenu/index.js +185 -0
  16. package/Flexmenu/styles.js +62 -0
  17. package/FlexmenuWebview/index.js +167 -0
  18. package/FlexmenuWebview/styles.js +16 -0
  19. package/Howhy/index.js +151 -0
  20. package/Howhy/styles.js +11 -0
  21. package/Jobs/index.js +217 -0
  22. package/Jobs/styles.js +41 -0
  23. package/MainMenu/index.js +329 -0
  24. package/MainMenu/styles.js +36 -0
  25. package/NewsTabbar/index.js +164 -0
  26. package/NewsTabbar/styles.js +27 -0
  27. package/Opal/index.js +136 -0
  28. package/Opal/styles.js +11 -0
  29. package/PublicTransportTicket/index.js +173 -0
  30. package/PublicTransportTicket/styles.js +17 -0
  31. package/Search/index.js +186 -0
  32. package/Search/styles.js +67 -0
  33. package/SettingsAccessibility/index.js +148 -0
  34. package/SettingsAccessibility/styles.js +13 -0
  35. package/SettingsAppInfo/index.js +86 -0
  36. package/SettingsAppInfo/styles.js +18 -0
  37. package/SettingsCanteens/index.js +249 -0
  38. package/SettingsCanteens/styles.js +33 -0
  39. package/SettingsGeneral/index.js +173 -0
  40. package/SettingsGeneral/styles.js +28 -0
  41. package/SettingsNotifications/index.js +204 -0
  42. package/SettingsNotifications/styles.js +38 -0
  43. package/SettingsUser/index.js +170 -0
  44. package/SettingsUser/styles.js +17 -0
  45. package/TimetableCalendar/index.js +322 -0
  46. package/TimetableCalendar/styles.js +117 -0
  47. package/TimetableList/index.js +397 -0
  48. package/TimetableList/styles.js +55 -0
  49. package/Webviews/index.js +158 -0
  50. package/Webviews/styles.js +11 -0
  51. package/index.js +25 -0
  52. package/package.json +41 -0
@@ -0,0 +1,397 @@
1
+ /**
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import { useState, useMemo, useCallback } from 'react';
16
+ import {
17
+ SafeAreaView,
18
+ StyleSheet,
19
+ View,
20
+ ScrollView,
21
+ TouchableOpacity,
22
+ RefreshControl,
23
+ ActivityIndicator,
24
+ Linking,
25
+ } from 'react-native';
26
+ import { connect } from 'react-redux'
27
+ import { TabView, TabBar, TabBarItem } from 'react-native-tab-view';
28
+ import { Appbar, useTheme, Text } from 'react-native-paper';
29
+ import { useTranslation } from 'react-i18next';
30
+ import { useFocusEffect } from '@react-navigation/native';
31
+
32
+ import { DateTime, Duration } from 'luxon';
33
+
34
+ import { onUpdateRefreshing, store } from '@olea-bps/core';
35
+ import { ApiProviderNotInitializedError, useCourses, useTimetableCode } from '@olea-bps/context-timetable';
36
+ import { AppBar as AppbarComponent } from '@olea-bps/components';
37
+ import { OtherCourses as OtherCoursesComponent } from '@olea-bps/components';
38
+ import { TimetableList as TimetableListComponent } from '@olea-bps/components';
39
+ import { TimetableCodeInput } from '@olea-bps/components';
40
+ import { CourseDetailDialog } from '@olea-bps/components';
41
+
42
+ import componentStyles from './styles';
43
+
44
+ /**
45
+ * Timetable View
46
+ *
47
+ * Displays the timetable, if the has imported one. If no timetable
48
+ * is available, the view will provide a import. The view also
49
+ * provides a button to import a new timetable.
50
+ *
51
+ * Parameters:
52
+ * - none
53
+ *
54
+ * Navigation-Parameters:
55
+ * - none
56
+ */
57
+ function TimetableViewList(props) {
58
+ const theme = useTheme();
59
+ const { t } = useTranslation();
60
+ const [selectedCourse, setSelectedCourse] = useState(null);
61
+
62
+ // Get all required constants from props
63
+ const {
64
+ settings: { settingsGeneral: { language } },
65
+ } = props;
66
+
67
+ const { colors, themeStyles, appSettings: { modules: { timetable: { downloadEnabled } } } } = theme;
68
+
69
+ const componentName = TimetableViewList.name;
70
+ const timetableSettings = theme?.appSettings?.modules?.timetable;
71
+ const disabledWeekdays = timetableSettings?.disabledWeekdays ?? [];
72
+ const weeksToRender = timetableSettings?.weeksToRender ?? 2;
73
+ // Jetziger Zeitpunkt
74
+ const now = DateTime.now();
75
+ // Zeitpunkt, der auf den Wochenanfang zeigt
76
+ const startDate = now.startOf('week');
77
+ // Zeitpunkt, der auf den letzten anzuzeigenen Tag zeigt
78
+ const endDate = startDate.plus({ weeks: weeksToRender }).endOf('week');
79
+
80
+ // Generiert die Tabs beginnend beim Wochenanfang bis zum letzten Tag der Ansicht
81
+ // Es werden die nicht anzuzeigenden Wochentage herausgefiltert
82
+ const daysTabViewRoutes = useMemo(
83
+ () => {
84
+ // Berechenen der Anzahl der zu zeigenden Tage bzw. Anzahl der Tabs
85
+ const daysToRender = Duration.fromDurationLike({ weeks: weeksToRender }).as('days');
86
+
87
+ // Erstellen der Tabs
88
+ return Array.from(
89
+ // Es wird ein Array erzeugt, welches so lang ist wie die Anzahl der zu zeigenden Tage
90
+ { length: daysToRender },
91
+ // Tabs anhand des Indexes berechnen
92
+ (_, index) => {
93
+
94
+ // Festlegen des Tages des entsprechenden Tabs beim Index
95
+ const currentDay = startDate
96
+ // Es wird der Start genommen und um index-viele Tage in die Zukunft verschoben
97
+ .plus({ days: index })
98
+ // Abschliesend wird die Uhrzeit auf 00:00, also den Anfang des Tages, gesetzt.
99
+ .startOf('day');
100
+
101
+ // Tab wird als Objekt zurückgeben
102
+ return {
103
+ // Der Schlüssel des Tabs ist das Datum des Tabs im ISO-Format
104
+ // Somit lässt sich über das Datum der entsprechende Tab aktivieren
105
+ key: currentDay.toISODate(),
106
+ // Für die weiter Verarbeitung, wird das Datum als Datumsobjekt mitgeben
107
+ // Dem Datumsobject wird die eingestellt Sprache gegeben
108
+ date: currentDay.setLocale(language),
109
+ }
110
+ }
111
+ )
112
+ .filter(dayRoute => !disabledWeekdays.includes(dayRoute.date.weekday))
113
+ },
114
+ [weeksToRender, disabledWeekdays, startDate, language]
115
+ );
116
+ // Create state for tab view index
117
+ const [daysTabViewActiveRouteIndex, setDaysTabViewActiveRouteIndex] = useState(() => {
118
+ // Present day
119
+ const today = DateTime.now().startOf('day');
120
+ // Search for the index of today or the day after. If no index can be found, -1 is taken.
121
+ let initialDayTabIndex = daysTabViewRoutes.findIndex(dayTab => dayTab.date >= today);
122
+ // If no index could be found, the last tab is taken.
123
+ // If only one week is rendered and the weekend days are switched off, no following day will be found.
124
+ initialDayTabIndex = initialDayTabIndex === -1 ? daysTabViewRoutes.length - 1 : initialDayTabIndex;
125
+ return initialDayTabIndex;
126
+ });
127
+
128
+ const [timetableCode] = useTimetableCode();
129
+ const [courses, refreshCourses] = useCourses();
130
+
131
+ /**
132
+ * State der speichert, ob die Code-Eingabe gezeigt werden soll.
133
+ *
134
+ * Der State kann 3 Zustände annehmen:
135
+ * - null : Es wurde noch kein Stundenplan importiert -> Code-Eingabe wird angezeigt
136
+ * - true : Der Nutzer möchte die Code-Eingabe sehen -> Code-Eingabe wird angezeigt
137
+ * - false: Die Nutzer möchte die Code-Eingabe nicht sehen -> Stundenplan wird angezeigt
138
+ *
139
+ * Der null-Wert wird benutzt um festzustellen, dass die App die Code-Eingabe anzeigt, weil bisher kein Stundenplan importiert wurde.
140
+ * Somit kann nach dem Import geprüft werden, ob der State den null-Wert hält und automatisch zu den Stundenplan schalten.
141
+ */
142
+ const [showImport, setShowImport] = useState(timetableCode === null && courses === null ? true : false);
143
+ const [coursesRefreshing, setCoursesRefreshing] = useState(false);
144
+
145
+ // Generate styles. Will be generated only if not present or the theme property changes.
146
+ const styles = useMemo(
147
+ () => StyleSheet.create(componentStyles(theme)),
148
+ [theme]
149
+ )
150
+
151
+ const otherCourses = courses?.filter?.(course => course?.times?.some(courseTime => courseTime?.dayOfWeek === 0));
152
+ const activeTabDate = daysTabViewRoutes[daysTabViewActiveRouteIndex]?.date;
153
+ const activeTabWeek = activeTabDate.weekNumber;
154
+
155
+ // Refreshen der Vorlesungen, wenn die View angeziegt wird und den Fokus vom nutzer bekommt.
156
+ useFocusEffect(
157
+ useCallback(
158
+ () => {
159
+ refreshCourses(startDate.toISODate(), endDate.toISODate())
160
+ .catch((reason) => {
161
+ if (reason instanceof ApiProviderNotInitializedError) {
162
+ console.error(componentName, ': ', reason);
163
+ } else {
164
+ console.debug(componentName, ': ', reason);
165
+ }
166
+ });
167
+ },
168
+ [])
169
+ )
170
+
171
+ /*
172
+ Depending on the existence of a timetable, either the timetable or the view for the input of a timetablecode will be rendered
173
+ To decide which components have to rendered, the flag showImport is used.
174
+ If its value is true, there already is an imported timetable as well as a list of courses
175
+ and the function for rendering the timetable-tabview(renderTabView) is called.
176
+ Otherwise, the function for entering a timetablecode will be called(renderTimetableCodeInput)
177
+ */
178
+ return (
179
+ <SafeAreaView style={[styles.container, themeStyles.appSafeAreaContainer]}>
180
+ <AppbarComponent {...props}
181
+ title={t('timetable:title')}
182
+ subtitle={`${t('timetable:weekNumber', { kw: activeTabWeek })} / ${t(activeTabWeek % 2 === 0 ? 'timetable:evenWeek' : 'timetable:oddWeek')}`}
183
+ // in addition to the selection of the icon for the right Action in the app-bar the color for the icon also has to be defined
184
+ rightAction={
185
+ <>
186
+ {
187
+ downloadEnabled
188
+ ? <Appbar.Action
189
+ icon={'download'}
190
+ onPress={
191
+ async () => {
192
+ const { modules: { timetable: { downloadUrl } } } = props.theme.appSettings;
193
+ await Linking.openURL(downloadUrl + timetableCode);
194
+ }
195
+ }
196
+ color={colors.appbarIconColor}
197
+ accessibilityLabel={t('accessibility:timetable:downloadTimetableButton')}
198
+ />
199
+ : null
200
+ }
201
+ <Appbar.Action
202
+ icon={showImport ? 'table' : 'table-plus'}
203
+ color={colors.appbarIconColor}
204
+ onPress={
205
+ () => setShowImport(currentValue => !currentValue)
206
+ }
207
+ accessibilityLabel={t(
208
+ showImport
209
+ ? 'accessibility:timetable:showImportButton'
210
+ : 'accessibility:timetable:showTimetableButton'
211
+ )}
212
+ />
213
+ </>
214
+ }
215
+ />
216
+ {
217
+ !(showImport) // !FIXME: If-Cases sollten getauscht werden, damit Code einfacher wird
218
+ ? <View style={themeStyles.container}>
219
+ <TabView
220
+ style={props.style}
221
+ navigationState={{ index: daysTabViewActiveRouteIndex, routes: daysTabViewRoutes }}
222
+ onIndexChange={setDaysTabViewActiveRouteIndex}
223
+ renderTabBar={
224
+ (props) =>
225
+ <TabBar
226
+ {...props}
227
+ scrollEnabled
228
+ style={themeStyles.tabs}
229
+ labelStyle={themeStyles.tab}
230
+ activeColor={themeStyles.tabs.activeColor}
231
+ inactiveColor={themeStyles.tabs.inactiveColor}
232
+ indicatorStyle={themeStyles.tabIndicator}
233
+ tabStyle={{ width: 'auto', paddingHorizontal: 20 }}
234
+ renderTabBarItem={({ route, navigationState, ...rest}) =>
235
+ <TabBarItem
236
+ {...rest}
237
+ key={route.key}
238
+ route={route}
239
+ navigationState={navigationState}
240
+ labelStyle={themeStyles.tab}
241
+ activeColor={themeStyles.tabs.activeColor}
242
+ inactiveColor={themeStyles.tabs.inactiveColor}
243
+ // Die einbindung von moment.js zum Anzeigen des Wochentages sollte langfristig entfernt werden.
244
+ // Funktioniert die Luxon funktionalität der Wochenanzeige nicht unter iOS datetime.toFormat('ccc')
245
+ label={
246
+ // Generieren das Tab-Textes
247
+ ({ route }) => {
248
+ // Datumsobject aus dem Tab holen
249
+ const date = route.date;
250
+ // Kurzbezeichnung des Wochentages bestimmen
251
+ const shortWeekDay = t(`common:isoWeekDay:${date.weekday}:short`); // Falls hermes Intl soweit ist, lieber folgende Zeile verwenden: const shortWeekDay = date.weekdayShort;
252
+ // Datum, bestehend aus Tag und Monat, bestimmen
253
+ const localeDate = date.toLocaleString(
254
+ {
255
+ day: '2-digit',
256
+ month: '2-digit',
257
+ }
258
+ );
259
+
260
+ // Tab-Text aus Wochentag und Datum generieren
261
+ return <Text>{shortWeekDay}, {localeDate}</Text>;
262
+ }
263
+ }
264
+ accessible={true}
265
+ accessibilityLabel={route.date.toLocaleString(DateTime.DATE_FULL)}
266
+ />
267
+ }
268
+ />
269
+ }
270
+ renderScene={
271
+ ({ route }) => {
272
+ const dayIsoDate = route.key;
273
+ const coursesOfDay = courses?.[dayIsoDate];
274
+
275
+ return (
276
+ <View style={themeStyles.container}>
277
+ <View style={styles.horizontalSeperator} />
278
+ <ScrollView
279
+ refreshControl={
280
+ <RefreshControl
281
+ refreshing={coursesRefreshing}
282
+ onRefresh={
283
+ () => {
284
+ setCoursesRefreshing(true);
285
+ refreshCourses(dayIsoDate, dayIsoDate)
286
+ .finally(() => setCoursesRefreshing(false));
287
+ }
288
+ }
289
+ />
290
+ }>
291
+ <View style={styles.renderList}>
292
+ {
293
+ coursesOfDay?.length
294
+ ? coursesOfDay.map(
295
+ (course, index) => {
296
+ const courseTime = course?.times?.[0];
297
+
298
+ return (
299
+ <TimetableListComponent
300
+ {...props}
301
+ key={`${course?.title?.data}${course?.type?.data}${courseTime.start}${courseTime.end}`}
302
+ course={course}
303
+ times={courseTime}
304
+ onCourseSelected={course => setSelectedCourse(course)}
305
+ />
306
+ )
307
+ }
308
+ )
309
+ : <View style={styles.emptyListContainer}>
310
+ <Text style={styles.emptyText}>{t('timetable:noEvents')}</Text>
311
+ </View>
312
+ }
313
+ </View>
314
+ </ScrollView>
315
+ </View>
316
+ );
317
+ }
318
+ }
319
+ lazy
320
+ lazyPreloadDistance={2}
321
+ renderLazyPlaceholder={(route) =>
322
+ <View style={styles.centerContainer}>
323
+ <ActivityIndicator
324
+ style={styles.activity}
325
+ size={'large'}
326
+ color={theme.colors.loadingIndicator}
327
+ />
328
+ </View>
329
+ }
330
+ />
331
+ {
332
+ otherCourses?.length
333
+ ? <TouchableOpacity
334
+ style={styles.otherContainer}
335
+ onPress={
336
+ () => {
337
+ // Never provide props directly if you are using translations in this or a parent component
338
+ const otherCoursesComponentProps = { navigation: { ...props.navigation } };
339
+
340
+ store.dispatch(
341
+ {
342
+ type: 'UPDATE_MODAL_CONTENT',
343
+ modalContent: (
344
+ <View style={styles.modalContainer}>
345
+ <OtherCoursesComponent
346
+ {...otherCoursesComponentProps}
347
+ course={otherCourses}
348
+ />
349
+ </View>
350
+ )
351
+ }
352
+ );
353
+ props.navigation.navigate('Modal');
354
+ }
355
+ }
356
+ >
357
+ <Text
358
+ style={styles.otherTitle}
359
+ >
360
+ {t('timetable:moreEvents')}
361
+ </Text>
362
+ </TouchableOpacity>
363
+ : null
364
+ }
365
+
366
+
367
+ <CourseDetailDialog
368
+ course={selectedCourse}
369
+ visible={selectedCourse ? true : false}
370
+ onClose={() => setSelectedCourse(null)}
371
+ onDismiss={() => setSelectedCourse(null)}
372
+ />
373
+
374
+ </View>
375
+ : <TimetableCodeInput
376
+ onImportSuccessfullyFinished={
377
+ // Wenn Stundenplan erfolgreich importiert wurde, wird der Stundenplan angezeigt
378
+ () => setShowImport(false)
379
+ }
380
+ />
381
+ }
382
+ </SafeAreaView>
383
+ );
384
+ }
385
+
386
+ const mapStateToProps = state => {
387
+ return {
388
+ pluginComponent: state.pluginReducer.timetable.component,
389
+ pluginStyles: state.pluginReducer.timetable.styles,
390
+ courses: state.apiReducer.courses,
391
+ coursesStatus: state.apiReducer.coursesStatus,
392
+ refreshing: state.stateReducer.refreshing,
393
+ settings: state.settingReducer
394
+ };
395
+ };
396
+
397
+ export default connect(mapStateToProps, { onUpdateRefreshing })(TimetableViewList)
@@ -0,0 +1,55 @@
1
+ import {Dimensions} from "react-native";
2
+
3
+ export default function(theme) {
4
+ const width = Dimensions.get('window').width;
5
+ return {
6
+ horizontalSeperator: {
7
+ height: 1,
8
+ width: "100%",
9
+ backgroundColor: theme.colors.listSeperator
10
+ },
11
+ otherContainer: {
12
+ width: width,
13
+ height: "10%",
14
+ backgroundColor: theme.colors.primary,
15
+ shadowColor: theme.colors.shadow,
16
+ shadowOffset: {
17
+ width: 0,
18
+ height: 1,
19
+ },
20
+ shadowOpacity: 0.5,
21
+ shadowRadius: 10,
22
+ elevation: 3,
23
+ justifyContent: 'center'
24
+ },
25
+ otherTitle: {
26
+ fontSize: theme.fontSizes.xxl,
27
+ ...theme.fonts.medium,
28
+ textAlign: "center",
29
+ padding: theme.paddings.small,
30
+ color: theme.colors.primaryText,
31
+ },
32
+ container: {
33
+ flex: 1,
34
+ backgroundColor: theme.colors.contentBackground,
35
+ },
36
+ modalContainer: {
37
+ flex: 1,
38
+ },
39
+ renderList: {
40
+ marginBottom: theme.paddings.small
41
+ },
42
+ emptyListContainer: {
43
+ alignItems: "center",
44
+ justifyContent: "center",
45
+ width: "100%",
46
+ height: 400,
47
+ padding: theme.paddings.default,
48
+ marginTop: theme.paddings.default
49
+ },
50
+ emptyText: {
51
+ textAlign: "center",
52
+ fontSize: theme.fontSizes.title
53
+ }
54
+ }
55
+ };
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Licensed under the Apache License, Version 2.0 (the "License");
3
+ * you may not use this file except in compliance with the License.
4
+ * You may obtain a copy of the License at
5
+ *
6
+ * http://www.apache.org/licenses/LICENSE-2.0
7
+ *
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ */
14
+
15
+ import React from 'react';
16
+ import {SafeAreaView, StyleSheet, ActivityIndicator, View, Linking} from 'react-native';
17
+ import {connect} from 'react-redux'
18
+ import {Appbar, withTheme} from "react-native-paper";
19
+ import { WebView } from 'react-native-webview';
20
+ import merge from 'lodash/merge';
21
+
22
+ import componentStyles from "./styles";
23
+ import { AppBar as AppbarComponent } from '@olea-bps/components';
24
+ import IconsOpenasist from "@olea-bps/icons-openasist";
25
+
26
+
27
+ /**
28
+ * Webview View
29
+ *
30
+ * Use this víew to show a webpage (via url).
31
+ *
32
+ * Parameters:
33
+ * - none
34
+ *
35
+ * Navigation-Parameters:
36
+ * - title: Header title
37
+ * - url: Webpage Url
38
+ */
39
+ class WebviewsView extends React.Component {
40
+ static navigationOptions = {
41
+ header: null
42
+ };
43
+
44
+ state = {
45
+ refreshing: false,
46
+ };
47
+
48
+ // Styles of this component
49
+ styles;
50
+
51
+
52
+
53
+ webView = {
54
+ canGoBack: false,
55
+ ref: null,
56
+ };
57
+
58
+ jsScript = `
59
+ const meta = document.createElement('meta');
60
+ meta.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0');
61
+ meta.setAttribute('name', 'viewport');
62
+ document.head.appendChild(meta);
63
+ `;
64
+
65
+ constructor(props) {
66
+ super(props);
67
+ // ------------------------------------------------------------------------
68
+ // PLUGIN FUNCTIONALITY
69
+ // ------------------------------------------------------------------------
70
+
71
+ const {pluginStyles, theme} = this.props;
72
+ this.styles = componentStyles(theme);
73
+
74
+ if (pluginStyles) {
75
+ this.styles = merge(this.styles, pluginStyles);
76
+ }
77
+
78
+ this.styles = StyleSheet.create(this.styles);
79
+
80
+ // ------------------------------------------------------------------------
81
+ }
82
+
83
+ /**
84
+ * Intercept URL loading in the WebView.
85
+ * If the base URL of the event is different from the initial base URL, open it in the external browser.
86
+ * Still allows url navigation with # values in the URL by comparing the base URL of the event with the base URL of the initial URL.
87
+ */
88
+ onShouldStartLoadWithRequest = (event) => {
89
+ const {url} = this.props.route.params;
90
+ const baseUrl = url.split('#')[0];
91
+ const eventBaseUrl = event.url.split('#')[0];
92
+
93
+ if (eventBaseUrl !== baseUrl) {
94
+ Linking.openURL(event.url);
95
+ return false;
96
+ }
97
+ return true;
98
+ }
99
+
100
+ render() {
101
+ const {route} = this.props;
102
+ const {colors, themeStyles, customScript} = this.props.theme;
103
+ // The language is necessary because it is needed in the header in the source-prop of the webview elemnent
104
+ // to display the website in the selected system-language
105
+ const {language} = this.props.settings.settingsGeneral
106
+
107
+ // Get the current title of the element, that should be displayed e.g. Imprint, data policy, etc.
108
+ const title = route.params && route.params.title || null;
109
+ // Get the url for the current element defined in the settings
110
+ const url = route.params && route.params.url || null;
111
+
112
+ // The returned View contains a Appbar followed by the webview that calls the websites provided in the URL
113
+ return (
114
+ <SafeAreaView style={[this.styles.container, themeStyles.appSafeAreaContainer]}>
115
+ <View style={{zIndex: 100, position: 'relative'}}>
116
+ <AppbarComponent {...this.props}
117
+ title={title}
118
+ leftAction={
119
+ <Appbar.Action
120
+ icon={props => <IconsOpenasist {...props} icon={'back'} color={colors.primaryText} /> }
121
+ onPress={() => {
122
+ if (this.webView.canGoBack) {
123
+ this.webView.ref.goBack();
124
+ } else {
125
+ this.props.navigation.goBack(null);
126
+ }
127
+ }} />
128
+ }
129
+ rightAction={<Appbar.Action icon="refresh" onPress={() => this.webView.ref.reload()}/>}/>
130
+ </View>
131
+ <WebView
132
+ ref={ref => this.webView.ref = ref}
133
+ // In addition to only providing the url as a source, headers can be defined that will contain additional information
134
+ // In this case the header provides information about the current system-language in order to display a given translation of the website
135
+ source={{ uri: url, headers: {
136
+ "Accept-Language": `${language}`,
137
+ } }}
138
+ startInLoadingState={true}
139
+ renderLoading={() => <ActivityIndicator style={this.styles.activity} size="large" color={colors.loadingIndicator} />}
140
+ onNavigationStateChange={(navState) => { this.webView.canGoBack = navState.canGoBack; }}
141
+ injectedJavaScript={this.jsScript + customScript}
142
+ onMessage={() => {}}
143
+ onShouldStartLoadWithRequest={this.onShouldStartLoadWithRequest}
144
+ />
145
+ </SafeAreaView>
146
+ );
147
+ }
148
+ }
149
+
150
+ const mapStateToProps = state => {
151
+ return {
152
+ // The settings are necessary to determine the current system-language so that the websites in the webview can be
153
+ // translated in the selected language
154
+ settings: state.settingReducer
155
+ };
156
+ };
157
+
158
+ export default connect(mapStateToProps, null)(withTheme(WebviewsView))
@@ -0,0 +1,11 @@
1
+ export default function(theme) {
2
+ return {
3
+ container: {
4
+ flex: 1,
5
+ backgroundColor: theme.colors.background,
6
+ },
7
+ activity: {
8
+ padding: 20
9
+ }
10
+ }
11
+ };
package/index.js ADDED
@@ -0,0 +1,25 @@
1
+ export { default as Callmanager } from './Callmanager';
2
+ export { default as Canteens } from './Canteens';
3
+ export { default as Dashboard } from './Dashboard';
4
+ export { default as DashboardHtwk } from './DashboardHtwk';
5
+ export { default as Event } from './Event';
6
+ export { default as FeedList } from './FeedList';
7
+ export { default as FeedNews } from './FeedNews';
8
+ export { default as Flexmenu } from './Flexmenu';
9
+ export { default as FlexmenuWebview } from './FlexmenuWebview';
10
+ export { default as Howhy } from './Howhy';
11
+ export { default as Jobs } from './Jobs';
12
+ export { default as MainMenu } from './MainMenu';
13
+ export { default as NewsTabbar } from './NewsTabbar';
14
+ export { default as Opal } from './Opal';
15
+ export { default as PublicTransportTicket } from './PublicTransportTicket';
16
+ export { default as Search } from './Search';
17
+ export { default as SettingsAccessibility } from './SettingsAccessibility';
18
+ export { default as SettingsAppInfo } from './SettingsAppInfo';
19
+ export { default as SettingsCanteens } from './SettingsCanteens';
20
+ export { default as SettingsGeneral } from './SettingsGeneral';
21
+ export { default as SettingsNotifications } from './SettingsNotifications';
22
+ export { default as SettingsUser } from './SettingsUser';
23
+ export { default as TimetableCalendar } from './TimetableCalendar';
24
+ export { default as TimetableList } from './TimetableList';
25
+ export { default as Webviews } from './Webviews';
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@olea-bps/views",
3
+ "version": "1.0.0",
4
+ "description": "Consolidated views for OLEA",
5
+ "main": "index.js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/tuc-urz/olea.git",
9
+ "directory": "packages/views"
10
+ },
11
+ "author": "codeculture<info@codeculture.de>",
12
+ "license": "Apache-2.0",
13
+ "files": [
14
+ "index.js",
15
+ "*/index.js",
16
+ "*/styles.js",
17
+ "*/**/*"
18
+ ],
19
+ "dependencies": {
20
+ "react-native-paper": "^5.14.5",
21
+ "@olea-bps/core": "^1.0.0",
22
+ "react-native-webview": "13.15.0",
23
+ "@react-navigation/drawer": "^7.3.12",
24
+ "@react-navigation/native": "^7.1.9",
25
+ "react-native-elements": "^3.4.3",
26
+ "react-native-modalbox": "^2.0.2",
27
+ "react-native-vector-icons": "^10.2.0",
28
+ "react-native-tab-view": "^4.1.3",
29
+ "@olea-bps/icons-openasist": "^1.0.0",
30
+ "expo-application": "^6.1.5",
31
+ "moment": "^2.29.4",
32
+ "react-native-swipe-gestures": "^1.0.5",
33
+ "@olea-bps/views": "^1.0.0",
34
+ "@olea-bps/components": "^1.0.0"
35
+ },
36
+ "peerDependencies": {
37
+ "react": "^19.0.0",
38
+ "react-native": "^0.81.0",
39
+ "react-native-paper": "^5.0.0"
40
+ }
41
+ }