diff --git a/fastlane/metadata/en-US/release_notes.txt b/fastlane/metadata/en-US/release_notes.txt index 46181811..9e6b2fe9 100644 --- a/fastlane/metadata/en-US/release_notes.txt +++ b/fastlane/metadata/en-US/release_notes.txt @@ -1,9 +1,2 @@ Enjoy toooting! This version includes following improvements and fixes: -- Auto fetch remote content in conversations! -- Remember last read position in timeline! -- Follow a user with other logged in accounts -- Allowing adding more context of reports -- Option to disable autoplay gif -- Hide boosts from users -- Followed hashtags are underlined -- Support GoToSocial \ No newline at end of file +- Added following remote instance \ No newline at end of file diff --git a/fastlane/metadata/zh-Hans/release_notes.txt b/fastlane/metadata/zh-Hans/release_notes.txt index df4f1cc5..05869c85 100644 --- a/fastlane/metadata/zh-Hans/release_notes.txt +++ b/fastlane/metadata/zh-Hans/release_notes.txt @@ -1,9 +1,2 @@ toooting愉快!此版本包括以下改进和修复: -- 主动获取对话的远程内容 -- 自动加载上次我的关注的阅读位置 -- 用其它已登陆的账户关注用户 -- 可添加举报细节 -- 新增暂停自动播放gif动画选项 -- 隐藏用户的转嘟 -- 下划线高亮正在关注的话题标签 -- 支持GoToSocial \ No newline at end of file +- 新增关注远程实例功能 \ No newline at end of file diff --git a/package.json b/package.json index ed39a02e..96cfbca4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tooot", - "version": "4.8.9", + "version": "4.9.0", "description": "tooot for Mastodon", "author": "xmflsct ", "license": "GPL-3.0-or-later", diff --git a/src/@types/app.d.ts b/src/@types/app.d.ts index 3b2b9525..36b6ff82 100644 --- a/src/@types/app.d.ts +++ b/src/@types/app.d.ts @@ -3,7 +3,7 @@ declare namespace App { | 'Following' | 'Local' | 'LocalPublic' - | 'Trending' + | 'Explore' | 'Notifications' | 'Hashtag' | 'List' diff --git a/src/components/Menu/Row.tsx b/src/components/Menu/Row.tsx index ffad2741..28967bc5 100644 --- a/src/components/Menu/Row.tsx +++ b/src/components/Menu/Row.tsx @@ -22,7 +22,7 @@ export interface Props { switchDisabled?: boolean switchOnValueChange?: () => void - iconBack?: 'chevron-right' | 'external-link' | 'check' + iconBack?: 'chevron-right' | 'chevron-down' | 'external-link' | 'check' iconBackColor?: ColorDefinitions loading?: boolean @@ -66,14 +66,7 @@ const MenuRow: React.FC = ({ }} > - + { style={{ flex: 1, borderWidth: StyleSheet.hairlineWidth, - borderRadius: 6, + borderRadius: StyleConstants.Spacing.S, margin: StyleConstants.Spacing.Global.PagePadding, borderColor: colors.border }} diff --git a/src/screens/Tabs/Public/Root.tsx b/src/screens/Tabs/Public/Root.tsx index 95540a5f..97f44517 100644 --- a/src/screens/Tabs/Public/Root.tsx +++ b/src/screens/Tabs/Public/Root.tsx @@ -1,26 +1,384 @@ -import { HeaderRight } from '@components/Header' +import Button from '@components/Button' +import { HeaderLeft, HeaderRight } from '@components/Header' +import Icon from '@components/Icon' +import CustomText from '@components/Text' import Timeline from '@components/Timeline' import SegmentedControl from '@react-native-segmented-control/segmented-control' import { NativeStackScreenProps } from '@react-navigation/native-stack' +import apiGeneral from '@utils/api/general' import { TabPublicStackParamList } from '@utils/navigation/navigators' +import { useInstanceQuery } from '@utils/queryHooks/instance' import { QueryKeyTimeline } from '@utils/queryHooks/timeline' -import { getGlobalStorage, setGlobalStorage } from '@utils/storage/actions' +import { getGlobalStorage, setGlobalStorage, useGlobalStorage } from '@utils/storage/actions' import { StorageGlobal } from '@utils/storage/global' +import { StyleConstants } from '@utils/styles/constants' +import layoutAnimation from '@utils/styles/layoutAnimation' import { useTheme } from '@utils/styles/ThemeManager' -import { useEffect, useState } from 'react' +import { debounce } from 'lodash' +import { useCallback, useEffect, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -import { Dimensions } from 'react-native' +import { Dimensions, FlatList, Platform, Pressable, TextInput, View } from 'react-native' import { SceneMap, TabView } from 'react-native-tab-view' +import { Placeholder, PlaceholderLine } from 'rn-placeholder' +import * as DropdownMenu from 'zeego/dropdown-menu' -const Route = ({ route: { key: page } }: { route: any }) => { +const Explore = ({ route: { key: page } }: { route: { key: 'Explore' } }) => { + const { t } = useTranslation(['common', 'componentInstance', 'screenTabs']) + const { colors, mode } = useTheme() + + const [addingRemote, setAddingRemote] = useState(false) + const [domain, setDomain] = useState('') + const [domainValid, setDomainValid] = useState() + const instanceQuery = useInstanceQuery({ + domain, + options: { + enabled: false, + retry: false, + keepPreviousData: false, + cacheTime: 1000 * 30, + onSuccess: () => + apiGeneral({ + method: 'get', + domain: domain, + url: 'api/v1/timelines/public', + params: { local: 'true', limit: 1 } + }) + .then(({ body }) => { + if (Array.isArray(body)) { + setDomainValid(true) + } else { + setDomainValid(false) + } + }) + .catch(() => setDomainValid(false)) + } + }) + const debounceFetch = useCallback( + debounce(() => { + instanceQuery.refetch() + }, 1000), + [] + ) + + const [accountActive] = useGlobalStorage.string('account.active') + const [remoteActive, setRemoteActive] = useGlobalStorage.string('remote.active') + const [remotes, setRemotes] = useGlobalStorage.object('remotes') + + const flRef = useRef(null) + const queryKey: QueryKeyTimeline = [ + 'Timeline', + { page, ...(remoteActive && { domain: remoteActive }) } + ] + + const info = ({ + heading, + content, + lines, + potentialWidth = 6 + }: { + heading: string + content?: string + lines?: number + potentialWidth?: number + }) => ( + + + {content ? ( + + ) : ( + Array.from({ length: lines || 1 }).map((_, index) => ( + + )) + )} + + ) + + return ( + + + { + setDomain('') + setAddingRemote(false) + layoutAnimation().then(() => + flRef.current?.scrollToOffset({ animated: true, offset: 0 }) + ) + }} + /> + + {}} /> + + + + { + setDomain(text.replace(/^http(s)?\:\/\//i, '')) + setDomainValid(undefined) + debounceFetch() + }} + autoCapitalize='none' + clearButtonMode='never' + keyboardType='url' + textContentType='URL' + onSubmitEditing={() => instanceQuery.refetch()} + placeholder={' ' + t('componentInstance:server.textInput.placeholder')} + placeholderTextColor={colors.secondary} + returnKeyType='go' + keyboardAppearance={mode} + autoCorrect={false} + spellCheck={false} + autoFocus + /> +