ViewArticle.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /**
  2. * 文章详情
  3. * @邠心vbe on 2023/10/24
  4. */
  5. import React, { Component } from 'react';
  6. import { View, StyleSheet, Image, ScrollView, Linking, Animated, Easing } from 'react-native';
  7. import Swiper from 'react-native-swiper';
  8. import apiArticle from '../../api/apiArticle';
  9. import TextView from '../../components/TextView';
  10. import VbeSkeleton from '../../components/VbeSkeleton';
  11. import utils from '../../utils/utils';
  12. import { PagerView } from './ViewUtil';
  13. import MyStatusBar from '../../components/MyStatusBar';
  14. import Toolbar, { BackButton } from '../../components/Toolbar';
  15. export default class ViewArticle extends Component {
  16. constructor(props) {
  17. super(props);
  18. this.state = {
  19. id: "",
  20. loading: true,
  21. showTitleBar: false,
  22. messageInfo: {
  23. articleTypeName: "",
  24. articleTitle: "",
  25. articleContent: ""
  26. },
  27. opacity: new Animated.Value(0)
  28. };
  29. }
  30. componentDidMount() {
  31. if (this.props.route?.params?.id) {
  32. this.setState({
  33. id: this.props.route?.params?.id
  34. }, () => {
  35. this.readMessage();
  36. })
  37. }
  38. MyStatusBar.setStatusBarTheme(MyStatusBar.LIGHT_STYLE);
  39. this.props.navigation.addListener('beforeRemove', (e) => {
  40. MyStatusBar.setStatusBarTheme(MyStatusBar.DEFAULT_STYLE);
  41. });
  42. }
  43. readMessage() {
  44. apiArticle.readMessage(this.state.id).then(res => {
  45. if (res.data) {
  46. this.setState({
  47. loading: false,
  48. messageInfo: res.data
  49. });
  50. //this.setPageTitle();
  51. }
  52. }).catch(err => {
  53. toastShort(err);
  54. });
  55. }
  56. setPageTitle() {
  57. if (this.state.messageInfo.articleTitle) {
  58. /*this.props.navigation.setOptions({
  59. headerTitle: () => (<HeaderTitle title={this.state.messageInfo.articleTitle}/>)
  60. })*/
  61. setTimeout(() => {
  62. this.setState({
  63. loading: false
  64. });
  65. }, 300);
  66. }
  67. }
  68. accessLink(url) {
  69. Linking.openURL(utils.getImageUrl(url))
  70. }
  71. onScrollView(e) {
  72. if (e.nativeEvent.contentOffset) {
  73. const isR = e.nativeEvent.contentOffset.y >= $vw(95);
  74. if (isR != this.state.showTitleBar) {
  75. this.setState({
  76. showTitleBar: isR
  77. });
  78. if (isR) {
  79. this.startTitleAnimate();
  80. } else {
  81. this.hideTitleAnimate();
  82. }
  83. MyStatusBar.setStatusBarTheme(isR ? MyStatusBar.DEFAULT_STYLE : MyStatusBar.LIGHT_STYLE);
  84. }
  85. }
  86. }
  87. startTitleAnimate() {
  88. Animated.timing(this.state.opacity, {
  89. toValue: 1,
  90. duration: 250,
  91. easing: Easing.linear,
  92. useNativeDriver: true
  93. }).start(() => {
  94. });
  95. }
  96. hideTitleAnimate() {
  97. Animated.timing(this.state.opacity, {
  98. toValue: 0,
  99. duration: 250,
  100. easing: Easing.linear,
  101. useNativeDriver: true
  102. }).start(() => {
  103. });
  104. }
  105. render() {
  106. if (this.state.loading) {
  107. return (
  108. <View style={styles.container}>
  109. <VbeSkeleton
  110. style={{width: $width, height: $width}}
  111. layout={[
  112. {width: $width, height: $width}
  113. ]}
  114. animationDirection={"horizontalRight"}/>
  115. <VbeSkeleton
  116. style={styles.loadingView}
  117. layout={[
  118. {width: '90%', height: 20, marginTop: 8},
  119. {width: '50%', height: 12, marginTop: 8},
  120. {width: '100%', height: 15, marginTop: 24},
  121. {width: '100%', height: 15, marginTop: 8},
  122. {width: '100%', height: 15, marginTop: 8},
  123. {width: '100%', height: 15, marginTop: 8},
  124. {width: '30%', height: 15, marginTop: 8},
  125. {width: '100%', height: 15, marginTop: 24},
  126. {width: '100%', height: 15, marginTop: 8},
  127. {width: '100%', height: 15, marginTop: 8},
  128. {width: '100%', height: 15, marginTop: 8},
  129. {width: '30%', height: 15, marginTop: 8}
  130. ]}
  131. animationDirection={"horizontalRight"}/>
  132. </View>
  133. )
  134. } else {
  135. return (
  136. <>
  137. <ScrollView
  138. style={styles.container}
  139. onScroll={e => this.onScrollView(e)}
  140. scrollEventThrottle={16}
  141. contentContainerStyle={$padding(0,0,32)}>
  142. { utils.isNotEmpty(this.state.messageInfo.articleImages) &&
  143. <Swiper
  144. style={{height: $width}}
  145. autoplay={true}
  146. autoplayTimeout={5}
  147. renderPagination={(index,total) => <PagerView index={index+1} total={total}/> }
  148. removeClippedSubviews={false}>
  149. { this.state.messageInfo.articleImages.map((item, index) => {
  150. return (
  151. <Image
  152. key={index}
  153. style={{width: $width, height: $width}}
  154. source={{uri: utils.getImageUrl(item.articleImagePath)}}/>
  155. );
  156. })}
  157. </Swiper>
  158. }
  159. <View style={styles.header}>
  160. <TextView
  161. style={styles.textTitle}>
  162. {this.state.messageInfo.articleTitle}
  163. </TextView>
  164. <View style={ui.flexc}>
  165. <MaterialCommunityIcons
  166. name="clock-time-four-outline"
  167. color={textSecondary}
  168. size={12}/>
  169. <TextView
  170. style={styles.textDate}
  171. numberOfLines={1}>
  172. {this.state.messageInfo.createTime}
  173. </TextView>
  174. <View style={ui.flexc}>
  175. <MaterialCommunityIcons
  176. name="eye-check-outline"
  177. size={12}
  178. color={textPrimary}/>
  179. <TextView
  180. style={styles.textView}
  181. numberOfLines={1}>
  182. {this.state.messageInfo.articleViews}
  183. </TextView>
  184. </View>
  185. </View>
  186. <View style={ui.flex}>
  187. <TextView
  188. style={styles.labelTypeText}
  189. numberOfLines={1}>
  190. {this.state.messageInfo.articleTypeName}
  191. </TextView>
  192. </View>
  193. </View>
  194. <TextView
  195. style={styles.textMessage}
  196. selectable={true}>
  197. {this.state.messageInfo.articleContent}
  198. </TextView>
  199. { utils.isNotEmpty(this.state.messageInfo.articleLinks) &&
  200. <>
  201. <TextView style={styles.textLinkTitle}>{$t("notification.labelLinks")}</TextView>
  202. { this.state.messageInfo.articleLinks.map((item, index) =>
  203. <View style={styles.itemLink} key={index}>
  204. <TextView style={styles.linkIndex}>{index + 1}.</TextView>
  205. <TextView
  206. style={styles.linkHyper}
  207. onPress={() => this.accessLink(item.articleLink)}>{item.articleLinkName}</TextView>
  208. </View>
  209. )}
  210. </>
  211. }
  212. <EndView/>
  213. </ScrollView>
  214. { !this.state.showTitleBar &&
  215. <View style={[styles.toolbar, {top: statusHeight}]}>
  216. <BackButton style={styles.backIcon} color={"#F0F0F0"}/>
  217. </View>
  218. }
  219. <Animated.View style={[styles.toolbar, {opacity: this.state.opacity}]}>
  220. <Toolbar title={this.state.messageInfo.articleTitle}/>
  221. </Animated.View>
  222. </>
  223. );
  224. }
  225. }
  226. }
  227. const styles = StyleSheet.create({
  228. container: {
  229. flex: 1,
  230. backgroundColor: pageBackground
  231. },
  232. toolbar: {
  233. top: 0,
  234. left: 0,
  235. right: 0,
  236. zIndex: 2,
  237. position: 'absolute'
  238. },
  239. backIcon: {
  240. width: 48,
  241. height: toolbarSize,
  242. zIndex: 2,
  243. marginLeft: isIOS ? 0 : 2,
  244. alignItems: 'center',
  245. justifyContent: 'center'
  246. },
  247. loadingView: {
  248. flex: 1,
  249. padding: 16,
  250. justifyContent: 'flex-start',
  251. backgroundColor: pageBackground
  252. },
  253. textTitle: {
  254. color: textPrimary,
  255. fontSize: 18,
  256. fontWeight: 'bold',
  257. paddingBottom: 2
  258. },
  259. textDate: {
  260. flex: 1,
  261. color: textSecondary,
  262. fontSize: 10,
  263. paddingLeft: 2
  264. },
  265. textView: {
  266. color: textSecondary,
  267. fontSize: 10,
  268. padding: 4
  269. },
  270. header: {
  271. padding: 16,
  272. backgroundColor: pageBackground
  273. },
  274. textMessage: {
  275. color: textPrimary,
  276. fontSize: 12,
  277. paddingLeft: 16,
  278. paddingRight: 16
  279. },
  280. labelTypeText: {
  281. fontSize: 12,
  282. fontWeight: 'bold',
  283. borderWidth: 1,
  284. borderRadius: 4,
  285. borderColor: colorPrimary,
  286. marginTop: 8,
  287. ...$padding(2, 6)
  288. },
  289. textLinkTitle: {
  290. color: textPrimary,
  291. fontSize: 14,
  292. fontWeight: 'bold',
  293. padding: 16
  294. },
  295. itemLink: {
  296. ...$padding(0, 16, 8),
  297. flexDirection: 'row'
  298. },
  299. linkIndex: {
  300. fontSize: 12,
  301. paddingRight: 2
  302. },
  303. linkHyper: {
  304. ...ui.link,
  305. fontSize: 12,
  306. textDecorationLine: 'underline'
  307. },
  308. linkActive: {
  309. color: "#FF3B30"
  310. }
  311. })