1
0
mirror of https://github.com/tooot-app/app synced 2025-06-05 22:19:13 +02:00

Added frequent used emojis

This commit is contained in:
Zhiyuan Zheng
2022-02-13 22:14:16 +01:00
parent 5ab988585b
commit 9e4189c522
21 changed files with 265 additions and 12 deletions

View File

@ -3,6 +3,7 @@ import { InstanceV4 } from './v4'
import { InstanceV5 } from './v5'
import { InstanceV6 } from './v6'
import { InstanceV7 } from './v7'
import { InstanceV8 } from './v8'
const instancesMigration = {
4: (state: InstanceV3): InstanceV4 => {
@ -76,6 +77,16 @@ const instancesMigration = {
}
})
}
},
8: (state: InstanceV7): InstanceV8 => {
return {
instances: state.instances.map(instance => {
return {
...instance,
frequentEmojis: []
}
})
}
}
}

View File

@ -0,0 +1,83 @@
import { ComposeStateDraft } from '@screens/Compose/utils/types'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
type Instance = {
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
}
max_toot_chars?: number // To be deprecated in v4
configuration?: Mastodon.Instance['configuration']
filters: Mastodon.Filter[]
notifications_filter: {
follow: boolean
favourite: boolean
reblog: boolean
mention: boolean
poll: boolean
follow_request: 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: Date
}[]
}
export type InstanceV8 = {
instances: Instance[]
}

View File

@ -0,0 +1,15 @@
import apiInstance from '@api/instance'
import queryClient from '@helpers/queryClient'
import { createAsyncThunk } from '@reduxjs/toolkit'
export const checkEmojis = createAsyncThunk(
'instances/checkEmojis',
async (): Promise<Mastodon.Emoji[]> => {
const res = await apiInstance<Mastodon.Emoji[]>({
method: 'get',
url: 'custom_emojis'
}).then(res => res.body)
queryClient.setQueryData(['Emojis'], res)
return res
}
)

View File

@ -4,6 +4,7 @@ import { RootState } from '@root/store'
import { ComposeStateDraft } from '@screens/Compose/utils/types'
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
import addInstance from './instances/add'
import { checkEmojis } from './instances/checkEmojis'
import removeInstance from './instances/remove'
import { updateAccountPreferences } from './instances/updateAccountPreferences'
import { updateConfiguration } from './instances/updateConfiguration'
@ -81,6 +82,12 @@ export type Instance = {
announcements: { shown: boolean; unread: number }
}
drafts: ComposeStateDraft[]
frequentEmojis: {
emoji: Pick<Mastodon.Emoji, 'shortcode' | 'url' | 'static_url'>
score: number
count: number
lastUsed: number
}[]
}
export type InstancesState = {
@ -184,6 +191,56 @@ const instancesSlice = createSlice({
...instances[activeIndex].mePage,
...action.payload
}
},
countInstanceEmoji: (
{ instances },
action: PayloadAction<Instance['frequentEmojis'][0]['emoji']>
) => {
const HALF_LIFE = 60 * 60 * 24 * 7 // 1 week
const calculateScore = (emoji: Instance['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
var sign = score > 0 ? 1 : score === 0 ? 0 : -1
return (sign * order + seconds / HALF_LIFE) * 10
}
const activeIndex = findInstanceActive(instances)
const foundEmojiIndex = instances[activeIndex].frequentEmojis?.findIndex(
e =>
e.emoji.shortcode === action.payload.shortcode &&
e.emoji.url === action.payload.url
)
let newEmojisSort: Instance['frequentEmojis']
if (foundEmojiIndex > -1) {
newEmojisSort = instances[activeIndex].frequentEmojis
.map((e, i) =>
i === foundEmojiIndex
? {
...e,
score: calculateScore(e),
count: e.count + 1,
lastUsed: new Date().getTime()
}
: e
)
.sort((a, b) => b.score - a.score)
} else {
newEmojisSort = instances[activeIndex].frequentEmojis || []
const temp = {
emoji: action.payload,
score: 0,
count: 0,
lastUsed: new Date().getTime()
}
newEmojisSort.push({
...temp,
score: calculateScore(temp),
count: temp.count + 1
})
}
instances[activeIndex].frequentEmojis = newEmojisSort
.sort((a, b) => b.score - a.score)
.slice(0, 20)
}
},
extraReducers: builder => {
@ -321,6 +378,22 @@ const instancesSlice = createSlice({
action.meta.arg.changed
].loading = true
})
// Check if frequently used emojis still exist
.addCase(checkEmojis.fulfilled, (state, action) => {
const activeIndex = findInstanceActive(state.instances)
state.instances[activeIndex].frequentEmojis = state.instances[
activeIndex
].frequentEmojis?.filter(emoji => {
return action.payload.find(
e =>
e.shortcode === emoji.emoji.shortcode && e.url === emoji.emoji.url
)
})
})
.addCase(checkEmojis.rejected, (_, action) => {
console.error(action.error)
})
}
})
@ -394,6 +467,10 @@ export const getInstanceMePage = ({ instances: { instances } }: RootState) =>
export const getInstanceDrafts = ({ instances: { instances } }: RootState) =>
instances[findInstanceActive(instances)]?.drafts
export const getInstanceFrequentEmojis = ({
instances: { instances }
}: RootState) => instances[findInstanceActive(instances)]?.frequentEmojis
export const {
updateInstanceActive,
updateInstanceAccount,
@ -403,7 +480,8 @@ export const {
clearPushLoading,
disableAllPushes,
updateInstanceTimelineLookback,
updateInstanceMePage
updateInstanceMePage,
countInstanceEmoji
} = instancesSlice.actions
export default instancesSlice.reducer