@olea-bps/components 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 (79) hide show
  1. package/AppBar/index.js +83 -0
  2. package/AppBar/styles.js +27 -0
  3. package/BookDetail/index.js +268 -0
  4. package/BookDetail/styles.js +124 -0
  5. package/Component/342/200/216JobsFilter/index.js +188 -0
  6. package/Component/342/200/216JobsFilter/styles.js +12 -0
  7. package/ConnectivityWarning/index.js +65 -0
  8. package/ConnectivityWarning/styles.js +19 -0
  9. package/ContactDetail/index.js +232 -0
  10. package/ContactDetail/styles.js +32 -0
  11. package/CourseDetail/index.js +357 -0
  12. package/CourseDetail/styles.js +59 -0
  13. package/CourseDetailDialog/index.js +169 -0
  14. package/CourseDetailDialog/styles.js +116 -0
  15. package/CourseInfo/index.js +219 -0
  16. package/CourseInfo/styles.js +40 -0
  17. package/DevelopmentDialog/index.js +208 -0
  18. package/DevelopmentDialog/styles.js +10 -0
  19. package/EventCodeInput/index.js +146 -0
  20. package/EventCodeInput/styles.js +108 -0
  21. package/FlexMenuEntry/index.js +84 -0
  22. package/FlexMenuEntry/styles.js +27 -0
  23. package/MainMenuEntry/index.js +88 -0
  24. package/MainMenuEntry/styles.js +28 -0
  25. package/MealItem/index.js +87 -0
  26. package/MealItem/styles.js +73 -0
  27. package/MensaMenu/index.js +307 -0
  28. package/MensaMenu/styles.js +94 -0
  29. package/MensaSlider/index.js +184 -0
  30. package/MensaSlider/styles.js +53 -0
  31. package/Modal/index.js +106 -0
  32. package/Modal/styles.js +8 -0
  33. package/NewsDetail/index.js +377 -0
  34. package/NewsDetail/styles.js +77 -0
  35. package/NewsList/index.js +120 -0
  36. package/NewsList/styles.js +19 -0
  37. package/NewsListItem/index.js +89 -0
  38. package/NewsListItem/styles.js +32 -0
  39. package/OtherCourses/index.js +152 -0
  40. package/OtherCourses/styles.js +10 -0
  41. package/PtsDeparture/index.js +140 -0
  42. package/PtsDeparture/styles.js +7 -0
  43. package/PtsStation/index.js +183 -0
  44. package/PtsStation/styles.js +47 -0
  45. package/QuickLinks/index.js +127 -0
  46. package/QuickLinks/styles.js +45 -0
  47. package/RoomDetail/index.js +281 -0
  48. package/RoomDetail/styles.js +56 -0
  49. package/ScaledImage/index.js +92 -0
  50. package/SearchResults/index.js +362 -0
  51. package/SearchResults/styles.js +59 -0
  52. package/SettingSection/index.js +54 -0
  53. package/SettingSection/styles.js +15 -0
  54. package/SettingsDialog/index.js +52 -0
  55. package/SettingsDialog/styles.js +12 -0
  56. package/SettingsDialogRadio/index.js +66 -0
  57. package/SettingsDialogRadio/styles.js +7 -0
  58. package/SettingsDialogSelect/index.js +73 -0
  59. package/SettingsDialogSelect/styles.js +7 -0
  60. package/TimetableCodeInput/index.js +201 -0
  61. package/TimetableCodeInput/styles.js +28 -0
  62. package/TimetableDay/index.js +266 -0
  63. package/TimetableDay/styles.js +103 -0
  64. package/TimetableEvent/index.js +163 -0
  65. package/TimetableEvent/styles.js +108 -0
  66. package/TimetableList/index.js +116 -0
  67. package/TimetableList/styles.js +109 -0
  68. package/TimetableMonth/index.js +156 -0
  69. package/TimetableMonth/styles.js +29 -0
  70. package/TimetableWeek/index.js +245 -0
  71. package/TimetableWeek/styles.js +58 -0
  72. package/TopNews/index.js +282 -0
  73. package/TopNews/styles.js +125 -0
  74. package/TopNewsHtwk/index.js +279 -0
  75. package/TopNewsHtwk/styles.js +142 -0
  76. package/WebView/index.js +108 -0
  77. package/WebView/styles.js +11 -0
  78. package/index.js +39 -0
  79. package/package.json +37 -0
@@ -0,0 +1,245 @@
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 { 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 { Calendar } from 'react-native-big-calendar';
21
+ import { useCourses } from '@olea-bps/context-timetable';
22
+ import CalendarStrip from 'react-native-calendar-strip';
23
+ import { DateTime, Duration } from 'luxon';
24
+ import { TabView } from 'react-native-tab-view';
25
+ import { onUpdateRefreshing } from '@olea-bps/core';
26
+ import { CourseDetailDialog } from '@olea-bps/components';
27
+ import moment from 'moment';
28
+ import 'moment/locale/de';
29
+
30
+ import componentStyles from './styles';
31
+
32
+ /**
33
+ * Die Zeitspanne, welche vor und nach heute angezeigt werden soll.
34
+ */
35
+ const daysTabDuration = Duration.fromISO('P6M');
36
+
37
+ /**
38
+ *
39
+ * @param {object} props
40
+ * @param {(DateTime)=> void} props.onWeekChanged
41
+ * @returns
42
+ */
43
+ function CalendarWeek(props) {
44
+ const { selectedISOWeek, theme, settings, calendarScrollOffsetMinutes, onWeekChanged, onCourseSelected } = props;
45
+
46
+ const styles = useMemo(
47
+ () => StyleSheet.create(componentStyles(theme)),
48
+ [theme]
49
+ );
50
+
51
+ const { width } = useWindowDimensions();
52
+
53
+ const [courses] = useCourses();
54
+
55
+ const language = settings?.settingsGeneral?.language;
56
+
57
+ const selectedWeekDate = useMemo(
58
+ () => DateTime.fromISO(selectedISOWeek),
59
+ [selectedISOWeek]
60
+ );
61
+
62
+ const now = DateTime.now()
63
+ const todayWeekNumber = now.weekNumber;
64
+ const todayWeekYearNumber = now.weekYear;
65
+
66
+ const weeksTabViewRoutes = useMemo(
67
+ () => {
68
+ const todayWeekYear = DateTime.fromObject({ weekNumber: todayWeekNumber, weekYear: todayWeekYearNumber }).startOf('week');
69
+ const beginWeekYear = todayWeekYear.minus(daysTabDuration).startOf('week');
70
+ const endWeekYear = todayWeekYear.plus(daysTabDuration).endOf('week');
71
+ let currentWeekYear = DateTime.fromObject(beginWeekYear.toObject());
72
+
73
+ const weekYearRoutes = [];
74
+
75
+ while (currentWeekYear <= endWeekYear) {
76
+ const currentISOWeekYear = currentWeekYear.toISOWeekDate();
77
+
78
+ const currentWeekYearBeginDate = currentWeekYear.startOf('week');
79
+ const currentWeekYearEndDate = currentWeekYear.endOf('week');
80
+ let currentWeekYearDate = DateTime.fromObject(currentWeekYearBeginDate.toObject());
81
+
82
+ const currentWeekYearCourses = [];
83
+
84
+ const eventColor = theme.colors.eventContainerSidebar;
85
+
86
+ while (currentWeekYearDate <= currentWeekYearEndDate) {
87
+ const currentWeekYearISODate = currentWeekYearDate.toISODate();
88
+ const currentWeekYearDateCourses = courses?.[currentWeekYearISODate]
89
+ ?.map(
90
+ course => (
91
+ {
92
+ title: course.title.data,
93
+ start: course.startDateTime,
94
+ end: course.endDateTime,
95
+ color: eventColor,
96
+ type: course.type?.data,
97
+ professor: course.lecturer[0]?.data,
98
+ room: course.room.data,
99
+ }
100
+ )
101
+ ) ?? [];
102
+
103
+ currentWeekYearCourses.push(currentWeekYearDateCourses);
104
+
105
+ currentWeekYearDate = currentWeekYearDate.plus({ day: 1 });
106
+ }
107
+
108
+ weekYearRoutes.push(
109
+ {
110
+ key: currentISOWeekYear,
111
+ weekbeginISODate: currentWeekYearBeginDate.toISODate(),
112
+ week: currentWeekYear.weekNumber,
113
+ weekYear: currentWeekYear.weekYear,
114
+ events: currentWeekYearCourses.flat(),
115
+ }
116
+ );
117
+
118
+ currentWeekYear = currentWeekYear.plus({ week: 1 });
119
+ }
120
+
121
+ return weekYearRoutes;
122
+ },
123
+ [todayWeekNumber, todayWeekYearNumber, courses]
124
+ );
125
+
126
+ const weeksTabViewIndexes = useMemo(
127
+ () => weeksTabViewRoutes
128
+ .reduce(
129
+ (accumulator, currentRoute, currentIndex) =>
130
+ (
131
+ {
132
+ ...accumulator,
133
+ [currentRoute.key]: currentIndex
134
+ }
135
+ ),
136
+ {}
137
+ ),
138
+ [weeksTabViewRoutes]
139
+ )
140
+
141
+ const weeksTabViewIndex = weeksTabViewIndexes[selectedISOWeek];
142
+
143
+ const renderEvent = useCallback((event, touchableOpacityProps) => {
144
+ const { style, ...restTouchableOpacityProps } = touchableOpacityProps;
145
+ return (
146
+ <>
147
+ <TouchableOpacity
148
+ {...restTouchableOpacityProps}
149
+ style={[style, styles.eventContainer, { borderTopColor: event.color || '#000' }]}
150
+ >
151
+ <View style={styles.eventHeader}>
152
+ <Text style={styles.eventTitle} numberOfLines={2} ellipsizeMode={'clip'} >{event.title}</Text>
153
+ </View>
154
+ <Text style={styles.eventRoom} numberOfLines={1} ellipsizeMode={'clip'}>{event.room}</Text>
155
+ </TouchableOpacity>
156
+ </>
157
+ );
158
+ }, [styles]);
159
+
160
+ const renderScene = useCallback(
161
+ ({ route }) => {
162
+ return (
163
+ <View style={{ flex: 1, width: width }}>
164
+ <Calendar
165
+ events={route.events}
166
+ renderEvent={renderEvent}
167
+ renderHeader={() => null}
168
+ mode={'week'}
169
+ height={800}
170
+ headerContentStyle={{ backgroundColor: 'transparent' }}
171
+ weekStartsOn={1}
172
+ date={route.weekbeginISODate}
173
+ onPressEvent={
174
+ (event) => {
175
+ const eventDateISO = DateTime.fromJSDate(event.start).toISODate();
176
+
177
+ const eventStartTime = event.start.getTime();
178
+ const originalCourse = courses[eventDateISO]
179
+ ?.find(
180
+ course =>
181
+ eventStartTime === course.startDateTime.getTime()
182
+ &&
183
+ event?.title === course?.title?.data
184
+ &&
185
+ event?.professor === course?.lecturer[0]?.data
186
+ &&
187
+ event?.room === course?.room?.data
188
+ );
189
+
190
+ onCourseSelected(originalCourse);
191
+ }
192
+ }
193
+ swipeEnabled={false}
194
+ scrollOffsetMinutes={calendarScrollOffsetMinutes}
195
+ hourStyle={styles.hourStyle}
196
+ />
197
+ </View>
198
+ );
199
+ },
200
+ [styles, width, courses, renderEvent]
201
+ );
202
+
203
+ return (
204
+ <>
205
+ <View style={styles.viewStrip}>
206
+ <View pointerEvents="none">
207
+ <CalendarStrip
208
+ style={styles.strip}
209
+ locale={{
210
+ name: language,
211
+ config: moment.localeData(language)
212
+ }}
213
+ highlightDateContainerStyle={styles.highlightDateContainer}
214
+ showMonth={false}
215
+ iconStyle={{ display: 'none' }}
216
+ startingDate={selectedWeekDate.plus({ day: 1 }).toJSDate()}
217
+ pointerEvents={'none'}
218
+ />
219
+ </View>
220
+ </View>
221
+
222
+ <TabView
223
+ navigationState={{ index: weeksTabViewIndex, routes: weeksTabViewRoutes }}
224
+ renderTabBar={() => null}
225
+ lazy
226
+ lazyPreloadDistance={2}
227
+ onIndexChange={
228
+ (index) => {
229
+ const deltaISOWeekYear = weeksTabViewRoutes?.[index]?.key;
230
+ onWeekChanged(deltaISOWeekYear);
231
+ }
232
+ }
233
+ renderScene={renderScene}
234
+ />
235
+ </>
236
+ );
237
+ }
238
+
239
+ const mapStateToProps = (state) => {
240
+ return {
241
+ settings: state.settingReducer,
242
+ };
243
+ };
244
+
245
+ export default connect(mapStateToProps, { onUpdateRefreshing })(withTranslation()(withTheme(CalendarWeek)));
@@ -0,0 +1,58 @@
1
+ export default function (theme) {
2
+ return {
3
+ eventContainer: {
4
+ borderTopWidth: 8,
5
+ paddingTop: 5,
6
+ paddingLeft: 5,
7
+ paddingBottom: 10,
8
+ marginBottom: 10,
9
+ backgroundColor: theme.colors.eventContainerBackground,
10
+ borderRadius: 8,
11
+ shadowColor: '#000',
12
+ shadowOffset: { width: 0, height: 2 },
13
+ shadowOpacity: 0.3,
14
+ shadowRadius: 3,
15
+ elevation: 5,
16
+ overflow: 'visible'
17
+ },
18
+ eventTitle: {
19
+ fontSize: 12,
20
+ fontWeight: 'bold',
21
+ },
22
+ eventRoom: {
23
+ fontSize: 11,
24
+ color: '#757575',
25
+ },
26
+ highlightDateContainer: {
27
+ borderRadius: 100,
28
+ borderWidth: 3,
29
+ borderColor: 'red',
30
+ height: 48,
31
+ width: 48,
32
+ },
33
+ line: {
34
+ backgroundColor: '#000',
35
+ },
36
+ strip: {
37
+ height: 65,
38
+ width: '89%',
39
+ paddingTop: 5,
40
+ paddingBottom: 5,
41
+ backgroundColor: '#fff',
42
+ alignSelf: 'flex-end'
43
+ },
44
+ viewStrip: {
45
+ height: 65,
46
+ backgroundColor: '#fff',
47
+ elevation: 4,
48
+ shadowColor: '#000',
49
+ shadowOffset: { width: 0, height: 3 },
50
+ shadowOpacity: 0.2,
51
+ shadowRadius: 2,
52
+ },
53
+ hourStyle: {
54
+ fontSize: 12,
55
+ color: theme.colors.text,
56
+ },
57
+ };
58
+ }
@@ -0,0 +1,282 @@
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 {
17
+ Animated,
18
+ Dimensions,
19
+ StyleSheet,
20
+ Text,
21
+ TouchableOpacity,
22
+ View
23
+ } from 'react-native';
24
+
25
+ import {connect} from 'react-redux';
26
+ import {withTheme} from "react-native-paper";
27
+
28
+ import merge from 'lodash/merge';
29
+ import NetInfo from '@react-native-community/netinfo';
30
+
31
+ import componentStyles from "./styles";
32
+ import PropTypes from "prop-types";
33
+ import {withTranslation} from "react-i18next";
34
+ import {handleHtmlEntities} from "@olea-bps/core/helper/format.helper";
35
+
36
+
37
+
38
+ /**
39
+ * Top News Component
40
+ *
41
+ * Shows a single news item with the name and the logo of the university.
42
+ *
43
+ * Parameters:
44
+ * - animationRange: Animation Range for animation of the dashboard view
45
+ *
46
+ * Navigation-Parameters:
47
+ * - none
48
+ */
49
+ class TopNewsComponent extends React.Component {
50
+
51
+ static propTypes = {
52
+ animationRange: PropTypes.any
53
+ };
54
+
55
+ // Styles of this component
56
+ styles;
57
+
58
+ animateHeader = null;
59
+ animateBackground = null;
60
+ topNews = null;
61
+ hasConnection = true;
62
+ netInfoUnsubscribe = null;
63
+
64
+ constructor(props) {
65
+ super(props);
66
+
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
+ const height = Dimensions.get('window').height;
82
+
83
+ this.animateHeader = {
84
+ transform: [{
85
+ translateY: this.props.animationRange.interpolate({
86
+ inputRange: [0, 1],
87
+ outputRange: [0, height / 8],
88
+ })
89
+ }]
90
+ };
91
+
92
+ this.animateLogo = {
93
+ transform: [{
94
+ translateY: this.props.animationRange.interpolate({
95
+ inputRange: [0, 1],
96
+ outputRange: [30, (height / 50)],
97
+ })
98
+ },
99
+ {
100
+ scale: this.props.animationRange.interpolate({
101
+ inputRange: [0, 1],
102
+ outputRange: [1, .4],
103
+ })
104
+ }]
105
+ };
106
+
107
+ this.animateBackground = {
108
+ transform: [{
109
+ translateY: this.props.animationRange.interpolate({
110
+ inputRange: [0, 1],
111
+ outputRange: [0, height / 7],
112
+ extrapolate: 'clamp'
113
+ })
114
+ }]
115
+ };
116
+
117
+ this.netInfoUnsubscribe = NetInfo.addEventListener(state => {
118
+ this.hasConnection = state.isInternetReachable && state.isConnected;
119
+ });
120
+ }
121
+
122
+ componentWillUnmount() {
123
+ if(this.netInfoUnsubscribe) {
124
+ this.netInfoUnsubscribe();
125
+ }
126
+ }
127
+
128
+ render() {
129
+
130
+ // ------------------------------------------------------------------------
131
+ // PLUGIN FUNCTIONALITY
132
+ // ------------------------------------------------------------------------
133
+ const PluginComponent = this.props.pluginComponent;
134
+ if (PluginComponent) {
135
+ return <PluginComponent />;
136
+ }
137
+ // ------------------------------------------------------------------------
138
+
139
+
140
+ const {feeds, t} = this.props;
141
+ const {colors, appSettings} = this.props.theme;
142
+ let topNews = this.props.topNews;
143
+
144
+ if(!Array.isArray(topNews)) {
145
+ topNews = [];
146
+ }
147
+
148
+ let topItem = null;
149
+ let imageSrc = null;
150
+ let feedTitle = null;
151
+ if(topNews[0]) {
152
+ topItem = topNews[0];
153
+ if(topItem.imageUrl) {
154
+ imageSrc = {uri: topItem.imageUrl};
155
+ }
156
+ }
157
+
158
+ if(feeds && topItem && topItem.originFeedId) {
159
+ const feed = feeds.filter(feed => feed.feedid === topItem.originFeedId)[0];
160
+
161
+ if(feed && feed.title) {
162
+ feedTitle = feed.title.toUpperCase();
163
+ }
164
+ }
165
+
166
+ if(!imageSrc)
167
+ imageSrc = appSettings.header;
168
+
169
+
170
+ // Top News available
171
+ this.topNews = topItem;
172
+
173
+ // Notice about "." in accessibilityLabels: This will set a short break in the sound output, like in a normal sentence.
174
+
175
+ return (
176
+ <View style={{overflow:'hidden'}}>
177
+ <View stlyle={this.styles.backgroundImageWrapper}>
178
+ <TouchableOpacity
179
+ onPress={
180
+ topItem?.link ?? null
181
+ ? () => { this._handlePressNews(topItem) }
182
+ : null
183
+ }
184
+ >
185
+ <Animated.Image
186
+ source={imageSrc}
187
+ resizeMode="cover"
188
+ fadeDuration={0}
189
+ style={[this.styles.newsImage, this.animateBackground]}
190
+ accessible={true}
191
+ accessibilityLabel={
192
+ !topItem && !this.hasConnection
193
+ ? t('home:noConnectionTitle')
194
+ : (!topItem ? t('home:noItemTitle') : handleHtmlEntities(topItem.title))
195
+ }
196
+ accessibilityHint={!topItem ? '' : t('accessibility:topNewsHint')}
197
+ />
198
+ </TouchableOpacity>
199
+ </View>
200
+
201
+ {
202
+ (!topItem && !this.hasConnection) ? (
203
+ <Animated.View style={[this.styles.newsItem]}
204
+ accessible={true}
205
+ accessibilityLabel={t('home:noConnectionTitle')}>
206
+ <Text
207
+ style={this.styles.newsItemCategory}>{t('home:noConnectionSubtitle').toUpperCase()}</Text>
208
+ <Text style={this.styles.newsItemTitle}>{t('home:noConnectionTitle')}</Text>
209
+ <Text style={this.styles.newsItemText}>{t('home:noConnectionText')}</Text>
210
+ <View style={this.styles.newsItemActionbar}>
211
+ <Text style={this.styles.newsItemDate}></Text>
212
+ </View>
213
+ </Animated.View>
214
+ ) : ((!topItem) ? (
215
+ <Animated.View style={[this.styles.newsItem]}
216
+ accessible={true}
217
+ accessibilityLabel={t('home:noItemTitle')}>
218
+ <Text style={this.styles.newsItemCategory}>{t('home:noItemSubtitle').toUpperCase()}</Text>
219
+ <Text style={this.styles.newsItemTitle}>{t('home:noItemTitle')}</Text>
220
+ <Text style={this.styles.newsItemText}>{t('home:noItemText')}</Text>
221
+ <View style={this.styles.newsItemActionbar}>
222
+ <Text style={this.styles.newsItemDate}/>
223
+ </View>
224
+ </Animated.View>
225
+ ) : (topItem?.shortDesc
226
+ ? <TouchableOpacity
227
+ style={this.styles.newsItem}
228
+ onPress={() => {this._handlePressNews(topItem)}}
229
+ accessible={true}
230
+ accessibilityLabel={handleHtmlEntities(topItem.title)}
231
+ accessibilityHint={t('accessibility:topNewsHint')}>
232
+ <View>
233
+ {feedTitle && <Text style={this.styles.newsItemCategory}>{feedTitle}</Text>}
234
+ <Text style={this.styles.newsItemTitle}>{handleHtmlEntities(topItem.title)}</Text>
235
+ <Text style={this.styles.newsItemText}>{handleHtmlEntities(topItem.shortDesc)} ... <Text style={this.styles.newsItemReadMore}>{t('home:readMore')}</Text></Text>
236
+ <View style={this.styles.newsItemActionbar}>
237
+ {topItem?.author != null
238
+ ? <Text style={this.styles.newsItemAuthor}>{handleHtmlEntities(topItem.author)}</Text>
239
+ : null
240
+ }
241
+ </View>
242
+ </View>
243
+ </TouchableOpacity>
244
+ : null
245
+ ))
246
+ }
247
+ </View>
248
+ );
249
+ }
250
+
251
+
252
+ /**
253
+ * User has pressed the news item card.
254
+ * Shows the news details in a modal window.
255
+ *
256
+ * @param news
257
+ *
258
+ * @private
259
+ */
260
+ _handlePressNews = (news) => {
261
+ if (news) {
262
+ this.props.navigation.navigate(
263
+ 'TopNewsDetail',
264
+ {
265
+ news: {...news, 'feedId': 0},
266
+ newsType: "Default"
267
+ });
268
+ }
269
+ }
270
+ }
271
+
272
+
273
+ const mapStateToProps = state => {
274
+ return {
275
+ pluginComponent: state.pluginReducer.topNews.component,
276
+ pluginStyles: state.pluginReducer.topNews.styles,
277
+ topNews: state.apiReducer.topNews,
278
+ feeds: state.apiReducer.feeds
279
+ };
280
+ };
281
+
282
+ export default connect(mapStateToProps, null)(withTranslation()(withTheme(TopNewsComponent)))
@@ -0,0 +1,125 @@
1
+ import {Platform, Dimensions} from "react-native";
2
+
3
+ export default function(theme) {
4
+ const width = Dimensions.get('window').width;
5
+ const height = Dimensions.get('window').height;
6
+ const headerImageHeight = height / 2;
7
+ return {
8
+ appHeader: {
9
+ flex: 1,
10
+ flexDirection: 'row',
11
+ alignItems: 'baseline',
12
+ },
13
+ appHeaderSearchButton: {
14
+ position: 'absolute',
15
+ top: Platform.OS === 'ios' ? theme.paddings.default : theme.paddings.xlarge,
16
+ right: theme.paddings.default
17
+
18
+ },
19
+ appHeaderSearch: {},
20
+ appHeaderContainer: {
21
+ flex: 1,
22
+ justifyContent: 'center',
23
+ alignContent: 'center',
24
+ alignItems: 'center',
25
+ height: headerImageHeight,
26
+ },
27
+ universityTitle: {
28
+ marginTop: theme.paddings.large,
29
+ marginLeft: theme.paddings.default,
30
+ color: theme.colors.primaryText,
31
+ fontSize: theme.fontSizes.universityTitle,
32
+ ...theme.fonts.bold,
33
+ lineHeight: theme.lineHeights.xxl,
34
+ textAlign: 'left',
35
+ alignSelf: 'flex-start',
36
+ marginBottom: theme.paddings.small
37
+ },
38
+ newsImage: {
39
+ aspectRatio: 16/9,
40
+ width: width
41
+ },
42
+ backgroundImageWrapper: {
43
+ height: headerImageHeight,
44
+ width: width,
45
+ marginTop: 0,
46
+ backgroundColor: theme.colors.primary,
47
+ position:'relative',
48
+ overflow: 'hidden'
49
+ },
50
+ backgroundImage: {
51
+ position:'absolute',
52
+ top: -10,
53
+ left: 0,
54
+ right: 0,
55
+ bottom: 0
56
+ },
57
+ imageOverlay: {
58
+ height: headerImageHeight,
59
+ width: width,
60
+ flex: 1
61
+ },
62
+ newsItem: {
63
+ backgroundColor: theme.colors.background,
64
+ paddingHorizontal: theme.paddings.default,
65
+ paddingTop: theme.paddings.default
66
+ },
67
+ newsItemCategory: {
68
+ marginBottom: 5,
69
+ fontSize: theme.fontSizes.s
70
+ },
71
+ newsItemTitle: {
72
+ ...theme.fonts.bold,
73
+ fontSize: theme.fontSizes.xxl,
74
+ lineHeight: theme.lineHeights.titleBigger,
75
+ marginBottom: theme.paddings.small,
76
+ },
77
+ newsItemText: {
78
+ ...theme.fonts.regular,
79
+ fontSize: theme.fontSizes.m,
80
+ lineHeight: theme.lineHeights.s
81
+ },
82
+ newsItemReadMore: {
83
+ textDecorationLine: 'underline'
84
+ },
85
+ newsItemActionbar: {
86
+ borderBottomColor: theme.colors.accent,
87
+ borderBottomWidth: 1,
88
+ //borderStyle: 'dotted', // TODO Not available on iOS at the moment (also dashed)
89
+ borderStyle: 'solid',
90
+ paddingBottom: theme.paddings.small,
91
+ marginTop: theme.paddings.small,
92
+ flex: 1,
93
+ flexDirection: 'row'
94
+ },
95
+ newsItemDate: {
96
+ fontSize: theme.fontSizes.s,
97
+ ...theme.fonts.bold,
98
+ color: theme.colors.subtitle,
99
+ flex: 1,
100
+ alignItems: 'center',
101
+ alignSelf: 'center',
102
+ flexDirection: 'row',
103
+ },
104
+ newsItemAuthor: {
105
+ fontSize: theme.fontSizes.s,
106
+ ...theme.fonts.bold,
107
+ color: theme.colors.subtitle,
108
+ flex: 1,
109
+ alignItems: 'center',
110
+ alignSelf: 'center',
111
+ flexDirection: 'row',
112
+ },
113
+ newsItemActions: {
114
+ flex: 1,
115
+ alignItems: 'flex-end',
116
+ justifyContent: 'flex-end'
117
+ },
118
+ newsItemAction: {
119
+ marginRight: -4
120
+ },
121
+ modalContainer: {
122
+ flex: 1
123
+ },
124
+ }
125
+ };