mirror of
https://github.com/tooot-app/app
synced 2025-06-05 22:19:13 +02:00
Refine notifications
https://github.com/tooot-app/app/issues/306 https://github.com/tooot-app/app/issues/305 This one uses the positive filtering that is added since v3.5, that a such a filter won't be shown as there is no way to check if a user is an admin or not and showing a useless option for majority users won't be a good experience.
This commit is contained in:
@ -1,13 +1,14 @@
|
||||
import queryClient from '@helpers/queryClient'
|
||||
import { store } from '@root/store'
|
||||
import { InstanceLatest } from './migrations/instances/migration'
|
||||
// import { prefetchTimelineQuery } from './queryHooks/timeline'
|
||||
import { Instance, updateInstanceActive } from './slices/instancesSlice'
|
||||
import { updateInstanceActive } from './slices/instancesSlice'
|
||||
|
||||
const initQuery = async ({
|
||||
instance,
|
||||
prefetch
|
||||
}: {
|
||||
instance: Instance
|
||||
instance: InstanceLatest
|
||||
prefetch?: { enabled: boolean; page?: 'Following' | 'LocalPublic' }
|
||||
}) => {
|
||||
store.dispatch(updateInstanceActive(instance))
|
||||
|
@ -5,6 +5,7 @@ import { InstanceV6 } from './v6'
|
||||
import { InstanceV7 } from './v7'
|
||||
import { InstanceV8 } from './v8'
|
||||
import { InstanceV9 } from './v9'
|
||||
import { InstanceV10 } from './v10'
|
||||
|
||||
const instancesMigration = {
|
||||
4: (state: InstanceV3): InstanceV4 => {
|
||||
@ -99,7 +100,23 @@ const instancesMigration = {
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
10: (state: { instances: InstanceV9[] }): { instances: InstanceV10[] } => {
|
||||
return {
|
||||
instances: state.instances.map(instance => {
|
||||
return {
|
||||
...instance,
|
||||
notifications_filter: {
|
||||
...instance.notifications_filter,
|
||||
status: true,
|
||||
update: true
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { InstanceV10 as InstanceLatest }
|
||||
|
||||
export default instancesMigration
|
||||
|
81
src/utils/migrations/instances/v10.ts
Normal file
81
src/utils/migrations/instances/v10.ts
Normal file
@ -0,0 +1,81 @@
|
||||
import { ComposeStateDraft } from '@screens/Compose/utils/types'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
|
||||
export type InstanceV10 = {
|
||||
active: boolean
|
||||
appData: {
|
||||
clientId: string
|
||||
clientSecret: string
|
||||
}
|
||||
url: string
|
||||
token: string
|
||||
uri: Mastodon.Instance['uri']
|
||||
urls: Mastodon.Instance['urls']
|
||||
account: {
|
||||
id: Mastodon.Account['id']
|
||||
acct: Mastodon.Account['acct']
|
||||
avatarStatic: Mastodon.Account['avatar_static']
|
||||
preferences: Mastodon.Preferences
|
||||
}
|
||||
version: string
|
||||
configuration?: Mastodon.Instance['configuration']
|
||||
filters: Mastodon.Filter[]
|
||||
notifications_filter: {
|
||||
follow: boolean
|
||||
follow_request: boolean
|
||||
favourite: boolean
|
||||
reblog: boolean
|
||||
mention: boolean
|
||||
poll: boolean
|
||||
status: boolean
|
||||
update: boolean
|
||||
}
|
||||
push: {
|
||||
global: { loading: boolean; value: boolean }
|
||||
decode: { loading: boolean; value: boolean }
|
||||
alerts: {
|
||||
follow: {
|
||||
loading: boolean
|
||||
value: Mastodon.PushSubscription['alerts']['follow']
|
||||
}
|
||||
favourite: {
|
||||
loading: boolean
|
||||
value: Mastodon.PushSubscription['alerts']['favourite']
|
||||
}
|
||||
reblog: {
|
||||
loading: boolean
|
||||
value: Mastodon.PushSubscription['alerts']['reblog']
|
||||
}
|
||||
mention: {
|
||||
loading: boolean
|
||||
value: Mastodon.PushSubscription['alerts']['mention']
|
||||
}
|
||||
poll: {
|
||||
loading: boolean
|
||||
value: Mastodon.PushSubscription['alerts']['poll']
|
||||
}
|
||||
}
|
||||
keys: {
|
||||
auth?: string
|
||||
public?: string // legacy
|
||||
private?: string // legacy
|
||||
}
|
||||
}
|
||||
timelinesLookback?: {
|
||||
[key: string]: {
|
||||
queryKey: QueryKeyTimeline
|
||||
ids: Mastodon.Status['id'][]
|
||||
}
|
||||
}
|
||||
mePage: {
|
||||
lists: { shown: boolean }
|
||||
announcements: { shown: boolean; unread: number }
|
||||
}
|
||||
drafts: ComposeStateDraft[]
|
||||
frequentEmojis: {
|
||||
emoji: Pick<Mastodon.Emoji, 'shortcode' | 'url' | 'static_url'>
|
||||
score: number
|
||||
count: number
|
||||
lastUsed: number
|
||||
}[]
|
||||
}
|
@ -4,7 +4,8 @@ import { displayMessage } from '@components/Message'
|
||||
import navigationRef from '@helpers/navigationRef'
|
||||
import { useAppDispatch } from '@root/store'
|
||||
import { isDevelopment } from '@utils/checkEnvironment'
|
||||
import { disableAllPushes, Instance } from '@utils/slices/instancesSlice'
|
||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||
import { disableAllPushes } from '@utils/slices/instancesSlice'
|
||||
import { useTheme } from '@utils/styles/ThemeManager'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import { useEffect } from 'react'
|
||||
@ -12,7 +13,7 @@ import { TFunction } from 'react-i18next'
|
||||
|
||||
export interface Params {
|
||||
t: TFunction<'screens'>
|
||||
instances: Instance[]
|
||||
instances: InstanceLatest[]
|
||||
}
|
||||
|
||||
const pushUseConnect = ({ t, instances }: Params) => {
|
||||
|
@ -1,14 +1,14 @@
|
||||
import { displayMessage } from '@components/Message'
|
||||
import queryClient from '@helpers/queryClient'
|
||||
import initQuery from '@utils/initQuery'
|
||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import { Instance } from '@utils/slices/instancesSlice'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import { useEffect } from 'react'
|
||||
import pushUseNavigate from './useNavigate'
|
||||
|
||||
export interface Params {
|
||||
instances: Instance[]
|
||||
instances: InstanceLatest[]
|
||||
}
|
||||
|
||||
const pushUseReceive = ({ instances }: Params) => {
|
||||
|
@ -1,13 +1,13 @@
|
||||
import queryClient from '@helpers/queryClient'
|
||||
import initQuery from '@utils/initQuery'
|
||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||
import { Instance } from '@utils/slices/instancesSlice'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import { useEffect } from 'react'
|
||||
import pushUseNavigate from './useNavigate'
|
||||
|
||||
export interface Params {
|
||||
instances: Instance[]
|
||||
instances: InstanceLatest[]
|
||||
}
|
||||
|
||||
const pushUseRespond = ({ instances }: Params) => {
|
||||
|
@ -2,7 +2,10 @@ import apiInstance, { InstanceResponse } from '@api/instance'
|
||||
import haptics from '@components/haptics'
|
||||
import queryClient from '@helpers/queryClient'
|
||||
import { store } from '@root/store'
|
||||
import { getInstanceNotificationsFilter } from '@utils/slices/instancesSlice'
|
||||
import {
|
||||
checkInstanceFeature,
|
||||
getInstanceNotificationsFilter
|
||||
} from '@utils/slices/instancesSlice'
|
||||
import { AxiosError } from 'axios'
|
||||
import { uniqBy } from 'lodash'
|
||||
import {
|
||||
@ -62,16 +65,26 @@ const queryFunction = async ({
|
||||
case 'Notifications':
|
||||
const rootStore = store.getState()
|
||||
const notificationsFilter = getInstanceNotificationsFilter(rootStore)
|
||||
const usePositiveFilter = checkInstanceFeature(
|
||||
'notification_types_positive_filter'
|
||||
)(rootStore)
|
||||
return apiInstance<Mastodon.Notification[]>({
|
||||
method: 'get',
|
||||
url: 'notifications',
|
||||
params: {
|
||||
...params,
|
||||
...(notificationsFilter && {
|
||||
exclude_types: Object.keys(notificationsFilter)
|
||||
// @ts-ignore
|
||||
.filter(filter => notificationsFilter[filter] === false)
|
||||
})
|
||||
...(notificationsFilter &&
|
||||
(usePositiveFilter
|
||||
? {
|
||||
types: Object.keys(notificationsFilter)
|
||||
// @ts-ignore
|
||||
.filter(filter => notificationsFilter[filter] === true)
|
||||
}
|
||||
: {
|
||||
exclude_types: Object.keys(notificationsFilter)
|
||||
// @ts-ignore
|
||||
.filter(filter => notificationsFilter[filter] === false)
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import apiGeneral from '@api/general'
|
||||
import { createAsyncThunk } from '@reduxjs/toolkit'
|
||||
import { RootState } from '@root/store'
|
||||
import { Instance } from '../instancesSlice'
|
||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||
|
||||
const addInstance = createAsyncThunk(
|
||||
'instances/add',
|
||||
@ -11,11 +11,11 @@ const addInstance = createAsyncThunk(
|
||||
instance,
|
||||
appData
|
||||
}: {
|
||||
domain: Instance['url']
|
||||
token: Instance['token']
|
||||
domain: InstanceLatest['url']
|
||||
token: InstanceLatest['token']
|
||||
instance: Mastodon.Instance
|
||||
appData: Instance['appData']
|
||||
}): Promise<{ type: 'add' | 'overwrite'; data: Instance }> => {
|
||||
appData: InstanceLatest['appData']
|
||||
}): Promise<{ type: 'add' | 'overwrite'; data: InstanceLatest }> => {
|
||||
const { store } = require('@root/store')
|
||||
const instances = (store.getState() as RootState).instances.instances
|
||||
|
||||
@ -81,11 +81,13 @@ const addInstance = createAsyncThunk(
|
||||
filters,
|
||||
notifications_filter: {
|
||||
follow: true,
|
||||
follow_request: true,
|
||||
favourite: true,
|
||||
reblog: true,
|
||||
mention: true,
|
||||
poll: true,
|
||||
follow_request: true
|
||||
status: true,
|
||||
update: true
|
||||
},
|
||||
push: {
|
||||
global: { loading: false, value: false },
|
||||
|
@ -2,7 +2,8 @@ import apiInstance from '@api/instance'
|
||||
import apiTooot, { TOOOT_API_DOMAIN } from '@api/tooot'
|
||||
import i18n from '@root/i18n/i18n'
|
||||
import { RootState } from '@root/store'
|
||||
import { getInstance, Instance } from '@utils/slices/instancesSlice'
|
||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||
import { getInstance } from '@utils/slices/instancesSlice'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import * as Random from 'expo-random'
|
||||
import { Platform } from 'react-native'
|
||||
@ -34,7 +35,7 @@ const subscribe = async ({
|
||||
const pushRegister = async (
|
||||
state: RootState,
|
||||
expoToken: string
|
||||
): Promise<Instance['push']['keys']['auth']> => {
|
||||
): Promise<InstanceLatest['push']['keys']['auth']> => {
|
||||
const instance = getInstance(state)
|
||||
const instanceUrl = instance?.url
|
||||
const instanceUri = instance?.uri
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { createAsyncThunk } from '@reduxjs/toolkit'
|
||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||
import * as AuthSession from 'expo-auth-session'
|
||||
import { Instance } from '../instancesSlice'
|
||||
import { updateInstancePush } from './updatePush'
|
||||
|
||||
const removeInstance = createAsyncThunk(
|
||||
'instances/remove',
|
||||
async (instance: Instance, { dispatch }): Promise<Instance> => {
|
||||
async (instance: InstanceLatest, { dispatch }): Promise<InstanceLatest> => {
|
||||
if (instance.push.global.value) {
|
||||
dispatch(updateInstancePush(false))
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { createAsyncThunk } from '@reduxjs/toolkit'
|
||||
import { RootState } from '@root/store'
|
||||
import { isDevelopment } from '@utils/checkEnvironment'
|
||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import { Instance } from '../instancesSlice'
|
||||
import pushRegister from './push/register'
|
||||
import pushUnregister from './push/unregister'
|
||||
|
||||
@ -11,7 +11,7 @@ export const updateInstancePush = createAsyncThunk(
|
||||
async (
|
||||
disable: boolean,
|
||||
{ getState }
|
||||
): Promise<Instance['push']['keys']['auth'] | undefined> => {
|
||||
): Promise<InstanceLatest['push']['keys']['auth'] | undefined> => {
|
||||
const state = getState() as RootState
|
||||
const expoToken = isDevelopment
|
||||
? 'DEVELOPMENT_TOKEN_1'
|
||||
|
@ -1,15 +1,15 @@
|
||||
import apiInstance from '@api/instance'
|
||||
import { createAsyncThunk } from '@reduxjs/toolkit'
|
||||
import { Instance } from '../instancesSlice'
|
||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||
|
||||
export const updateInstancePushAlert = createAsyncThunk(
|
||||
'instances/updatePushAlert',
|
||||
async ({
|
||||
alerts
|
||||
}: {
|
||||
changed: keyof Instance['push']['alerts']
|
||||
alerts: Instance['push']['alerts']
|
||||
}): Promise<Instance['push']['alerts']> => {
|
||||
changed: keyof InstanceLatest['push']['alerts']
|
||||
alerts: InstanceLatest['push']['alerts']
|
||||
}): Promise<InstanceLatest['push']['alerts']> => {
|
||||
const formData = new FormData()
|
||||
Object.keys(alerts).map(alert =>
|
||||
// @ts-ignore
|
||||
|
@ -3,9 +3,10 @@ import { createAsyncThunk } from '@reduxjs/toolkit'
|
||||
import i18n from '@root/i18n/i18n'
|
||||
import { RootState } from '@root/store'
|
||||
import { isDevelopment } from '@utils/checkEnvironment'
|
||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||
import * as Notifications from 'expo-notifications'
|
||||
import { Platform } from 'react-native'
|
||||
import { getInstance, Instance } from '../instancesSlice'
|
||||
import { getInstance } from '../instancesSlice'
|
||||
import androidDefaults from './push/androidDefaults'
|
||||
|
||||
export const updateInstancePushDecode = createAsyncThunk(
|
||||
@ -13,7 +14,7 @@ export const updateInstancePushDecode = createAsyncThunk(
|
||||
async (
|
||||
disable: boolean,
|
||||
{ getState }
|
||||
): Promise<{ disable: Instance['push']['decode']['value'] }> => {
|
||||
): Promise<{ disable: InstanceLatest['push']['decode']['value'] }> => {
|
||||
const state = getState() as RootState
|
||||
const instance = getInstance(state)
|
||||
if (!instance?.url || !instance.account.id || !instance.push.keys) {
|
||||
|
@ -3,7 +3,7 @@ import features from '@helpers/features'
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||
import { RootState } from '@root/store'
|
||||
import { ComposeStateDraft } from '@screens/Compose/utils/types'
|
||||
import { InstanceV9 } from '@utils/migrations/instances/v9'
|
||||
import { InstanceLatest } from '@utils/migrations/instances/migration'
|
||||
import addInstance from './instances/add'
|
||||
import { checkEmojis } from './instances/checkEmojis'
|
||||
import removeInstance from './instances/remove'
|
||||
@ -14,24 +14,25 @@ import { updateInstancePush } from './instances/updatePush'
|
||||
import { updateInstancePushAlert } from './instances/updatePushAlert'
|
||||
import { updateInstancePushDecode } from './instances/updatePushDecode'
|
||||
|
||||
export type Instance = InstanceV9
|
||||
|
||||
export type InstancesState = {
|
||||
instances: Instance[]
|
||||
instances: InstanceLatest[]
|
||||
}
|
||||
|
||||
export const instancesInitialState: InstancesState = {
|
||||
instances: []
|
||||
}
|
||||
|
||||
const findInstanceActive = (instances: Instance[]) =>
|
||||
const findInstanceActive = (instances: InstanceLatest[]) =>
|
||||
instances.findIndex(instance => instance.active)
|
||||
|
||||
const instancesSlice = createSlice({
|
||||
name: 'instances',
|
||||
initialState: instancesInitialState,
|
||||
reducers: {
|
||||
updateInstanceActive: ({ instances }, action: PayloadAction<Instance>) => {
|
||||
updateInstanceActive: (
|
||||
{ instances },
|
||||
action: PayloadAction<InstanceLatest>
|
||||
) => {
|
||||
instances = instances.map(instance => {
|
||||
instance.active =
|
||||
instance.url === action.payload.url &&
|
||||
@ -42,7 +43,9 @@ const instancesSlice = createSlice({
|
||||
},
|
||||
updateInstanceAccount: (
|
||||
{ instances },
|
||||
action: PayloadAction<Pick<Instance['account'], 'acct' & 'avatarStatic'>>
|
||||
action: PayloadAction<
|
||||
Pick<InstanceLatest['account'], 'acct' & 'avatarStatic'>
|
||||
>
|
||||
) => {
|
||||
const activeIndex = findInstanceActive(instances)
|
||||
instances[activeIndex].account = {
|
||||
@ -52,7 +55,7 @@ const instancesSlice = createSlice({
|
||||
},
|
||||
updateInstanceNotificationsFilter: (
|
||||
{ instances },
|
||||
action: PayloadAction<Instance['notifications_filter']>
|
||||
action: PayloadAction<InstanceLatest['notifications_filter']>
|
||||
) => {
|
||||
const activeIndex = findInstanceActive(instances)
|
||||
instances[activeIndex].notifications_filter = action.payload
|
||||
@ -99,7 +102,7 @@ const instancesSlice = createSlice({
|
||||
},
|
||||
updateInstanceTimelineLookback: (
|
||||
{ instances },
|
||||
action: PayloadAction<Instance['timelinesLookback']>
|
||||
action: PayloadAction<InstanceLatest['timelinesLookback']>
|
||||
) => {
|
||||
const activeIndex = findInstanceActive(instances)
|
||||
instances[activeIndex] &&
|
||||
@ -110,7 +113,7 @@ const instancesSlice = createSlice({
|
||||
},
|
||||
updateInstanceMePage: (
|
||||
{ instances },
|
||||
action: PayloadAction<Partial<Instance['mePage']>>
|
||||
action: PayloadAction<Partial<InstanceLatest['mePage']>>
|
||||
) => {
|
||||
const activeIndex = findInstanceActive(instances)
|
||||
instances[activeIndex].mePage = {
|
||||
@ -120,10 +123,12 @@ const instancesSlice = createSlice({
|
||||
},
|
||||
countInstanceEmoji: (
|
||||
{ instances },
|
||||
action: PayloadAction<Instance['frequentEmojis'][0]['emoji']>
|
||||
action: PayloadAction<InstanceLatest['frequentEmojis'][0]['emoji']>
|
||||
) => {
|
||||
const HALF_LIFE = 60 * 60 * 24 * 7 // 1 week
|
||||
const calculateScore = (emoji: Instance['frequentEmojis'][0]): number => {
|
||||
const calculateScore = (
|
||||
emoji: InstanceLatest['frequentEmojis'][0]
|
||||
): number => {
|
||||
var seconds = (new Date().getTime() - emoji.lastUsed) / 1000
|
||||
var score = emoji.count + 1
|
||||
var order = Math.log(Math.max(score, 1)) / Math.LN10
|
||||
@ -136,7 +141,7 @@ const instancesSlice = createSlice({
|
||||
e.emoji.shortcode === action.payload.shortcode &&
|
||||
e.emoji.url === action.payload.url
|
||||
)
|
||||
let newEmojisSort: Instance['frequentEmojis']
|
||||
let newEmojisSort: InstanceLatest['frequentEmojis']
|
||||
if (foundEmojiIndex > -1) {
|
||||
newEmojisSort = instances[activeIndex].frequentEmojis
|
||||
.map((e, i) =>
|
||||
|
Reference in New Issue
Block a user