@olea-bps/base 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 (268) hide show
  1. package/components/AppBar/index.js +84 -0
  2. package/components/AppBar/styles.js +27 -0
  3. package/components/BookDetail/index.js +268 -0
  4. package/components/BookDetail/styles.js +124 -0
  5. package/components/ComponentJobsFilter/index.js +188 -0
  6. package/components/ComponentJobsFilter/styles.js +12 -0
  7. package/components/ConnectivityWarning/index.js +65 -0
  8. package/components/ConnectivityWarning/styles.js +19 -0
  9. package/components/ContactDetail/index.js +232 -0
  10. package/components/ContactDetail/styles.js +32 -0
  11. package/components/CourseDetail/index.js +357 -0
  12. package/components/CourseDetail/styles.js +59 -0
  13. package/components/CourseDetailDialog/index.js +169 -0
  14. package/components/CourseDetailDialog/styles.js +116 -0
  15. package/components/CourseInfo/index.js +219 -0
  16. package/components/CourseInfo/styles.js +40 -0
  17. package/components/DevelopmentDialog/index.js +214 -0
  18. package/components/DevelopmentDialog/styles.js +10 -0
  19. package/components/EventCodeInput/index.js +149 -0
  20. package/components/EventCodeInput/styles.js +108 -0
  21. package/components/FlexMenuEntry/index.js +84 -0
  22. package/components/FlexMenuEntry/styles.js +27 -0
  23. package/components/MainMenuEntry/index.js +88 -0
  24. package/components/MainMenuEntry/styles.js +28 -0
  25. package/components/MealItem/index.js +87 -0
  26. package/components/MealItem/styles.js +84 -0
  27. package/components/MensaMenu/index.js +305 -0
  28. package/components/MensaMenu/styles.js +94 -0
  29. package/components/MensaSlider/index.js +188 -0
  30. package/components/MensaSlider/styles.js +53 -0
  31. package/components/Modal/index.js +106 -0
  32. package/components/Modal/styles.js +8 -0
  33. package/components/NewsDetail/index.js +377 -0
  34. package/components/NewsDetail/styles.js +77 -0
  35. package/components/NewsList/index.js +120 -0
  36. package/components/NewsList/styles.js +19 -0
  37. package/components/NewsListItem/index.js +89 -0
  38. package/components/NewsListItem/styles.js +32 -0
  39. package/components/OtherCourses/index.js +152 -0
  40. package/components/OtherCourses/styles.js +10 -0
  41. package/components/PtsDeparture/index.js +140 -0
  42. package/components/PtsDeparture/styles.js +7 -0
  43. package/components/PtsStation/index.js +186 -0
  44. package/components/PtsStation/styles.js +47 -0
  45. package/components/QuickLinks/index.js +127 -0
  46. package/components/QuickLinks/styles.js +45 -0
  47. package/components/RoomDetail/index.js +281 -0
  48. package/components/RoomDetail/styles.js +56 -0
  49. package/components/ScaledImage/index.js +92 -0
  50. package/components/SearchResults/index.js +362 -0
  51. package/components/SearchResults/styles.js +59 -0
  52. package/components/SettingSection/index.js +54 -0
  53. package/components/SettingSection/styles.js +15 -0
  54. package/components/SettingsDialog/index.js +52 -0
  55. package/components/SettingsDialog/styles.js +12 -0
  56. package/components/SettingsDialogRadio/index.js +66 -0
  57. package/components/SettingsDialogRadio/styles.js +7 -0
  58. package/components/SettingsDialogSelect/index.js +73 -0
  59. package/components/SettingsDialogSelect/styles.js +7 -0
  60. package/components/TimetableCodeInput/index.js +205 -0
  61. package/components/TimetableCodeInput/styles.js +28 -0
  62. package/components/TimetableDay/index.js +252 -0
  63. package/components/TimetableDay/styles.js +103 -0
  64. package/components/TimetableEvent/index.js +163 -0
  65. package/components/TimetableEvent/styles.js +108 -0
  66. package/components/TimetableList/index.js +180 -0
  67. package/components/TimetableList/styles.js +106 -0
  68. package/components/TimetableMonth/index.js +156 -0
  69. package/components/TimetableMonth/styles.js +29 -0
  70. package/components/TimetableWeek/index.js +230 -0
  71. package/components/TimetableWeek/styles.js +58 -0
  72. package/components/TopNews/index.js +282 -0
  73. package/components/TopNews/styles.js +125 -0
  74. package/components/TopNewsHtwk/index.js +279 -0
  75. package/components/TopNewsHtwk/styles.js +142 -0
  76. package/components/WebView/index.js +108 -0
  77. package/components/WebView/styles.js +11 -0
  78. package/context/context-callmanager/TucCallManager.js +74 -0
  79. package/context/context-callmanager/index.js +128 -0
  80. package/context/context-canteen/AsistServerApiProvider.js +126 -0
  81. package/context/context-canteen/CollektorVersion2ApiProvider.js +100 -0
  82. package/context/context-canteen/index.js +692 -0
  83. package/context/context-connectivity/index.js +85 -0
  84. package/context/context-event/AsistServerClient.js +82 -0
  85. package/context/context-event/index.js +205 -0
  86. package/context/context-flex-menu/AsistServerApiProvider.js +0 -0
  87. package/context/context-flex-menu/CollectorVersion2ApiProvider.js +32 -0
  88. package/context/context-flex-menu/index.js +160 -0
  89. package/context/context-info-dialog/CollektorVersion2ApiProvider.js +53 -0
  90. package/context/context-info-dialog/ProviderErrors.js +22 -0
  91. package/context/context-info-dialog/index.js +190 -0
  92. package/context/context-mails/MailService.js +147 -0
  93. package/context/context-mails/TucUnseenApiProvider.js +65 -0
  94. package/context/context-mails/index.js +131 -0
  95. package/context/context-news/CollektorVersion2ApiProvider.js +68 -0
  96. package/context/context-news/index.js +155 -0
  97. package/context/context-public-transport-ticket/CollektorVersion2ApiProvider.js +45 -0
  98. package/context/context-public-transport-ticket/ProviderErrors.js +11 -0
  99. package/context/context-public-transport-ticket/index.js +175 -0
  100. package/context/context-timetable/CollectorVersion2ApiProvider.js +102 -0
  101. package/context/context-timetable/ProviderErrors.js +22 -0
  102. package/context/context-timetable/TimetableService.js +357 -0
  103. package/context/context-timetable/index.js +215 -0
  104. package/context/context-user/index.js +586 -0
  105. package/index.js +178 -0
  106. package/libraries/base-api-provider/hooks.js +24 -0
  107. package/libraries/base-api-provider/http-api-provider.js +168 -0
  108. package/libraries/base-api-provider/index.js +20 -0
  109. package/libraries/core/api/canteens.js +88 -0
  110. package/libraries/core/api/corona.js +45 -0
  111. package/libraries/core/api/courses.js +54 -0
  112. package/libraries/core/api/device.js +98 -0
  113. package/libraries/core/api/feed.js +144 -0
  114. package/libraries/core/api/feedback.js +123 -0
  115. package/libraries/core/api/jobs.js +48 -0
  116. package/libraries/core/api/library.js +67 -0
  117. package/libraries/core/api/lostfound.js +77 -0
  118. package/libraries/core/api/occupancy.js +44 -0
  119. package/libraries/core/api/officehours.js +25 -0
  120. package/libraries/core/api/poi.js +25 -0
  121. package/libraries/core/api/pts.js +68 -0
  122. package/libraries/core/api/rooms.js +31 -0
  123. package/libraries/core/api/survey.js +121 -0
  124. package/libraries/core/api/telephone.js +32 -0
  125. package/libraries/core/api/tucrooms.js +31 -0
  126. package/libraries/core/constants/actions.js +75 -0
  127. package/libraries/core/constants/api.js +146 -0
  128. package/libraries/core/constants/enums.js +5 -0
  129. package/libraries/core/helper/date.js +9 -0
  130. package/libraries/core/helper/format.helper.js +2 -0
  131. package/libraries/core/index.js +60 -0
  132. package/libraries/core/redux/actions/notifications.js +6 -0
  133. package/libraries/core/redux/actions/setting.js +75 -0
  134. package/libraries/core/redux/actions/state.js +74 -0
  135. package/libraries/core/redux/asyncDispatch.js +27 -0
  136. package/libraries/core/redux/reducers/api.js +190 -0
  137. package/libraries/core/redux/reducers/index.js +32 -0
  138. package/libraries/core/redux/reducers/notifications.js +16 -0
  139. package/libraries/core/redux/reducers/setting.js +99 -0
  140. package/libraries/core/redux/reducers/state.js +122 -0
  141. package/libraries/core/redux/selectors.js +123 -0
  142. package/libraries/core/redux/store.js +40 -0
  143. package/libraries/core/services/data.js +96 -0
  144. package/libraries/core/services/root-navigation.js +36 -0
  145. package/libraries/core/services/search.js +175 -0
  146. package/libraries/core-plugins/enums/replaceTypes.js +53 -0
  147. package/libraries/core-plugins/index.js +21 -0
  148. package/libraries/core-plugins/redux/actions/plugin.js +13 -0
  149. package/libraries/core-plugins/redux/reducers/plugin.js +210 -0
  150. package/libraries/icons-openasist/index.js +143 -0
  151. package/libraries/notifications/index.js +268 -0
  152. package/libraries/notifications/services/subscriber.service.js +123 -0
  153. package/libraries/react-native-webview-autoheight/README.md +47 -0
  154. package/libraries/react-native-webview-autoheight/index.js +140 -0
  155. package/libraries/react-native-webview-autoheight/package.json +37 -0
  156. package/libraries/react-native-webview-autoheight/utils.js +268 -0
  157. package/libraries/redux-offline/.eslintignore +1 -0
  158. package/libraries/redux-offline/.github/ISSUE_TEMPLATE/redux-offline-core-issues-template.md +25 -0
  159. package/libraries/redux-offline/.prettierrc +6 -0
  160. package/libraries/redux-offline/LICENSE +21 -0
  161. package/libraries/redux-offline/README.md +133 -0
  162. package/libraries/redux-offline/flow-typed/npm/redux-logger_vx.x.x.js +109 -0
  163. package/libraries/redux-offline/flow-typed/npm/redux_v4.x.x.js +100 -0
  164. package/libraries/redux-offline/lib/actions.js +46 -0
  165. package/libraries/redux-offline/lib/config.js +15 -0
  166. package/libraries/redux-offline/lib/constants.js +17 -0
  167. package/libraries/redux-offline/lib/defaults/defaultCommit.js +11 -0
  168. package/libraries/redux-offline/lib/defaults/defaultRollback.js +11 -0
  169. package/libraries/redux-offline/lib/defaults/detectNetwork.js +33 -0
  170. package/libraries/redux-offline/lib/defaults/detectNetwork.native.js +211 -0
  171. package/libraries/redux-offline/lib/defaults/discard.js +18 -0
  172. package/libraries/redux-offline/lib/defaults/effect.js +87 -0
  173. package/libraries/redux-offline/lib/defaults/index.js +32 -0
  174. package/libraries/redux-offline/lib/defaults/offlineStateLens.js +24 -0
  175. package/libraries/redux-offline/lib/defaults/persist.js +9 -0
  176. package/libraries/redux-offline/lib/defaults/persist.native.js +17 -0
  177. package/libraries/redux-offline/lib/defaults/persistAutoRehydrate.js +8 -0
  178. package/libraries/redux-offline/lib/defaults/queue.js +27 -0
  179. package/libraries/redux-offline/lib/defaults/retry.js +29 -0
  180. package/libraries/redux-offline/lib/index.js +115 -0
  181. package/libraries/redux-offline/lib/middleware.js +56 -0
  182. package/libraries/redux-offline/lib/offlineActionTracker.js +43 -0
  183. package/libraries/redux-offline/lib/send.js +112 -0
  184. package/libraries/redux-offline/lib/types.js +3 -0
  185. package/libraries/redux-offline/lib/updater.js +111 -0
  186. package/libraries/redux-offline/package.json +69 -0
  187. package/libraries/redux-offline/src/__tests__/defaults/discard.js +22 -0
  188. package/libraries/redux-offline/src/__tests__/defaults/effect.js +118 -0
  189. package/libraries/redux-offline/src/__tests__/index.js +116 -0
  190. package/libraries/redux-offline/src/__tests__/middleware.js +185 -0
  191. package/libraries/redux-offline/src/__tests__/offlineActionTracker.js +54 -0
  192. package/libraries/redux-offline/src/__tests__/send.js +208 -0
  193. package/libraries/redux-offline/src/actions.js +36 -0
  194. package/libraries/redux-offline/src/config.js +9 -0
  195. package/libraries/redux-offline/src/constants.js +18 -0
  196. package/libraries/redux-offline/src/defaults/defaultCommit.js +7 -0
  197. package/libraries/redux-offline/src/defaults/defaultRollback.js +7 -0
  198. package/libraries/redux-offline/src/defaults/detectNetwork.js +16 -0
  199. package/libraries/redux-offline/src/defaults/detectNetwork.native.js +148 -0
  200. package/libraries/redux-offline/src/defaults/discard.js +19 -0
  201. package/libraries/redux-offline/src/defaults/effect.js +86 -0
  202. package/libraries/redux-offline/src/defaults/index.js +25 -0
  203. package/libraries/redux-offline/src/defaults/offlineStateLens.js +11 -0
  204. package/libraries/redux-offline/src/defaults/persist.js +4 -0
  205. package/libraries/redux-offline/src/defaults/persist.native.js +9 -0
  206. package/libraries/redux-offline/src/defaults/persistAutoRehydrate.js +4 -0
  207. package/libraries/redux-offline/src/defaults/queue.js +20 -0
  208. package/libraries/redux-offline/src/defaults/retry.js +18 -0
  209. package/libraries/redux-offline/src/index.js +138 -0
  210. package/libraries/redux-offline/src/middleware.js +52 -0
  211. package/libraries/redux-offline/src/offlineActionTracker.js +40 -0
  212. package/libraries/redux-offline/src/send.js +111 -0
  213. package/libraries/redux-offline/src/types.js +127 -0
  214. package/libraries/redux-offline/src/updater.js +141 -0
  215. package/libraries/redux-offline/typings.d.ts +150 -0
  216. package/libraries/redux-offline/yarn.lock +6460 -0
  217. package/libraries/stored-state/index.js +155 -0
  218. package/package.json +68 -0
  219. package/views/Callmanager/index.js +148 -0
  220. package/views/Callmanager/styles.js +62 -0
  221. package/views/Canteens/index.js +383 -0
  222. package/views/Canteens/styles.js +89 -0
  223. package/views/Dashboard/index.js +176 -0
  224. package/views/Dashboard/styles.js +16 -0
  225. package/views/DashboardHtwk/index.js +197 -0
  226. package/views/DashboardHtwk/styles.js +24 -0
  227. package/views/Event/index.js +373 -0
  228. package/views/Event/styles.js +63 -0
  229. package/views/FeedList/index.js +165 -0
  230. package/views/FeedList/styles.js +15 -0
  231. package/views/FeedNews/index.js +243 -0
  232. package/views/FeedNews/styles.js +32 -0
  233. package/views/Flexmenu/index.js +185 -0
  234. package/views/Flexmenu/styles.js +62 -0
  235. package/views/FlexmenuWebview/index.js +167 -0
  236. package/views/FlexmenuWebview/styles.js +16 -0
  237. package/views/Howhy/index.js +151 -0
  238. package/views/Howhy/styles.js +11 -0
  239. package/views/Jobs/index.js +217 -0
  240. package/views/Jobs/styles.js +41 -0
  241. package/views/MainMenu/index.js +283 -0
  242. package/views/MainMenu/styles.js +36 -0
  243. package/views/NewsTabbar/index.js +164 -0
  244. package/views/NewsTabbar/styles.js +27 -0
  245. package/views/Opal/index.js +136 -0
  246. package/views/Opal/styles.js +11 -0
  247. package/views/PublicTransportTicket/index.js +173 -0
  248. package/views/PublicTransportTicket/styles.js +17 -0
  249. package/views/Search/index.js +186 -0
  250. package/views/Search/styles.js +67 -0
  251. package/views/SettingsAccessibility/index.js +148 -0
  252. package/views/SettingsAccessibility/styles.js +13 -0
  253. package/views/SettingsAppInfo/index.js +86 -0
  254. package/views/SettingsAppInfo/styles.js +18 -0
  255. package/views/SettingsCanteens/index.js +249 -0
  256. package/views/SettingsCanteens/styles.js +33 -0
  257. package/views/SettingsGeneral/index.js +173 -0
  258. package/views/SettingsGeneral/styles.js +28 -0
  259. package/views/SettingsNotifications/index.js +204 -0
  260. package/views/SettingsNotifications/styles.js +38 -0
  261. package/views/SettingsUser/index.js +170 -0
  262. package/views/SettingsUser/styles.js +17 -0
  263. package/views/TimetableCalendar/index.js +387 -0
  264. package/views/TimetableCalendar/styles.js +121 -0
  265. package/views/TimetableList/index.js +402 -0
  266. package/views/TimetableList/styles.js +55 -0
  267. package/views/Webviews/index.js +158 -0
  268. package/views/Webviews/styles.js +11 -0
@@ -0,0 +1,73 @@
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, { useMemo } from 'react';
16
+ import { StyleSheet } from 'react-native';
17
+
18
+ import { Checkbox, useTheme } from 'react-native-paper';
19
+ import { useTranslation } from 'react-i18next';
20
+
21
+ import SettingsDialog from '../SettingsDialog';
22
+
23
+ import componentStyles from './styles';
24
+
25
+ export default function SettingsDialogSelect({ title, visible, options, onDismiss, onOk, onChange, ...props }) {
26
+ const selectedOptions = Array.isArray(props?.selectedOptions) ? props.selectedOptions : [];
27
+ const { t } = useTranslation();
28
+ const theme = useTheme();
29
+
30
+ const styles = useMemo(
31
+ () => StyleSheet.create(componentStyles(theme)),
32
+ [theme, componentStyles]
33
+ )
34
+
35
+ return (
36
+ <SettingsDialog
37
+ title={title}
38
+ visible={visible}
39
+ onDismiss={() => onDismiss(selectedOptions)}
40
+ onOk={() => onOk(selectedOptions)}
41
+ >
42
+ {
43
+ options.map(
44
+ option => {
45
+ const optionKey = option?.key;
46
+ const isChecked = selectedOptions?.includes?.(optionKey) ?? false;
47
+ const colors = theme.colors;
48
+ return (
49
+ <Checkbox.Item
50
+ key={optionKey}
51
+ value={optionKey}
52
+ status={isChecked ? 'checked' : 'unchecked'}
53
+ label={t(option.label)}
54
+ labelStyle={styles.optionLabel}
55
+ color={colors.checkboxChecked}
56
+ uncheckedColor={colors.checkboxUnchecked}
57
+ mode={'android'}
58
+ onPress={
59
+ () => {
60
+ const nextSelectedOptions = selectedOptions.includes(optionKey)
61
+ ? selectedOptions.filter(selectedOption => selectedOption !== optionKey)
62
+ : [...selectedOptions, optionKey];
63
+ onChange(nextSelectedOptions);
64
+ }
65
+ }
66
+ />
67
+ )
68
+ }
69
+ )
70
+ }
71
+ </SettingsDialog>
72
+ );
73
+ }
@@ -0,0 +1,7 @@
1
+ export default function (theme) {
2
+ return {
3
+ optionLabel: {
4
+ fontSize: theme.fontSizes.m,
5
+ }
6
+ }
7
+ };
@@ -0,0 +1,205 @@
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, { useState, useMemo } from 'react';
16
+ import {
17
+ StyleSheet,
18
+ View,
19
+ ScrollView,
20
+ ActivityIndicator,
21
+ KeyboardAvoidingView,
22
+ Alert,
23
+ Text,
24
+ Linking,
25
+ } from 'react-native';
26
+ import { connect } from 'react-redux'
27
+ import { Paragraph, TextInput, Button, withTheme } from 'react-native-paper';
28
+ import { withTranslation } from 'react-i18next';
29
+
30
+ import {
31
+ ApiProviderNotInitializedError,
32
+ useCourses,
33
+ useTimetableCode,
34
+ } from '../../context/context-timetable';
35
+
36
+ import componentStyles from './styles';
37
+
38
+ /**
39
+ * Diese Callback-Funktion wird gerufen, wenn der vom Nutzer ausgelöste Import erfolgreich war.
40
+ * @callback onImportSuccessfullyFinished
41
+ * @returns {void}
42
+ */
43
+
44
+ /**
45
+ * Diese Callback-Funktion wird gerufen, wenn der vom Nutzer ausgelöste Importversuch fehlschägt war.
46
+ * Es wird der Grund des Fehlschlags zur weiteren Behandlung übergeben.
47
+ * @callback onImportFailed
48
+ * @param {*} reason
49
+ */
50
+
51
+ /**
52
+ * @param {*} props
53
+ * @param {onImportSuccessfullyFinished} props.onImportFailed
54
+ * @param {onImportFailed} props.ponImportSuccessfullyFinished
55
+ */
56
+ function TimetableCodeInput(props) {
57
+ const {
58
+ theme,
59
+ theme: { colors, appSettings: { modules: { timetable: { code } } } },
60
+ t,
61
+ // Callback, welche nach dem erfolgreichen Importieren aufgerufen wird.
62
+ onImportSuccessfullyFinished,
63
+ // Callback, welche nach einem fehlgeschlagenen Importversuch aufgerufen wird.
64
+ onImportFailed,
65
+ } = props;
66
+
67
+ const componentName = TimetableCodeInput.name;
68
+
69
+ // Einstellungen für den Stundenplan-Code
70
+ const timetableCodeInputLength = code?.length ?? 0;
71
+ const timetableCodeInputFilters = code?.filters;
72
+ const timetableCodeInputPreSaveFilters = Array.isArray(code?.preSaveFilters) ? code.preSaveFilters : [];
73
+ const timetableCodeInputFilterToUpperCase = timetableCodeInputFilters?.toUpperCase ?? false;
74
+
75
+ const [timetableCode, saveTimetableCode] = useTimetableCode();
76
+ const [, refreshCourses] = useCourses();
77
+
78
+ const [timetableCodeInput, setTimetableCodeInput] = useState(timetableCode);
79
+ const [importing, setImporting] = useState(false);
80
+
81
+ // Generate styles. Will be generated only if not present or the theme property changes.
82
+ const styles = useMemo(
83
+ () => StyleSheet.create(componentStyles(theme)),
84
+ [theme]
85
+ )
86
+
87
+ const handleLinkPress = (url) => {
88
+ Linking.openURL(url);
89
+ };
90
+
91
+ const renderTextWithLinks = (text) => {
92
+ const parts = text.split(/(https?:\/\/[^\s]+)/g);
93
+ return parts.map((part, index) => {
94
+ if (part.match(/https?:\/\/[^\s]+/)) {
95
+ const displayText = part.replace(/https?:\/\//, '');
96
+ return (
97
+ <Text
98
+ key={index}
99
+ style={styles.link}
100
+ onPress={() => handleLinkPress(part)}
101
+ >
102
+ {displayText}
103
+ </Text>
104
+ );
105
+ }
106
+ return part;
107
+ });
108
+ };
109
+
110
+ const paragraphText = t(timetableCode ? 'timetable:inputTimetableCode' : 'timetable:notImportedYet', { timetableCodeInputLength });
111
+
112
+ return (
113
+ <ScrollView style={styles.mainContentContainer}>
114
+ <KeyboardAvoidingView behavior={"padding"} >
115
+ <View style={styles.paragraph}>
116
+ {/*selectable and dataDetectorType only work on andorid*/}
117
+ <Paragraph style={styles.paragraphText} selectable={true} dataDetectorType={'link'}>
118
+ {renderTextWithLinks(paragraphText)}
119
+ </Paragraph>
120
+ </View>
121
+ <View style={styles.importTextInputContainer}>
122
+ <TextInput
123
+ theme={{ colors: { primary: colors.textInput, placeholder: colors.textLighter } }}
124
+ style={styles.paragraphText}
125
+ selectionColor={colors.textInputSelection}
126
+ label={t('timetable:inputPlaceholder')}
127
+ value={timetableCodeInput}
128
+ autoCapitalize={timetableCodeInputFilterToUpperCase ? 'characters' : 'none'}
129
+ maxLength={timetableCodeInputLength ? timetableCodeInputLength : null}
130
+ onChangeText={setTimetableCodeInput}
131
+ />
132
+ </View>
133
+ <Button
134
+ onPress={async () => {
135
+ // Wenn eine Mindestlänge des Stundenplandcodes konfiguriert ist und diese nicht von der Eingabe erreicht wird, wird ein Fehlerdialog angezeigt
136
+ if (timetableCodeInputLength && (timetableCodeInput?.length ?? 0) < timetableCodeInputLength) {
137
+ const alertTranslationValues = { timetableCodeInputLength };
138
+ Alert.alert(
139
+ t('timetable:errorCodeShort:title', alertTranslationValues),
140
+ t('timetable:errorCodeShort:message', alertTranslationValues),
141
+ [{ text: 'OK' }],
142
+ );
143
+ } else {
144
+ // Import-Ladeanimation aktivieren
145
+ setImporting(true);
146
+ await saveTimetableCode(
147
+ // Falls Filter eingestellt sind, werden diese nacheinander auf den Stundenplancode angewendet
148
+ timetableCodeInputPreSaveFilters.reduce(
149
+ (currentTimetableCode, preSaveFilter) => preSaveFilter?.(currentTimetableCode) ?? currentTimetableCode,
150
+ timetableCodeInput
151
+ )
152
+ );
153
+ /**
154
+ * Dieser Aufruf ist eigentlich unnötig, aber die Nutzer möchten Feedback, wenn der Stundenplan nochmal importiert wird.
155
+ * Der Stundenplan wird über einen useEffect-Hook neu geladen, sobald der neue Stundenplancode vom Context gespeichert wurde.
156
+ * Es soll aber die Lade-Animation angezeigt werden und zum Stundenplan zurückgespungen werden, auch wenn schon ein Stundenplancode importiert wurde.
157
+ *
158
+ * Da ich mir nicht besser zu helfen weiß, wird die refreshCourses-Funktion gerufen und importiert NOCHMAL den Stundenplan, nachdem dieser schon vom useEffect-Hook im Kontext importiert wurde.
159
+ * refreshCourses gibt eine Promise zurück, die mit dem fertigen Import auf nachfolgende then-Anweisungen weiterleitet.
160
+ *
161
+ * Man könnte vielleicht auch bei saveTimetableCode ein Promise zurückgeben, die den Stundenplan auch gleich importiert.
162
+ * Aber dann müsste man anstatt des useEffekt-Hooks, der auf den Stundenplancode reagiert, jeden refresh des Stundenplanes über den Code selbst implementieren.
163
+ */
164
+ refreshCourses()
165
+ // Rufe onImportSuccessfullyFinished-Callback, wenn Import erfolgreich war
166
+ .then(() => onImportSuccessfullyFinished?.())
167
+ .catch((reason) => {
168
+ if (reason instanceof ApiProviderNotInitializedError) {
169
+ console.error(componentName, ': ', reason);
170
+ } else {
171
+ console.debug(componentName, ': ', reason);
172
+ }
173
+ // Rufe onImportFailed.Callback, wenn Import fehlschlug
174
+ onImportFailed?.(reason);
175
+ })
176
+ // Import-Ladeanimation immer deaktivieren
177
+ .finally(() => setImporting(false));
178
+ }
179
+ }}
180
+ labelStyle={styles.importButtonLabel}
181
+ color={colors.buttonText}
182
+ >
183
+ {t('timetable:importButton')}
184
+ </Button>
185
+ {
186
+ // Es wird ein Ladesymbol angezeigt, wenn der Stundenplan importiert wird.
187
+ importing
188
+ ? <>
189
+ <ActivityIndicator style={styles.activity} size="large" color={colors.loadingIndicator} />
190
+ <View style={styles.paragraph}><Paragraph>{t('timetable:importInProgress', '')}</Paragraph></View>
191
+ </>
192
+ : null
193
+ }
194
+ </KeyboardAvoidingView>
195
+ </ScrollView>
196
+ );
197
+ }
198
+
199
+ const mapStateToProps = state => {
200
+ return {
201
+ settings: state.settingReducer
202
+ };
203
+ };
204
+
205
+ export default connect(mapStateToProps, null)(withTranslation()(withTheme(TimetableCodeInput)))
@@ -0,0 +1,28 @@
1
+ export default function (theme) {
2
+ return {
3
+ mainContentContainer: {
4
+ flex: 1,
5
+ backgroundColor: theme.colors.contentBackground,
6
+ },
7
+ paragraph: {
8
+ paddingTop: theme.paddings.default,
9
+ paddingLeft: theme.paddings.default,
10
+ paddingRight: theme.paddings.default
11
+ },
12
+ paragraphText: {
13
+ fontSize: theme.fontSizes.l,
14
+ lineHeight: theme.lineHeights.l
15
+ },
16
+ importButtonLabel: {
17
+ fontSize: theme.fontSizes.l,
18
+ lineHeight: theme.lineHeights.l
19
+ },
20
+ importTextInputContainer: {
21
+ paddingLeft: theme.paddings.default,
22
+ paddingRight: theme.paddings.default
23
+ },
24
+ link: {
25
+ textDecorationLine: 'underline',
26
+ },
27
+ }
28
+ };
@@ -0,0 +1,252 @@
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, { useState, useMemo, useCallback, useEffect } from 'react';
16
+ import { View, Text, TouchableOpacity, StyleSheet, useWindowDimensions } from 'react-native';
17
+ import { connect } from 'react-redux';
18
+ import { withTheme } from 'react-native-paper';
19
+ import { withTranslation } from 'react-i18next';
20
+ import { onUpdateRefreshing } from '../../libraries/core';
21
+ import componentStyles from "./styles";
22
+ import { Calendar } from 'react-native-big-calendar';
23
+ import { useCourses } from '../../context/context-timetable';
24
+ import CalendarStrip from 'react-native-calendar-strip';
25
+ import CourseDetailDialog from '../CourseDetailDialog';
26
+ import { DateTime, Duration } from 'luxon';
27
+ import { TabView } from 'react-native-tab-view';
28
+ import moment from 'moment';
29
+ import 'moment/locale/de';
30
+
31
+ /**
32
+ * Die Zeitspanne, welche vor und nach heute angezeigt werden soll.
33
+ */
34
+ const daysTabDuration = Duration.fromISO('P6M');
35
+
36
+ /**
37
+ *
38
+ * @param {object} props
39
+ * @param {(DateTime) => void} props.onDateChanged Callback, welche aufgerufen wird, wenn der Tag in der Ansicht wechselt
40
+ * @returns
41
+ */
42
+ function CalendarDay({ selectedDate, theme, settings, calendarScrollOffsetMinutes, calendarHeight, onDateChanged, onCourseSelected }) {
43
+ const { appSettings: { modules: { timetable: { showDetails } } } } = theme;
44
+ const today = DateTime.now().toISODate();
45
+
46
+ const { width } = useWindowDimensions();
47
+
48
+ const [courses] = useCourses();
49
+
50
+ const language = settings?.settingsGeneral?.language;
51
+
52
+ const styles = useMemo(
53
+ () => StyleSheet.create(componentStyles(theme)),
54
+ [theme]
55
+ );
56
+
57
+ const calendarStripMinDate = useMemo(
58
+ () => DateTime.fromISO(today).minus(daysTabDuration).toJSDate(),
59
+ [today, daysTabDuration]
60
+ );
61
+
62
+ const calendarStripMaxDate = useMemo(
63
+ () => DateTime.fromISO(today).plus(daysTabDuration).toJSDate(),
64
+ [today, daysTabDuration]
65
+ );
66
+
67
+ const daysTabViewRoutes = useMemo(
68
+ () => {
69
+ const dateRoutes = [];
70
+ const todayDateTime = DateTime.fromISO(today);
71
+ const beginDateTime = todayDateTime.minus(daysTabDuration);
72
+ const endDateTime = todayDateTime.plus(daysTabDuration);
73
+ let currentDateTime = DateTime.fromObject(beginDateTime.toObject());
74
+
75
+ const eventColor = theme.colors.eventContainerSidebar;
76
+
77
+ while (currentDateTime <= endDateTime) {
78
+ const currentISODate = currentDateTime.toISODate();
79
+ const currentDateTimeCourses = courses?.[currentISODate]
80
+ ?.map(
81
+ course => (
82
+ {
83
+ title: course.title.data,
84
+ start: new Date(Date.parse(course.startDateTime)),
85
+ end: new Date(Date.parse(course.endDateTime)),
86
+ color: eventColor,
87
+ type: course.type?.data,
88
+ professor: course.lecturer[0]?.data,
89
+ room: course.room.data,
90
+ // Anfügen des Ürsprügnlichen Vorlesungsobjektes, damit es beim Klick zur Verfügung steht
91
+ origine: course,
92
+ }
93
+ )
94
+ ) ?? [];
95
+
96
+ dateRoutes.push(
97
+ {
98
+ key: currentISODate,
99
+ date: currentDateTime,
100
+ events: currentDateTimeCourses,
101
+ }
102
+ );
103
+
104
+ currentDateTime = currentDateTime.plus({ day: 1 });
105
+ }
106
+
107
+ return dateRoutes;
108
+ },
109
+ [today, courses, language]
110
+ );
111
+
112
+ const daysTabViewIndexes = useMemo(
113
+ () => daysTabViewRoutes
114
+ .reduce(
115
+ (accumulator, currentRoute, currentIndex) =>
116
+ (
117
+ {
118
+ ...accumulator,
119
+ [currentRoute.key]: currentIndex
120
+ }
121
+ ),
122
+ {}
123
+ ),
124
+ [daysTabViewRoutes]
125
+ )
126
+
127
+ const daysTabViewIndex = useMemo(
128
+ () => {
129
+ const selectedISODate = selectedDate.toISODate();
130
+ return daysTabViewIndexes[selectedISODate];
131
+ },
132
+ [daysTabViewIndexes, selectedDate]
133
+ )
134
+
135
+ const renderEvent = useCallback((event, touchableOpacityProps) => {
136
+ const { style, ...restTouchableOpacityProps } = touchableOpacityProps;
137
+ return (
138
+ <TouchableOpacity {...restTouchableOpacityProps} style={[style, styles.eventContainer, { borderLeftColor: event.color || '#000' }]} >
139
+ <View style={styles.eventHeader}>
140
+ <Text style={styles.eventTitle} numberOfLines={1} ellipsizeMode="tail">
141
+ {event.title}
142
+ </Text>
143
+ <Text style={styles.eventType} numberOfLines={1} ellipsizeMode="tail">
144
+ {event.type}
145
+ </Text>
146
+ </View>
147
+ <Text style={styles.eventProfessor} numberOfLines={1} ellipsizeMode="head">
148
+ {event.professor}
149
+ </Text>
150
+ <View style={styles.eventFooter}>
151
+ <Text style={styles.eventTime} numberOfLines={1} ellipsizeMode="tail">
152
+ {`${event.start.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })} - ${event.end.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })}`}
153
+ </Text>
154
+ <Text style={styles.eventRoom} numberOfLines={1} ellipsizeMode="tail">
155
+ {event.room}
156
+ </Text>
157
+ </View>
158
+ </TouchableOpacity>
159
+ );
160
+ }, [styles]);
161
+
162
+ const renderScene = useCallback(
163
+ ({ route }) => {
164
+ return (
165
+ <View style={{ flex: 1, width: width }}>
166
+ <Calendar
167
+ events={route.events}
168
+ renderEvent={renderEvent}
169
+ renderHeader={() => null}
170
+ overlapOffset={95}
171
+ mode={'day'}
172
+ height={calendarHeight}
173
+ headerContentStyle={{ backgroundColor: 'transparent' }}
174
+ weekStartsOn={1}
175
+ date={route.key}
176
+ swipeEnabled={false}
177
+ onPressEvent={
178
+ showDetails
179
+ // Wenn eine Vorlesung im Kalender angeklickt wird, wird die ursprüngliche Vorlesung ausgelesen und selektiert
180
+ ? (event) => onCourseSelected(event.origine)
181
+ : null
182
+ }
183
+ scrollOffsetMinutes={calendarScrollOffsetMinutes}
184
+ hourStyle={styles.hourStyle}
185
+ />
186
+ </View>
187
+ );
188
+ },
189
+ [styles, calendarScrollOffsetMinutes, courses, width, renderEvent]
190
+ );
191
+
192
+ return (
193
+ <>
194
+ <View style={styles.stripShadow}>
195
+ <CalendarStrip
196
+ style={styles.strip}
197
+ locale={{
198
+ name: language,
199
+ config: moment.localeData(language)
200
+ }}
201
+ selectedDate={selectedDate.toJSDate()}
202
+ onDateSelected={
203
+ (date) =>
204
+ onDateChanged?.(
205
+ DateTime.fromObject(
206
+ {
207
+ year: date.year(),
208
+ month: date.month() + 1,
209
+ day: date.date(),
210
+ }
211
+ )
212
+ )
213
+ }
214
+ highlightDateContainerStyle={styles.highlightDateContainer}
215
+ showMonth={false}
216
+ iconStyle={{ display: 'none' }}
217
+ scrollable={true}
218
+ minDate={calendarStripMinDate}
219
+ maxDate={calendarStripMaxDate}
220
+ />
221
+ </View>
222
+
223
+ <TabView
224
+ navigationState={{ index: daysTabViewIndex, routes: daysTabViewRoutes }}
225
+ renderTabBar={() => null}
226
+ lazy
227
+ lazyPreloadDistance={1}
228
+ onIndexChange={
229
+ (index) => {
230
+ const currentDateTime = daysTabViewRoutes?.[daysTabViewIndex].date;
231
+ const indexDelta = index - daysTabViewIndex;
232
+ const deltaDateTime = currentDateTime.plus({ days: indexDelta });
233
+ onDateChanged?.(deltaDateTime);
234
+ }
235
+ }
236
+ renderScene={renderScene}
237
+ />
238
+ </>
239
+ )
240
+ }
241
+
242
+ const mapStateToProps = (state) => {
243
+ return {
244
+ pluginComponent: state.pluginReducer.timetable.component,
245
+ pluginStyles: state.pluginReducer.timetable.styles,
246
+ settings: state.settingReducer,
247
+ refreshing: state.stateReducer.refreshing,
248
+
249
+ };
250
+ };
251
+
252
+ export default connect(mapStateToProps, { onUpdateRefreshing })(withTranslation()(withTheme(CalendarDay)));
@@ -0,0 +1,103 @@
1
+ export default function (theme) {
2
+ return {
3
+ eventContainer: {
4
+ borderLeftWidth: 4,
5
+ backgroundColor: theme.colors.eventContainerBackground,
6
+ padding: 10,
7
+ marginBottom: 10,
8
+ marginRight: 10,
9
+ borderRadius: 8,
10
+ elevation: 5,
11
+ shadowColor: '#000',
12
+ shadowOffset: { width: 0, height: 2 },
13
+ shadowOpacity: 0.3,
14
+ shadowRadius: 3,
15
+ overflow: 'visible',
16
+ },
17
+
18
+ eventHeader: {
19
+ flexDirection: 'row',
20
+ justifyContent: 'space-between',
21
+ marginBottom: 0,
22
+ },
23
+ eventTitle: {
24
+ color: theme.colors.text,
25
+ fontSize: 14,
26
+ fontWeight: 'bold',
27
+ flex: 1,
28
+ paddingRight: 10,
29
+ },
30
+ eventType: {
31
+ color: theme.colors.text,
32
+ fontSize: 13,
33
+ },
34
+ eventProfessor: {
35
+ color: theme.colors.text,
36
+ fontSize: 13,
37
+ paddingTop: 4,
38
+ },
39
+ eventFooter: {
40
+ flexDirection: 'row',
41
+ justifyContent: 'space-between',
42
+ alignItems: 'center',
43
+ marginTop: 4,
44
+ },
45
+ eventTime: {
46
+ fontSize: 13,
47
+ color: theme.colors.text,
48
+ flex: 1,
49
+ },
50
+ eventRoom: {
51
+ fontSize: 13,
52
+ color: theme.colors.text,
53
+ textAlign: 'right',
54
+ flex: 1,
55
+ },
56
+ highlightDateContainer: {
57
+ borderRadius: 100,
58
+ borderWidth: 3,
59
+ borderColor: 'red',
60
+ height: 48,
61
+ width: 48,
62
+ },
63
+ courseCard: {
64
+ paddingLeft: 5,
65
+ },
66
+ courseTimeContainerBigFont: {
67
+ width: "25%",
68
+ },
69
+ timeText: {
70
+ fontSize: theme.fontSizes.subtitle,
71
+ paddingTop: theme.paddings.small,
72
+ paddingBottom: theme.paddings.small
73
+ },
74
+ timeTextBig: {
75
+ fontSize: theme.fontSizes.m
76
+ },
77
+
78
+ courseContainerBigFont: {
79
+ width: "75%",
80
+ },
81
+ type: {
82
+ fontSize: theme.fontSizes.subtitle,
83
+ color: theme.colors.subtitle
84
+ },
85
+ strip: {
86
+ height: 65,
87
+ paddingTop: 5,
88
+ paddingBottom: 5,
89
+ elevation: 5,
90
+ backgroundColor: '#fff',
91
+ },
92
+ stripShadow: {
93
+ shadowColor: '#000',
94
+ shadowOffset: { width: 0, height: 3 },
95
+ shadowOpacity: 0.2,
96
+ shadowRadius: 2,
97
+ },
98
+ hourStyle: {
99
+ fontSize: 12,
100
+ color: theme.colors.text,
101
+ },
102
+ };
103
+ }