@olea-bps/base 1.1.9 → 1.1.11

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.
@@ -12,36 +12,35 @@
12
12
  * limitations under the License.
13
13
  */
14
14
 
15
- import React from 'react';
16
- import PropTypes from 'prop-types';
15
+ import React from 'react'
16
+ import PropTypes from 'prop-types'
17
17
 
18
18
  import {
19
- StyleSheet,
20
- Text,
21
- View,
22
- SafeAreaView,
23
- Share,
24
- Dimensions,
25
- Animated,
26
- Platform,
27
- Linking,
28
- PixelRatio
29
- } from 'react-native';
30
- import {Appbar, Headline, withTheme} from "react-native-paper";
31
- import { WebView } from 'react-native-webview';
32
- import {withTranslation} from "react-i18next";
19
+ StyleSheet,
20
+ Text,
21
+ View,
22
+ SafeAreaView,
23
+ Share,
24
+ Dimensions,
25
+ Animated,
26
+ Platform,
27
+ Linking,
28
+ PixelRatio,
29
+ Alert
30
+ } from 'react-native'
31
+ import { Headline, withTheme } from 'react-native-paper'
32
+ import { WebView } from 'react-native-webview'
33
+ import { withTranslation } from 'react-i18next'
33
34
  import { connect } from 'react-redux'
34
- import merge from 'lodash/merge';
35
- import moment from "moment";
35
+ import merge from 'lodash/merge'
36
+ import moment from 'moment'
36
37
 
37
- import WebViewAutoHeight from '../../libraries/react-native-webview-autoheight';
38
-
39
-
40
- import componentStyles from './styles';
41
- import AppbarComponent from '../AppBar';
42
- import AppbarAction from '../AppbarAction';
43
- import { selectFeedById } from '../../libraries/core/redux/reducers/api';
38
+ import WebViewAutoHeight from '../../libraries/react-native-webview-autoheight'
44
39
 
40
+ import componentStyles from './styles'
41
+ import AppbarComponent from '../AppBar'
42
+ import AppbarAction from '../AppbarAction'
43
+ import { selectFeedById } from '../../libraries/core/redux/reducers/api'
45
44
 
46
45
  /**
47
46
  * News Detail Component
@@ -55,100 +54,98 @@ import { selectFeedById } from '../../libraries/core/redux/reducers/api';
55
54
  * - news: News object with all informations of it (for use as standalone view)
56
55
  */
57
56
  class NewsDetailComponent extends React.Component {
58
- static propTypes = {
59
- news: PropTypes.object,
60
- };
57
+ static propTypes = {
58
+ news: PropTypes.object
59
+ }
61
60
 
62
- /**
61
+ /**
63
62
  * Constant to store news types. These types are used to change the view accordingly.
64
63
  */
65
- static newsTypes = Object.freeze({
66
- topNews: 'TopNews',
67
- })
64
+ static newsTypes = Object.freeze({
65
+ topNews: 'TopNews'
66
+ })
68
67
 
69
- // Styles of this component
70
- styles;
68
+ // Styles of this component
69
+ styles
71
70
 
72
- news = null;
71
+ news = null
73
72
 
74
- currentURL = null;
73
+ currentURL = null
75
74
 
76
- urlRegex = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$/;
75
+ urlRegex = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w.-]+)+[\w\-._~:/?#[\]@!$&'()*+,;=.]+$/
77
76
 
78
- maxHeaderHeight;
79
- minHeaderHeight = 120;
80
- headerScrollDistance;
81
- fontScaling;
77
+ maxHeaderHeight
78
+ minHeaderHeight = 120
79
+ headerScrollDistance
80
+ fontScaling
82
81
 
83
- constructor(props) {
84
- super(props);
85
- // ------------------------------------------------------------------------
86
- // PLUGIN FUNCTIONALITY
87
- // ------------------------------------------------------------------------
82
+ constructor (props) {
83
+ super(props)
84
+ // ------------------------------------------------------------------------
85
+ // PLUGIN FUNCTIONALITY
86
+ // ------------------------------------------------------------------------
88
87
 
89
- const { pluginStyles,theme } = this.props;
90
- this.styles = componentStyles(theme);
88
+ const { pluginStyles, theme } = this.props
89
+ this.styles = componentStyles(theme)
91
90
 
92
- if(pluginStyles) {
93
- this.styles = merge(this.styles, pluginStyles);
94
- }
91
+ if (pluginStyles) {
92
+ this.styles = merge(this.styles, pluginStyles)
93
+ }
95
94
 
96
- this.styles = StyleSheet.create(this.styles);
95
+ this.styles = StyleSheet.create(this.styles)
97
96
 
98
- // ------------------------------------------------------------------------
97
+ // ------------------------------------------------------------------------
99
98
 
100
- // Initialize dimension-dependent properties
101
- this.maxHeaderHeight = Dimensions.get('window').height / 3.8;
102
- this.headerScrollDistance = this.maxHeaderHeight - this.minHeaderHeight;
103
- this.fontScaling = PixelRatio.getFontScale();
99
+ // Initialize dimension-dependent properties
100
+ this.maxHeaderHeight = Dimensions.get('window').height / 3.8
101
+ this.headerScrollDistance = this.maxHeaderHeight - this.minHeaderHeight
102
+ this.fontScaling = PixelRatio.getFontScale()
104
103
 
105
- this._onScroll = this._onScroll.bind(this);
104
+ this._onScroll = this._onScroll.bind(this)
106
105
 
107
- this.state = {
108
- imageHeight: Dimensions.get('window').height / 3.8,
109
- scrollY: new Animated.Value(Platform.OS === 'ios' ? -this.maxHeaderHeight :0)
110
- };
111
- };
106
+ this.state = {
107
+ imageHeight: Dimensions.get('window').height / 3.8,
108
+ scrollY: new Animated.Value(Platform.OS === 'ios' ? -this.maxHeaderHeight : 0)
109
+ }
110
+ };
112
111
 
113
- /**
112
+ /**
114
113
  * Share function for contact
115
114
  *
116
115
  * @returns {Promise<void>}
117
116
  * @private
118
117
  */
119
- async _onShare() {
120
- try {
121
- let message = this.news.title + '\n\n' + this.news.link;
122
- const result = await Share.share({
123
- message: message
124
- });
125
-
126
- if (result.action === Share.sharedAction) {
127
- if (result.activityType) {
128
- // shared with activity type of result.activityType
129
- } else {
130
- // shared
131
- }
132
- } else if (result.action === Share.dismissedAction) {
133
- // dismissed
134
- }
135
- } catch (error) {
136
- alert(error.message);
118
+ async _onShare () {
119
+ try {
120
+ const message = this.news.title + '\n\n' + this.news.link
121
+ const result = await Share.share({
122
+ message
123
+ })
124
+
125
+ if (result.action === Share.sharedAction) {
126
+ if (result.activityType) {
127
+ // shared with activity type of result.activityType
128
+ } else {
129
+ // shared
137
130
  }
138
- };
139
-
140
-
141
- _onScroll = event => {
142
- let scrollPosY = event.nativeEvent.contentOffset.y;
143
- let imageHeight = Dimensions.get('window').height / 2.8;
131
+ } else if (result.action === Share.dismissedAction) {
132
+ // dismissed
133
+ }
134
+ } catch (error) {
135
+ Alert.alert('', error.message)
136
+ }
137
+ };
144
138
 
139
+ _onScroll = event => {
140
+ const scrollPosY = event.nativeEvent.contentOffset.y
141
+ const imageHeight = Dimensions.get('window').height / 2.8
145
142
 
146
- let calculatedHeight = imageHeight - scrollPosY;
147
- let limit = 80;
148
- this.setState({imageHeight: calculatedHeight > limit ? calculatedHeight : limit});
149
- };
143
+ const calculatedHeight = imageHeight - scrollPosY
144
+ const limit = 80
145
+ this.setState({ imageHeight: calculatedHeight > limit ? calculatedHeight : limit })
146
+ }
150
147
 
151
- /**
148
+ /**
152
149
  * get the news content
153
150
  *
154
151
  * @param news
@@ -157,228 +154,171 @@ class NewsDetailComponent extends React.Component {
157
154
  * @returns {{html: string}}
158
155
  * @private
159
156
  */
160
- _getNewsContent = (news, css) => {
161
- const newsContent = {html: css + "<div class='content'><meta http-equiv='Content-Type' content='text/html; charset=utf-8' />" + news.desc + "</div>"};
162
- if (Platform.OS === 'android') {
163
- newsContent.baseUrl = '';
164
- }
165
- return newsContent;
166
- };
157
+ _getNewsContent = (news, css) => {
158
+ const newsContent = { html: css + "<div class='content'><meta http-equiv='Content-Type' content='text/html; charset=utf-8' />" + news.desc + '</div>' }
159
+ if (Platform.OS === 'android') {
160
+ newsContent.baseUrl = ''
161
+ }
162
+ return newsContent
163
+ }
167
164
 
168
- /**
165
+ /**
169
166
  * checks if the url is a valid one -> if so, it will open the URL in the browser
170
167
  * otherwise it stops the request
171
168
  *
172
169
  * @param url
173
170
  * @returns {boolean}
174
171
  */
175
- startLoadingRequest = ({url}) => {
176
- if (!url.match(this.urlRegex)) {
177
- return true;
178
- } else if (url.match(this.urlRegex) && Linking.canOpenURL(url)){
179
- //Android does not support the stopLoading method
180
- if (Platform.OS === 'android') {
181
- this.webView && this.webView.goBack();
182
- Linking.openURL(url);
183
- } else {
184
- this.webView.stopLoading();
185
- Linking.openURL(url);
186
- }
187
- }
188
- };
189
-
190
- _renderTopNewsContent = (news) => {
191
- const {customScript} = this.props.theme;
192
- return (
193
- <View style={this.styles.container}>
194
- <WebView
195
- injectedJavaScript={customScript}
196
- source={{ uri: news.link }}
197
- />
198
- </View>
199
- );
172
+ handleNavigationStateChange = ({ url }) => {
173
+ if (!url.match(this.urlRegex)) {
174
+ return true
175
+ } else if (url.match(this.urlRegex) && Linking.canOpenURL(url)) {
176
+ // Android does not support the stopLoading method
177
+ if (Platform.OS === 'android') {
178
+ this.webView && this.webView.goBack()
179
+ Linking.openURL(url)
180
+ } else {
181
+ this.webView.stopLoading()
182
+ Linking.openURL(url)
183
+ }
200
184
  }
201
-
202
-
203
- /**
185
+ }
186
+
187
+ _renderTopNewsContent = (news) => {
188
+ const { customScript } = this.props.theme
189
+ return (
190
+ <View style={this.styles.container}>
191
+ <WebView
192
+ injectedJavaScript={customScript}
193
+ source={{ uri: news.link }}
194
+ />
195
+ </View>
196
+ )
197
+ }
198
+
199
+ /**
204
200
  * Render news contact details content
205
201
  *
206
202
  * @returns {*}
207
203
  * @private
208
204
  */
209
- _renderContent = (news) => {
210
- const {appSettings, css, themeStyles} = this.props.theme;
211
- this.currentURL = news.link;
212
-
213
-
214
-
215
- let imageSrc = null;
216
- if(news?.contentImageUrl) {
217
- imageSrc = {uri: news.contentImageUrl}
218
- }
219
- const scrollY = Animated.add(
220
- this.state.scrollY,
221
- Platform.OS === 'ios' ? this.maxHeaderHeight : 0,
222
- );
223
-
224
- const headerTranslate = scrollY.interpolate({
225
- inputRange: [0, this.headerScrollDistance],
226
- outputRange: [0, -this.headerScrollDistance],
227
- extrapolate: 'clamp',
228
- });
229
- const imageTranslate = scrollY.interpolate({
230
- inputRange: [0, this.headerScrollDistance],
231
- outputRange: [0, 1],
232
- extrapolate: 'clamp',
233
- });
234
-
235
- const titleOpacity = scrollY.interpolate({
236
- inputRange: [0, this.headerScrollDistance / 2, this.headerScrollDistance],
237
- outputRange: [0, 1, 1],
238
- extrapolate: 'clamp',
239
- });
240
-
241
- const titleScale = scrollY.interpolate({
242
- inputRange: [0, this.headerScrollDistance / 2, this.headerScrollDistance],
243
- outputRange: [1, 1, 0.8],
244
- extrapolate: 'clamp',
245
- });
246
- let titleTranslate = scrollY.interpolate({
247
- inputRange: [0, this.headerScrollDistance / 2, this.headerScrollDistance],
248
- outputRange: [0, 0, -8],
249
- extrapolate: 'clamp',
250
- });
251
-
252
- // No image
253
- if(imageSrc == null) {
254
- imageSrc = appSettings.header;
255
- }
256
-
205
+ _renderContent = (news) => {
206
+ const { appSettings, css, themeStyles } = this.props.theme
207
+ this.currentURL = news.link
257
208
 
258
- let barTitle = news.title.replace(/<(?:.|\n)*?>/gm, '');
259
- let barTitleFontSize = 22;
260
- let barTitleLineHeight = 22;
261
- let barTitleHeight = 120;
262
- if(barTitle.length > 80)
263
- barTitleFontSize = 18;
209
+ let imageSrc = null
210
+ if (news?.contentImageUrl) {
211
+ imageSrc = { uri: news.contentImageUrl }
212
+ }
264
213
 
265
- if(barTitle.length > 120)
266
- barTitleFontSize = 16;
214
+ // No image
215
+ if (imageSrc == null) {
216
+ imageSrc = appSettings.header
217
+ }
267
218
 
268
- if(this.fontScaling > 2) {
269
- barTitleFontSize = 15;
270
- barTitleLineHeight = 14;
271
- barTitleHeight = 140;
272
- }
273
- if(this.fontScaling > 2.3) {
274
- barTitleFontSize = 12;
275
- barTitleLineHeight = 14;
276
- barTitleHeight = 160;
277
- titleTranslate = scrollY.interpolate({
278
- inputRange: [0, this.headerScrollDistance / 2, this.headerScrollDistance],
279
- outputRange: [0, 0, -25],
280
- extrapolate: 'clamp',
281
- });
282
- }
283
- barTitleFontSize = Math.round(barTitleFontSize * 10000) / 10000;
219
+ let pubDate = news ? news.pubdate : null
220
+ const date = news ? moment(news.pubdate) : moment()
221
+ if (date) { pubDate = date.format('DD.MM.YYYY HH:mm') }
222
+
223
+ return (
224
+ <View style={this.styles.container}>
225
+ <Animated.ScrollView style={[this.styles.containerInner]}>
226
+ <Animated.View
227
+ pointerEvents='none'
228
+ style={[this.styles.header, { height: this.maxHeaderHeight }]}
229
+ >
230
+ {imageSrc != null &&
231
+ <Animated.Image
232
+ source={imageSrc}
233
+ style={[
234
+ this.styles.image,
235
+ {
236
+ height: this.maxHeaderHeight
237
+
238
+ }
239
+ ]}
240
+ />}
241
+ </Animated.View>
242
+ {news.contentImageDesc ? (<Text style={this.styles.imageDesc}>{news.contentImageDesc}</Text>) : null}
243
+ <View style={this.styles.containerContent}>
244
+ <Headline style={this.styles.title}>{news.title}</Headline>
245
+ <WebViewAutoHeight
246
+ source={this._getNewsContent(news, css)}
247
+ style={{ ...themeStyles.webview, ...this.styles.newsContent }}
248
+ scrollEnabled={false}
249
+ overScrollMode='never'
250
+ customStyle='html, body { overflow: hidden; }'
251
+ contentInset={{ top: 0, left: 0, right: 0, bottom: 0 }}
252
+ onNavigationStateChange={this.handleNavigationStateChange}
253
+ ref={el => { this.webView = el }}
254
+ />
255
+ <Text style={[this.styles.newsContent, this.styles.newsContentText]}>{pubDate}</Text>
256
+ </View>
257
+ </Animated.ScrollView>
258
+ </View>
259
+ )
260
+ }
261
+
262
+ render () {
263
+ // ------------------------------------------------------------------------
264
+ // PLUGIN FUNCTIONALITY
265
+ // ------------------------------------------------------------------------
266
+ const PluginComponent = this.props.pluginComponent
267
+ if (PluginComponent) {
268
+ return <PluginComponent />
269
+ }
270
+ // ------------------------------------------------------------------------
284
271
 
285
- let pubDate = news ? news.pubdate : null ;
286
- let date = news ? moment(news.pubdate) : moment();
287
- if(date)
288
- pubDate = date.format('DD.MM.YYYY HH:mm');
272
+ const { themeStyles } = this.props.theme
273
+ const { news, route, t, feed } = this.props
274
+ const { newsType } = route.params
289
275
 
290
- return (
276
+ if (!news) {
277
+ return (
278
+ <SafeAreaView style={[this.styles.container, themeStyles.appSafeAreaContainer]}>
279
+ <AppbarComponent
280
+ {...this.props}
281
+ title={t('news:title')}
282
+ />
291
283
  <View style={this.styles.container}>
292
- <Animated.ScrollView style={[this.styles.containerInner]}>
293
- <Animated.View
294
- pointerEvents="none"
295
- style={[this.styles.header, { height: this.maxHeaderHeight }]}>
296
- {imageSrc != null &&
297
- <Animated.Image
298
- source={imageSrc}
299
- style={[
300
- this.styles.image,
301
- {
302
- height: this.maxHeaderHeight,
303
-
304
- }
305
- ]}/>}
306
- </Animated.View>
307
- {news.contentImageDesc ? (<Text style={this.styles.imageDesc}>{news.contentImageDesc}</Text>) : null}
308
- <View style={[this.styles.containerContent, Platform.OS === 'android' && {paddingBottom: this.maxHeaderHeight + this.styles.containerContent.paddingVertical}]}>
309
- <Headline style={this.styles.title}>{news.title}</Headline>
310
- <WebViewAutoHeight source={this._getNewsContent(news, css)}
311
- style={{...themeStyles.webview, ...this.styles.newsContent}}
312
- scrollEnabled={false}
313
- contentInset={{top: 0, left: 0, right: 0, bottom: 0}}
314
- onNavigationStateChange={this.startLoadingRequest}
315
- ref={el => {this.webView = el}}/>
316
- <Text style={[this.styles.newsContent, this.styles.newsContentText]}>{pubDate}</Text>
317
- </View>
318
- </Animated.ScrollView>
284
+ <Text>{t('news:couldNotLoad')}</Text>
319
285
  </View>
320
- );
321
- };
322
-
323
- render() {
324
- // ------------------------------------------------------------------------
325
- // PLUGIN FUNCTIONALITY
326
- // ------------------------------------------------------------------------
327
- const PluginComponent = this.props.pluginComponent;
328
- if (PluginComponent) {
329
- return <PluginComponent />;
330
- }
331
- // ------------------------------------------------------------------------
332
-
333
- const {themeStyles} = this.props.theme;
334
- let { news, route, t, feed } = this.props;
335
- let { newsType } = route.params;
336
-
337
- if(!news){
338
- return (
339
- <SafeAreaView style={[this.styles.container, themeStyles.appSafeAreaContainer]}>
340
- <AppbarComponent {...this.props}
341
- title={t('news:title')}/>
342
- <View style={this.styles.container}>
343
- <Text>{t('news:couldNotLoad')}</Text>
344
- </View>
345
- </SafeAreaView>
346
- );
347
- }
286
+ </SafeAreaView>
287
+ )
288
+ }
348
289
 
349
- this.news = news;
350
- const title = feed ? feed.title : t('news:feeds');
290
+ this.news = news
291
+ const title = feed ? feed.title : t('news:feeds')
351
292
 
352
- return (
353
- <SafeAreaView style={[this.styles.container, themeStyles.appSafeAreaContainer]}>
354
- <AppbarComponent
355
- {...this.props}
356
- title={title}
357
- rightAction={
293
+ return (
294
+ <SafeAreaView style={[this.styles.container, themeStyles.appSafeAreaContainer]}>
295
+ <AppbarComponent
296
+ {...this.props}
297
+ title={title}
298
+ rightAction={
358
299
  newsType
359
- ? null
360
- : <AppbarAction icon='share' onPress={this._onShare.bind(this)} />
300
+ ? null
301
+ : <AppbarAction icon='share' onPress={this._onShare.bind(this)} />
361
302
  }
362
- />
363
- {newsType === NewsDetailComponent.newsTypes.topNews ? this._renderTopNewsContent(news) : this._renderContent(news)}
364
- </SafeAreaView>
365
- );
366
- }
303
+ />
304
+ {newsType === NewsDetailComponent.newsTypes.topNews ? this._renderTopNewsContent(news) : this._renderContent(news)}
305
+ </SafeAreaView>
306
+ )
307
+ }
367
308
  }
368
309
 
369
-
370
310
  const mapStateToProps = (state, ownProps) => {
371
- let {news, route} = ownProps;
372
- if (!news) {
373
- news = route.params && route.params.news || null;
374
- }
375
-
376
- return {
377
- pluginComponent: state.pluginReducer.newsDetail.component,
378
- pluginStyles: state.pluginReducer.newsDetail.styles,
379
- feed: selectFeedById(state, news.feedId),
380
- news: news
381
- };
382
- };
311
+ let { news, route } = ownProps
312
+ if (!news) {
313
+ news = (route.params && route.params.news) || null
314
+ }
315
+
316
+ return {
317
+ pluginComponent: state.pluginReducer.newsDetail.component,
318
+ pluginStyles: state.pluginReducer.newsDetail.styles,
319
+ feed: selectFeedById(state, news.feedId),
320
+ news
321
+ }
322
+ }
383
323
 
384
324
  export default connect(mapStateToProps, null)(withTranslation()(withTheme(NewsDetailComponent)))
@@ -1,7 +1,6 @@
1
1
  import { Dimensions } from 'react-native'
2
2
 
3
3
  export default function (theme) {
4
- const height = Dimensions.get('window').height
5
4
  const width = Dimensions.get('window').width
6
5
  return {
7
6
  overflow: {
@@ -17,7 +16,8 @@ export default function (theme) {
17
16
  },
18
17
  container: {
19
18
  flex: 1,
20
- overflow: 'hidden'
19
+ overflow: 'hidden',
20
+ backgroundColor: theme.colors.contentBackground
21
21
  },
22
22
  containerInner: {
23
23
  flex: 1
@@ -26,8 +26,7 @@ export default function (theme) {
26
26
  backgroundColor: theme.colors.contentBackground,
27
27
  flex: 1,
28
28
  paddingHorizontal: 5,
29
- paddingVertical: 20,
30
- minHeight: height // enough space for short news without excessive whitespace
29
+ paddingVertical: 20
31
30
  },
32
31
  activity: {
33
32
  marginTop: 20