mirror of https://github.com/tooot-app/app
Fixed #538
This commit is contained in:
parent
44379504eb
commit
73eb695cfc
|
@ -1,5 +1,6 @@
|
||||||
Enjoy toooting! This version includes following improvements and fixes:
|
Enjoy toooting! This version includes following improvements and fixes:
|
||||||
- Automatic setting detected language when tooting
|
- Automatic setting detected language when tooting
|
||||||
|
- Remember public timeline type selection
|
||||||
- Added notification for admins
|
- Added notification for admins
|
||||||
- Fix whole word filter matching
|
- Fix whole word filter matching
|
||||||
- Fix tablet cannot delete toot drafts
|
- Fix tablet cannot delete toot drafts
|
|
@ -1,5 +1,6 @@
|
||||||
toooting愉快!此版本包括以下改进和修复:
|
toooting愉快!此版本包括以下改进和修复:
|
||||||
- 自动识别发嘟语言
|
- 自动识别发嘟语言
|
||||||
|
- 记住上次公共时间轴选项
|
||||||
- 新增管理员推送通知
|
- 新增管理员推送通知
|
||||||
- 修复过滤整词功能
|
- 修复过滤整词功能
|
||||||
- 修复平板不能删除草稿
|
- 修复平板不能删除草稿
|
|
@ -3,14 +3,18 @@ import Timeline from '@components/Timeline'
|
||||||
import TimelineDefault from '@components/Timeline/Default'
|
import TimelineDefault from '@components/Timeline/Default'
|
||||||
import SegmentedControl from '@react-native-community/segmented-control'
|
import SegmentedControl from '@react-native-community/segmented-control'
|
||||||
import { NativeStackScreenProps } from '@react-navigation/native-stack'
|
import { NativeStackScreenProps } from '@react-navigation/native-stack'
|
||||||
|
import { useAppDispatch } from '@root/store'
|
||||||
|
import { ContextsLatest } from '@utils/migrations/contexts/migration'
|
||||||
import { TabPublicStackParamList } from '@utils/navigation/navigators'
|
import { TabPublicStackParamList } from '@utils/navigation/navigators'
|
||||||
import usePopToTop from '@utils/navigation/usePopToTop'
|
import usePopToTop from '@utils/navigation/usePopToTop'
|
||||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||||
|
import { getPreviousSegment, updatePreviousSegment } from '@utils/slices/contextsSlice'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Dimensions } from 'react-native'
|
import { Dimensions } from 'react-native'
|
||||||
import { SceneMap, TabView } from 'react-native-tab-view'
|
import { SceneMap, TabView } from 'react-native-tab-view'
|
||||||
|
import { useSelector } from 'react-redux'
|
||||||
|
|
||||||
const Route = ({ route: { key: page } }: { route: any }) => {
|
const Route = ({ route: { key: page } }: { route: any }) => {
|
||||||
const queryKey: QueryKeyTimeline = ['Timeline', { page }]
|
const queryKey: QueryKeyTimeline = ['Timeline', { page }]
|
||||||
|
@ -37,7 +41,12 @@ const Root: React.FC<NativeStackScreenProps<TabPublicStackParamList, 'Tab-Public
|
||||||
const { mode } = useTheme()
|
const { mode } = useTheme()
|
||||||
const { t } = useTranslation('screenTabs')
|
const { t } = useTranslation('screenTabs')
|
||||||
|
|
||||||
const [segment, setSegment] = useState(0)
|
const dispatch = useAppDispatch()
|
||||||
|
const previousSegment = useSelector(getPreviousSegment, () => true)
|
||||||
|
const segments: ContextsLatest['previousSegment'][] = ['Local', 'LocalPublic', 'Trending']
|
||||||
|
const [segment, setSegment] = useState<number>(
|
||||||
|
segments.findIndex(segment => segment === previousSegment)
|
||||||
|
)
|
||||||
const [routes] = useState([
|
const [routes] = useState([
|
||||||
{ key: 'Local', title: t('tabs.public.segments.local') },
|
{ key: 'Local', title: t('tabs.public.segments.local') },
|
||||||
{ key: 'LocalPublic', title: t('tabs.public.segments.federated') },
|
{ key: 'LocalPublic', title: t('tabs.public.segments.federated') },
|
||||||
|
@ -51,7 +60,10 @@ const Root: React.FC<NativeStackScreenProps<TabPublicStackParamList, 'Tab-Public
|
||||||
appearance={mode}
|
appearance={mode}
|
||||||
values={routes.map(({ title }) => title)}
|
values={routes.map(({ title }) => title)}
|
||||||
selectedIndex={segment}
|
selectedIndex={segment}
|
||||||
onChange={({ nativeEvent }) => setSegment(nativeEvent.selectedSegmentIndex)}
|
onChange={({ nativeEvent }) => {
|
||||||
|
setSegment(nativeEvent.selectedSegmentIndex)
|
||||||
|
dispatch(updatePreviousSegment(segments[nativeEvent.selectedSegmentIndex]))
|
||||||
|
}}
|
||||||
style={{ flexBasis: '65%' }}
|
style={{ flexBasis: '65%' }}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,8 +1,3 @@
|
||||||
/// <reference types="@welldone-software/why-did-you-render" />
|
|
||||||
|
|
||||||
import React from 'react'
|
|
||||||
import log from './log'
|
|
||||||
|
|
||||||
const dev = () => {
|
const dev = () => {
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
// log('log', 'devs', 'initializing wdyr')
|
// log('log', 'devs', 'initializing wdyr')
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import createSecureStore from '@neverdull-agency/expo-unlimited-secure-store'
|
import createSecureStore from '@neverdull-agency/expo-unlimited-secure-store'
|
||||||
import AsyncStorage from '@react-native-async-storage/async-storage'
|
import AsyncStorage from '@react-native-async-storage/async-storage'
|
||||||
import { AnyAction, configureStore, Reducer } from '@reduxjs/toolkit'
|
import { AnyAction, configureStore, Reducer } from '@reduxjs/toolkit'
|
||||||
import contextsMigration from '@utils/migrations/contexts/migration'
|
import contextsMigration, { ContextsLatest } from '@utils/migrations/contexts/migration'
|
||||||
import instancesMigration from '@utils/migrations/instances/migration'
|
import instancesMigration from '@utils/migrations/instances/migration'
|
||||||
import settingsMigration from '@utils/migrations/settings/migration'
|
import settingsMigration from '@utils/migrations/settings/migration'
|
||||||
import appSlice, { AppState } from '@utils/slices/appSlice'
|
import appSlice, { AppState } from '@utils/slices/appSlice'
|
||||||
import contextsSlice, { ContextsState } from '@utils/slices/contextsSlice'
|
import contextsSlice from '@utils/slices/contextsSlice'
|
||||||
import instancesSlice, { InstancesState } from '@utils/slices/instancesSlice'
|
import instancesSlice, { InstancesState } from '@utils/slices/instancesSlice'
|
||||||
import settingsSlice, { SettingsState } from '@utils/slices/settingsSlice'
|
import settingsSlice, { SettingsState } from '@utils/slices/settingsSlice'
|
||||||
import { Platform } from 'react-native'
|
import { Platform } from 'react-native'
|
||||||
|
@ -37,7 +37,7 @@ const contextsPersistConfig = {
|
||||||
key: 'contexts',
|
key: 'contexts',
|
||||||
prefix,
|
prefix,
|
||||||
storage: AsyncStorage,
|
storage: AsyncStorage,
|
||||||
version: 2,
|
version: 3,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
migrate: createMigrate(contextsMigration)
|
migrate: createMigrate(contextsMigration)
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ const store = configureStore({
|
||||||
reducer: {
|
reducer: {
|
||||||
app: persistReducer(appPersistConfig, appSlice) as Reducer<AppState, AnyAction>,
|
app: persistReducer(appPersistConfig, appSlice) as Reducer<AppState, AnyAction>,
|
||||||
contexts: persistReducer(contextsPersistConfig, contextsSlice) as Reducer<
|
contexts: persistReducer(contextsPersistConfig, contextsSlice) as Reducer<
|
||||||
ContextsState,
|
ContextsLatest,
|
||||||
AnyAction
|
AnyAction
|
||||||
>,
|
>,
|
||||||
instances: persistReducer(instancesPersistConfig, instancesSlice) as Reducer<
|
instances: persistReducer(instancesPersistConfig, instancesSlice) as Reducer<
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { ContextsV0 } from './v0'
|
import { ContextsV0 } from './v0'
|
||||||
import { ContextsV1 } from './v1'
|
import { ContextsV1 } from './v1'
|
||||||
import { ContextsV2 } from './v2'
|
import { ContextsV2 } from './v2'
|
||||||
|
import { ContextsV3 } from './v3'
|
||||||
|
|
||||||
const contextsMigration = {
|
const contextsMigration = {
|
||||||
1: (state: ContextsV0): ContextsV1 => {
|
1: (state: ContextsV0): ContextsV1 => {
|
||||||
|
@ -15,7 +16,12 @@ const contextsMigration = {
|
||||||
2: (state: ContextsV1): ContextsV2 => {
|
2: (state: ContextsV1): ContextsV2 => {
|
||||||
const { mePage, ...rest } = state
|
const { mePage, ...rest } = state
|
||||||
return rest
|
return rest
|
||||||
|
},
|
||||||
|
3: (state: ContextsV2): ContextsV3 => {
|
||||||
|
return { ...state, previousSegment: 'Local' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export { ContextsV3 as ContextsLatest }
|
||||||
|
|
||||||
export default contextsMigration
|
export default contextsMigration
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { ScreenTabsStackParamList } from '@utils/navigation/navigators'
|
||||||
|
|
||||||
|
export type ContextsV3 = {
|
||||||
|
storeReview: {
|
||||||
|
context: Readonly<number>
|
||||||
|
current: number
|
||||||
|
shown: boolean
|
||||||
|
}
|
||||||
|
publicRemoteNotice: {
|
||||||
|
context: Readonly<number>
|
||||||
|
current: number
|
||||||
|
hidden: boolean
|
||||||
|
}
|
||||||
|
previousTab: Extract<
|
||||||
|
keyof ScreenTabsStackParamList,
|
||||||
|
'Tab-Local' | 'Tab-Public' | 'Tab-Notifications' | 'Tab-Me'
|
||||||
|
>
|
||||||
|
previousSegment: Extract<App.Pages, 'Local' | 'LocalPublic' | 'Trending'>
|
||||||
|
}
|
|
@ -1,23 +1,10 @@
|
||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||||
import { RootState } from '@root/store'
|
import { RootState } from '@root/store'
|
||||||
|
import { ContextsLatest } from '@utils/migrations/contexts/migration'
|
||||||
import Constants from 'expo-constants'
|
import Constants from 'expo-constants'
|
||||||
import * as StoreReview from 'expo-store-review'
|
import * as StoreReview from 'expo-store-review'
|
||||||
|
|
||||||
export type ContextsState = {
|
export const contextsInitialState: ContextsLatest = {
|
||||||
storeReview: {
|
|
||||||
context: Readonly<number>
|
|
||||||
current: number
|
|
||||||
shown: boolean
|
|
||||||
}
|
|
||||||
publicRemoteNotice: {
|
|
||||||
context: Readonly<number>
|
|
||||||
current: number
|
|
||||||
hidden: boolean
|
|
||||||
}
|
|
||||||
previousTab: 'Tab-Local' | 'Tab-Public' | 'Tab-Notifications' | 'Tab-Me'
|
|
||||||
}
|
|
||||||
|
|
||||||
export const contextsInitialState = {
|
|
||||||
// After 10 successful postings
|
// After 10 successful postings
|
||||||
storeReview: {
|
storeReview: {
|
||||||
context: 10,
|
context: 10,
|
||||||
|
@ -30,49 +17,46 @@ export const contextsInitialState = {
|
||||||
current: 0,
|
current: 0,
|
||||||
hidden: false
|
hidden: false
|
||||||
},
|
},
|
||||||
previousTab: 'Tab-Me'
|
previousTab: 'Tab-Me',
|
||||||
|
previousSegment: 'Local'
|
||||||
}
|
}
|
||||||
|
|
||||||
const contextsSlice = createSlice({
|
const contextsSlice = createSlice({
|
||||||
name: 'contexts',
|
name: 'contexts',
|
||||||
initialState: contextsInitialState as ContextsState,
|
initialState: contextsInitialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
updateStoreReview: (state, action: PayloadAction<1>) => {
|
updateStoreReview: (state, action: PayloadAction<1>) => {
|
||||||
if (Constants.expoConfig?.extra?.environment === 'release') {
|
if (Constants.expoConfig?.extra?.environment === 'release') {
|
||||||
state.storeReview.current = state.storeReview.current + action.payload
|
state.storeReview.current = state.storeReview.current + action.payload
|
||||||
if (state.storeReview.current === state.storeReview.context) {
|
if (state.storeReview.current === state.storeReview.context) {
|
||||||
StoreReview?.isAvailableAsync().then(() =>
|
StoreReview?.isAvailableAsync().then(() => StoreReview.requestReview())
|
||||||
StoreReview.requestReview()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updatePublicRemoteNotice: (state, action: PayloadAction<1>) => {
|
updatePublicRemoteNotice: (state, action: PayloadAction<1>) => {
|
||||||
state.publicRemoteNotice.current =
|
state.publicRemoteNotice.current = state.publicRemoteNotice.current + action.payload
|
||||||
state.publicRemoteNotice.current + action.payload
|
if (state.publicRemoteNotice.current === state.publicRemoteNotice.context) {
|
||||||
if (
|
|
||||||
state.publicRemoteNotice.current === state.publicRemoteNotice.context
|
|
||||||
) {
|
|
||||||
state.publicRemoteNotice.hidden = true
|
state.publicRemoteNotice.hidden = true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updatePreviousTab: (
|
updatePreviousTab: (state, action: PayloadAction<ContextsLatest['previousTab']>) => {
|
||||||
state,
|
|
||||||
action: PayloadAction<ContextsState['previousTab']>
|
|
||||||
) => {
|
|
||||||
state.previousTab = action.payload
|
state.previousTab = action.payload
|
||||||
|
},
|
||||||
|
updatePreviousSegment: (state, action: PayloadAction<ContextsLatest['previousSegment']>) => {
|
||||||
|
state.previousSegment = action.payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const getPublicRemoteNotice = (state: RootState) =>
|
export const getPublicRemoteNotice = (state: RootState) => state.contexts.publicRemoteNotice
|
||||||
state.contexts.publicRemoteNotice
|
|
||||||
export const getPreviousTab = (state: RootState) => state.contexts.previousTab
|
export const getPreviousTab = (state: RootState) => state.contexts.previousTab
|
||||||
|
export const getPreviousSegment = (state: RootState) => state.contexts.previousSegment
|
||||||
export const getContexts = (state: RootState) => state.contexts
|
export const getContexts = (state: RootState) => state.contexts
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
updateStoreReview,
|
updateStoreReview,
|
||||||
updatePublicRemoteNotice,
|
updatePublicRemoteNotice,
|
||||||
updatePreviousTab
|
updatePreviousTab,
|
||||||
|
updatePreviousSegment
|
||||||
} = contextsSlice.actions
|
} = contextsSlice.actions
|
||||||
export default contextsSlice.reducer
|
export default contextsSlice.reducer
|
||||||
|
|
Loading…
Reference in New Issue