mirror of
				https://github.com/tooot-app/app
				synced 2025-06-05 22:19:13 +02:00 
			
		
		
		
	Fixed #525
HTML is removed. In this way, if a URL is changed, it can be highlighted as well
This commit is contained in:
		| @@ -1,6 +1,7 @@ | ||||
| Enjoy toooting! This version includes following improvements and fixes: | ||||
| - Automatic setting detected language when tooting | ||||
| - Remember public timeline type selection | ||||
| - Show diffing of edit history | ||||
| - Added notification for admins | ||||
| - Fix whole word filter matching | ||||
| - Fix tablet cannot delete toot drafts | ||||
| @@ -1,6 +1,7 @@ | ||||
| toooting愉快!此版本包括以下改进和修复: | ||||
| - 自动识别发嘟语言 | ||||
| - 记住上次公共时间轴选项 | ||||
| - 显示编辑历史的差异 | ||||
| - 新增管理员推送通知 | ||||
| - 修复过滤整词功能 | ||||
| - 修复平板不能删除草稿 | ||||
| @@ -43,6 +43,7 @@ | ||||
|     "@sharcoux/slider": "^6.1.1", | ||||
|     "@tanstack/react-query": "^4.19.1", | ||||
|     "axios": "^0.27.2", | ||||
|     "diff": "^5.1.0", | ||||
|     "expo": "^47.0.8", | ||||
|     "expo-auth-session": "^3.7.3", | ||||
|     "expo-av": "^13.0.2", | ||||
| @@ -101,6 +102,7 @@ | ||||
|     "@babel/preset-react": "^7.18.6", | ||||
|     "@babel/preset-typescript": "^7.18.6", | ||||
|     "@expo/config": "^7.0.3", | ||||
|     "@types/diff": "^5.0.2", | ||||
|     "@types/linkify-it": "^3.0.2", | ||||
|     "@types/lodash": "^4.14.191", | ||||
|     "@types/react": "~18.0.26", | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import { StyleConstants } from '@utils/styles/constants' | ||||
| import { adaptiveScale } from '@utils/styles/scaling' | ||||
| import { useTheme } from '@utils/styles/ThemeManager' | ||||
| import React, { useMemo } from 'react' | ||||
| import { Platform, StyleSheet } from 'react-native' | ||||
| import { Platform, StyleSheet, TextStyle } from 'react-native' | ||||
| import FastImage from 'react-native-fast-image' | ||||
| import { useSelector } from 'react-redux' | ||||
| import validUrl from 'valid-url' | ||||
| @@ -18,10 +18,11 @@ export interface Props { | ||||
|   size?: 'S' | 'M' | 'L' | ||||
|   adaptiveSize?: boolean | ||||
|   fontBold?: boolean | ||||
|   style?: TextStyle | ||||
| } | ||||
|  | ||||
| const ParseEmojis = React.memo( | ||||
|   ({ content, emojis, size = 'M', adaptiveSize = false, fontBold = false }: Props) => { | ||||
|   ({ content, emojis, size = 'M', adaptiveSize = false, fontBold = false, style }: Props) => { | ||||
|     const { reduceMotionEnabled } = useAccessibility() | ||||
|  | ||||
|     const adaptiveFontsize = useSelector(getSettingsFontsize) | ||||
| @@ -51,7 +52,7 @@ const ParseEmojis = React.memo( | ||||
|     }, [theme, adaptiveFontsize]) | ||||
|  | ||||
|     return ( | ||||
|       <CustomText style={styles.text} fontWeight={fontBold ? 'Bold' : undefined}> | ||||
|       <CustomText style={[styles.text, style]} fontWeight={fontBold ? 'Bold' : undefined}> | ||||
|         {emojis ? ( | ||||
|           content | ||||
|             .split(regexEmoji) | ||||
|   | ||||
							
								
								
									
										18
									
								
								src/helpers/removeHTML.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/helpers/removeHTML.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| import htmlparser2 from 'htmlparser2-without-node-native' | ||||
|  | ||||
| const removeHTML = (text: string): string => { | ||||
|   let raw: string = '' | ||||
|  | ||||
|   const parser = new htmlparser2.Parser({ | ||||
|     ontext: (text: string) => { | ||||
|       raw = raw + text | ||||
|     } | ||||
|   }) | ||||
|  | ||||
|   parser.write(text) | ||||
|   parser.end() | ||||
|  | ||||
|   return raw | ||||
| } | ||||
|  | ||||
| export default removeHTML | ||||
| @@ -4,25 +4,66 @@ import { ParseEmojis } from '@components/Parse' | ||||
| import ComponentSeparator from '@components/Separator' | ||||
| import CustomText from '@components/Text' | ||||
| import TimelineAttachment from '@components/Timeline/Shared/Attachment' | ||||
| import TimelineContent from '@components/Timeline/Shared/Content' | ||||
| import StatusContext from '@components/Timeline/Shared/Context' | ||||
| import HeaderSharedCreated from '@components/Timeline/Shared/HeaderShared/Created' | ||||
| import removeHTML from '@helpers/removeHTML' | ||||
| import { TabSharedStackScreenProps } from '@utils/navigation/navigators' | ||||
| import { useStatusHistory } from '@utils/queryHooks/statusesHistory' | ||||
| import { StyleConstants } from '@utils/styles/constants' | ||||
| import { useTheme } from '@utils/styles/ThemeManager' | ||||
| import { diffWords } from 'diff' | ||||
| import React, { useEffect } from 'react' | ||||
| import { useTranslation } from 'react-i18next' | ||||
| import { FlatList, View } from 'react-native' | ||||
|  | ||||
| const ContentView: React.FC<{ item: Mastodon.StatusHistory }> = ({ item }) => { | ||||
| const ContentView: React.FC<{ | ||||
|   item: Mastodon.StatusHistory | ||||
|   prevItem?: Mastodon.StatusHistory | ||||
| }> = ({ item, prevItem }) => { | ||||
|   const { colors } = useTheme() | ||||
|  | ||||
|   const changesSpoiler = diffWords( | ||||
|     removeHTML(prevItem?.spoiler_text || item.spoiler_text || ''), | ||||
|     removeHTML(item.spoiler_text || '') | ||||
|   ) | ||||
|   const changesContent = diffWords( | ||||
|     removeHTML(prevItem?.content || item.content), | ||||
|     removeHTML(item.content) | ||||
|   ) | ||||
|  | ||||
|   return ( | ||||
|     // @ts-ignore | ||||
|     <StatusContext.Provider value={{ status: item, disableOnPress: true }}> | ||||
|       <View style={{ padding: StyleConstants.Spacing.Global.PagePadding }}> | ||||
|         <HeaderSharedCreated created_at={item.created_at} /> | ||||
|       <TimelineContent /> | ||||
|         {changesSpoiler.length && changesSpoiler[0].count ? ( | ||||
|           <CustomText fontSize='M' style={{ color: colors.primaryDefault }}> | ||||
|             {changesSpoiler.map(({ value, added, removed }, index) => ( | ||||
|               <ParseEmojis | ||||
|                 key={index} | ||||
|                 content={value} | ||||
|                 emojis={item.emojis} | ||||
|                 style={{ | ||||
|                   color: added ? colors.green : removed ? colors.red : undefined, | ||||
|                   textDecorationLine: removed ? 'line-through' : undefined | ||||
|                 }} | ||||
|               /> | ||||
|             ))} | ||||
|           </CustomText> | ||||
|         ) : null} | ||||
|         <CustomText fontSize='M' style={{ color: colors.primaryDefault }}> | ||||
|           {changesContent.map(({ value, added, removed }, index) => ( | ||||
|             <ParseEmojis | ||||
|               key={index} | ||||
|               content={value} | ||||
|               emojis={item.emojis} | ||||
|               style={{ | ||||
|                 color: added ? colors.green : removed ? colors.red : undefined, | ||||
|                 textDecorationLine: removed ? 'line-through' : undefined | ||||
|               }} | ||||
|             /> | ||||
|           ))} | ||||
|         </CustomText> | ||||
|         {item.poll?.options.map((option, index) => ( | ||||
|           <View key={index} style={{ flex: 1, paddingVertical: StyleConstants.Spacing.XS }}> | ||||
|             <View style={{ flex: 1, flexDirection: 'row' }}> | ||||
| @@ -42,6 +83,7 @@ const ContentView: React.FC<{ item: Mastodon.StatusHistory }> = ({ item }) => { | ||||
|           </View> | ||||
|         ))} | ||||
|         <TimelineAttachment /> | ||||
|       </View> | ||||
|     </StatusContext.Provider> | ||||
|   ) | ||||
| } | ||||
| @@ -62,41 +104,18 @@ const TabSharedHistory: React.FC<TabSharedStackScreenProps<'Tab-Shared-History'> | ||||
|     }) | ||||
|   }, []) | ||||
|  | ||||
|   const dataReversed = data ? [...data].reverse() : [] | ||||
|  | ||||
|   return ( | ||||
|     <FlatList | ||||
|       style={{ flex: 1, minHeight: '100%', padding: StyleConstants.Spacing.Global.PagePadding }} | ||||
|       data={ | ||||
|         data && data.length > 0 | ||||
|           ? data | ||||
|               .slice(0) | ||||
|               .reverse() | ||||
|               .filter((_, index) => index !== 0) | ||||
|           : [] | ||||
|       } | ||||
|       renderItem={({ item }) => <ContentView item={item} />} | ||||
|       ItemSeparatorComponent={() => ( | ||||
|         <ComponentSeparator | ||||
|           extraMarginLeft={0} | ||||
|           style={{ marginVertical: StyleConstants.Spacing.Global.PagePadding }} | ||||
|         /> | ||||
|       style={{ flex: 1, minHeight: '100%' }} | ||||
|       data={dataReversed} | ||||
|       renderItem={({ item, index }) => ( | ||||
|         <ContentView item={item} prevItem={dataReversed[index + 1]} /> | ||||
|       )} | ||||
|       ItemSeparatorComponent={ComponentSeparator} | ||||
|     /> | ||||
|   ) | ||||
|  | ||||
|   // return ( | ||||
|   //   <ScrollView> | ||||
|   //     {data && data.length > 0 | ||||
|   //       ? data | ||||
|   //           .slice(0) | ||||
|   //           .reverse() | ||||
|   //           .map((d, i) => | ||||
|   //             i !== 0 ? ( | ||||
|   //               <ContentView key={i} history={d} first={i === 1} last={i === data.length - 1} /> | ||||
|   //             ) : null | ||||
|   //           ) | ||||
|   //       : null} | ||||
|   //   </ScrollView> | ||||
|   // ) | ||||
| } | ||||
|  | ||||
| export default TabSharedHistory | ||||
|   | ||||
							
								
								
									
										10
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								yarn.lock
									
									
									
									
									
								
							| @@ -2683,6 +2683,11 @@ | ||||
|     "@types/node" "*" | ||||
|     "@types/responselike" "^1.0.0" | ||||
|  | ||||
| "@types/diff@^5.0.2": | ||||
|   version "5.0.2" | ||||
|   resolved "https://registry.yarnpkg.com/@types/diff/-/diff-5.0.2.tgz#dd565e0086ccf8bc6522c6ebafd8a3125c91c12b" | ||||
|   integrity sha512-uw8eYMIReOwstQ0QKF0sICefSy8cNO/v7gOTiIy9SbwuHyEecJUm7qlgueOO5S1udZ5I/irVydHVwMchgzbKTg== | ||||
|  | ||||
| "@types/glob@^7.1.1": | ||||
|   version "7.2.0" | ||||
|   resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" | ||||
| @@ -5256,6 +5261,11 @@ detect-port-alt@1.1.6: | ||||
|     address "^1.0.1" | ||||
|     debug "^2.6.0" | ||||
|  | ||||
| diff@^5.1.0: | ||||
|   version "5.1.0" | ||||
|   resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" | ||||
|   integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== | ||||
|  | ||||
| diffie-hellman@^5.0.0: | ||||
|   version "5.0.3" | ||||
|   resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user