ViewArticle.js 8.1 KB

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