diff --git a/fastlane/metadata/en-US/release_notes.txt b/fastlane/metadata/en-US/release_notes.txt index 103e95c2..492ae4bc 100644 --- a/fastlane/metadata/en-US/release_notes.txt +++ b/fastlane/metadata/en-US/release_notes.txt @@ -1,5 +1,6 @@ Enjoy toooting! This version includes following improvements and fixes: - Automatic setting detected language when tooting +- Remember public timeline type selection - Added notification for admins - Fix whole word filter matching - Fix tablet cannot delete toot drafts \ 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 b7098afa..4e3b5ced 100644 --- a/fastlane/metadata/zh-Hans/release_notes.txt +++ b/fastlane/metadata/zh-Hans/release_notes.txt @@ -1,5 +1,6 @@ toooting愉快!此版本包括以下改进和修复: - 自动识别发嘟语言 +- 记住上次公共时间轴选项 - 新增管理员推送通知 - 修复过滤整词功能 - 修复平板不能删除草稿 \ No newline at end of file diff --git a/src/screens/Tabs/Public/Root.tsx b/src/screens/Tabs/Public/Root.tsx index 4451ea11..c1c07284 100644 --- a/src/screens/Tabs/Public/Root.tsx +++ b/src/screens/Tabs/Public/Root.tsx @@ -3,14 +3,18 @@ import Timeline from '@components/Timeline' import TimelineDefault from '@components/Timeline/Default' import SegmentedControl from '@react-native-community/segmented-control' 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 usePopToTop from '@utils/navigation/usePopToTop' import { QueryKeyTimeline } from '@utils/queryHooks/timeline' +import { getPreviousSegment, updatePreviousSegment } from '@utils/slices/contextsSlice' import { useTheme } from '@utils/styles/ThemeManager' import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { Dimensions } from 'react-native' import { SceneMap, TabView } from 'react-native-tab-view' +import { useSelector } from 'react-redux' const Route = ({ route: { key: page } }: { route: any }) => { const queryKey: QueryKeyTimeline = ['Timeline', { page }] @@ -37,7 +41,12 @@ const Root: React.FC true) + const segments: ContextsLatest['previousSegment'][] = ['Local', 'LocalPublic', 'Trending'] + const [segment, setSegment] = useState( + segments.findIndex(segment => segment === previousSegment) + ) const [routes] = useState([ { key: 'Local', title: t('tabs.public.segments.local') }, { key: 'LocalPublic', title: t('tabs.public.segments.federated') }, @@ -51,7 +60,10 @@ const Root: React.FC title)} selectedIndex={segment} - onChange={({ nativeEvent }) => setSegment(nativeEvent.selectedSegmentIndex)} + onChange={({ nativeEvent }) => { + setSegment(nativeEvent.selectedSegmentIndex) + dispatch(updatePreviousSegment(segments[nativeEvent.selectedSegmentIndex])) + }} style={{ flexBasis: '65%' }} /> ), diff --git a/src/startup/dev.ts b/src/startup/dev.ts index cd00e174..12915585 100644 --- a/src/startup/dev.ts +++ b/src/startup/dev.ts @@ -1,8 +1,3 @@ -/// - -import React from 'react' -import log from './log' - const dev = () => { if (__DEV__) { // log('log', 'devs', 'initializing wdyr') diff --git a/src/store.ts b/src/store.ts index f9725338..7673ea8f 100644 --- a/src/store.ts +++ b/src/store.ts @@ -1,11 +1,11 @@ import createSecureStore from '@neverdull-agency/expo-unlimited-secure-store' import AsyncStorage from '@react-native-async-storage/async-storage' 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 settingsMigration from '@utils/migrations/settings/migration' 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 settingsSlice, { SettingsState } from '@utils/slices/settingsSlice' import { Platform } from 'react-native' @@ -37,7 +37,7 @@ const contextsPersistConfig = { key: 'contexts', prefix, storage: AsyncStorage, - version: 2, + version: 3, // @ts-ignore migrate: createMigrate(contextsMigration) } @@ -64,7 +64,7 @@ const store = configureStore({ reducer: { app: persistReducer(appPersistConfig, appSlice) as Reducer, contexts: persistReducer(contextsPersistConfig, contextsSlice) as Reducer< - ContextsState, + ContextsLatest, AnyAction >, instances: persistReducer(instancesPersistConfig, instancesSlice) as Reducer< diff --git a/src/utils/migrations/contexts/migration.ts b/src/utils/migrations/contexts/migration.ts index 2dedf997..faa57786 100644 --- a/src/utils/migrations/contexts/migration.ts +++ b/src/utils/migrations/contexts/migration.ts @@ -1,6 +1,7 @@ import { ContextsV0 } from './v0' import { ContextsV1 } from './v1' import { ContextsV2 } from './v2' +import { ContextsV3 } from './v3' const contextsMigration = { 1: (state: ContextsV0): ContextsV1 => { @@ -15,7 +16,12 @@ const contextsMigration = { 2: (state: ContextsV1): ContextsV2 => { const { mePage, ...rest } = state return rest + }, + 3: (state: ContextsV2): ContextsV3 => { + return { ...state, previousSegment: 'Local' } } } +export { ContextsV3 as ContextsLatest } + export default contextsMigration diff --git a/src/utils/migrations/contexts/v3.ts b/src/utils/migrations/contexts/v3.ts new file mode 100644 index 00000000..0f35df8b --- /dev/null +++ b/src/utils/migrations/contexts/v3.ts @@ -0,0 +1,19 @@ +import { ScreenTabsStackParamList } from '@utils/navigation/navigators' + +export type ContextsV3 = { + storeReview: { + context: Readonly + current: number + shown: boolean + } + publicRemoteNotice: { + context: Readonly + current: number + hidden: boolean + } + previousTab: Extract< + keyof ScreenTabsStackParamList, + 'Tab-Local' | 'Tab-Public' | 'Tab-Notifications' | 'Tab-Me' + > + previousSegment: Extract +} diff --git a/src/utils/slices/contextsSlice.ts b/src/utils/slices/contextsSlice.ts index 27a4235f..df99bdd6 100644 --- a/src/utils/slices/contextsSlice.ts +++ b/src/utils/slices/contextsSlice.ts @@ -1,23 +1,10 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { RootState } from '@root/store' +import { ContextsLatest } from '@utils/migrations/contexts/migration' import Constants from 'expo-constants' import * as StoreReview from 'expo-store-review' -export type ContextsState = { - storeReview: { - context: Readonly - current: number - shown: boolean - } - publicRemoteNotice: { - context: Readonly - current: number - hidden: boolean - } - previousTab: 'Tab-Local' | 'Tab-Public' | 'Tab-Notifications' | 'Tab-Me' -} - -export const contextsInitialState = { +export const contextsInitialState: ContextsLatest = { // After 10 successful postings storeReview: { context: 10, @@ -30,49 +17,46 @@ export const contextsInitialState = { current: 0, hidden: false }, - previousTab: 'Tab-Me' + previousTab: 'Tab-Me', + previousSegment: 'Local' } const contextsSlice = createSlice({ name: 'contexts', - initialState: contextsInitialState as ContextsState, + initialState: contextsInitialState, reducers: { updateStoreReview: (state, action: PayloadAction<1>) => { if (Constants.expoConfig?.extra?.environment === 'release') { state.storeReview.current = state.storeReview.current + action.payload if (state.storeReview.current === state.storeReview.context) { - StoreReview?.isAvailableAsync().then(() => - StoreReview.requestReview() - ) + StoreReview?.isAvailableAsync().then(() => StoreReview.requestReview()) } } }, updatePublicRemoteNotice: (state, action: PayloadAction<1>) => { - state.publicRemoteNotice.current = - state.publicRemoteNotice.current + action.payload - if ( - state.publicRemoteNotice.current === state.publicRemoteNotice.context - ) { + state.publicRemoteNotice.current = state.publicRemoteNotice.current + action.payload + if (state.publicRemoteNotice.current === state.publicRemoteNotice.context) { state.publicRemoteNotice.hidden = true } }, - updatePreviousTab: ( - state, - action: PayloadAction - ) => { + updatePreviousTab: (state, action: PayloadAction) => { state.previousTab = action.payload + }, + updatePreviousSegment: (state, action: PayloadAction) => { + state.previousSegment = action.payload } } }) -export const getPublicRemoteNotice = (state: RootState) => - state.contexts.publicRemoteNotice +export const getPublicRemoteNotice = (state: RootState) => state.contexts.publicRemoteNotice 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 { updateStoreReview, updatePublicRemoteNotice, - updatePreviousTab + updatePreviousTab, + updatePreviousSegment } = contextsSlice.actions export default contextsSlice.reducer