Skip to content

Commit 5cde692

Browse files
kovsuhyoban
andauthored
refactor(desktop): move electron actions to entry actions (#3483)
Co-authored-by: Stephen Zhou <[email protected]>
1 parent ecf1c0f commit 5cde692

File tree

9 files changed

+135
-170
lines changed

9 files changed

+135
-170
lines changed

apps/desktop/src/renderer/src/hooks/biz/useEntryActions.tsx

Lines changed: 63 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
import { isMobile } from "@follow/components/hooks/useMobile.js"
2-
import { FeedViewType, UserRole } from "@follow/constants"
2+
import { FeedViewType, UserRole, views } from "@follow/constants"
33
import { IN_ELECTRON } from "@follow/shared/constants"
4-
import { useCallback, useMemo } from "react"
4+
import { useMemo } from "react"
55

66
import { useShowAISummaryAuto, useShowAISummaryOnce } from "~/atoms/ai-summary"
77
import { useShowAITranslationAuto, useShowAITranslationOnce } from "~/atoms/ai-translation"
88
import {
99
getReadabilityStatus,
10+
isInReadability,
1011
ReadabilityStatus,
1112
setReadabilityContent,
1213
setReadabilityStatus,
14+
useEntryInReadabilityStatus,
1315
} from "~/atoms/readability"
1416
import { useShowSourceContent } from "~/atoms/source-content"
1517
import { useUserRole, whoami } from "~/atoms/user"
@@ -25,41 +27,40 @@ import { useInboxById } from "~/store/inbox"
2527

2628
import { useRouteParamsSelector } from "./useRouteParams"
2729

28-
export const useEntryReadabilityToggle = ({ id, url }: { id: string; url: string }) =>
29-
useCallback(async () => {
30-
const status = getReadabilityStatus()[id]
31-
const isTurnOn = status !== ReadabilityStatus.INITIAL && !!status
30+
export const toggleEntryReadability = async ({ id, url }: { id: string; url: string }) => {
31+
const status = getReadabilityStatus()[id]
32+
const isTurnOn = status !== ReadabilityStatus.INITIAL && !!status
3233

33-
if (!isTurnOn && url) {
34-
setReadabilityStatus({
35-
[id]: ReadabilityStatus.WAITING,
34+
if (!isTurnOn && url) {
35+
setReadabilityStatus({
36+
[id]: ReadabilityStatus.WAITING,
37+
})
38+
const result = await tipcClient
39+
?.readability({
40+
url,
3641
})
37-
const result = await tipcClient
38-
?.readability({
39-
url,
40-
})
41-
.catch(() => {
42-
setReadabilityStatus({
43-
[id]: ReadabilityStatus.FAILURE,
44-
})
45-
})
46-
47-
if (result) {
48-
const status = getReadabilityStatus()[id]
49-
if (status !== ReadabilityStatus.WAITING) return
42+
.catch(() => {
5043
setReadabilityStatus({
51-
[id]: ReadabilityStatus.SUCCESS,
52-
})
53-
setReadabilityContent({
54-
[id]: result,
44+
[id]: ReadabilityStatus.FAILURE,
5545
})
56-
}
57-
} else {
46+
})
47+
48+
if (result) {
49+
const status = getReadabilityStatus()[id]
50+
if (status !== ReadabilityStatus.WAITING) return
5851
setReadabilityStatus({
59-
[id]: ReadabilityStatus.INITIAL,
52+
[id]: ReadabilityStatus.SUCCESS,
53+
})
54+
setReadabilityContent({
55+
[id]: result,
6056
})
6157
}
62-
}, [id, url])
58+
} else {
59+
setReadabilityStatus({
60+
[id]: ReadabilityStatus.INITIAL,
61+
})
62+
}
63+
}
6364

6465
export type EntryActionItem = {
6566
id: FollowCommandId
@@ -70,8 +71,17 @@ export type EntryActionItem = {
7071
disabled?: boolean
7172
}
7273

73-
export const useEntryActions = ({ entryId, view }: { entryId: string; view?: FeedViewType }) => {
74+
export const useEntryActions = ({
75+
entryId,
76+
view,
77+
compact,
78+
}: {
79+
entryId: string
80+
view?: FeedViewType
81+
compact?: boolean
82+
}) => {
7483
const entry = useEntry(entryId)
84+
const entryReadabilityStatus = useEntryInReadabilityStatus(entry?.entries.id)
7585
const imageLength = entry?.entries.media?.filter((a) => a.type === "photo").length || 0
7686
const feed = useFeedById(entry?.feedId, (feed) => {
7787
return {
@@ -208,17 +218,36 @@ export const useEntryActions = ({ entryId, view }: { entryId: string; view?: Fee
208218
active: !!entry?.read,
209219
shortcut: shortcuts.entry.toggleRead.key,
210220
},
221+
{
222+
id: COMMAND_ID.entry.tts,
223+
onClick: runCmdFn(COMMAND_ID.entry.tts, [
224+
{ entryId, entryContent: entry?.entries.content },
225+
]),
226+
hide: !IN_ELECTRON || compact || !entry?.entries.content,
227+
shortcut: shortcuts.entry.tts.key,
228+
},
229+
{
230+
id: COMMAND_ID.entry.readability,
231+
onClick: runCmdFn(COMMAND_ID.entry.readability, [
232+
{ entryId, entryUrl: entry?.entries.url },
233+
]),
234+
hide: !IN_ELECTRON || compact || (view && views[view]!.wideMode) || !entry?.entries.url,
235+
active: isInReadability(entryReadabilityStatus),
236+
},
211237
{
212238
id: COMMAND_ID.settings.customizeToolbar,
213239
onClick: runCmdFn(COMMAND_ID.settings.customizeToolbar, []),
214240
},
215241
].filter((config) => !config.hide)
216242
}, [
243+
compact,
217244
entry?.collections,
245+
entry?.entries.content,
218246
entry?.entries.url,
219247
entry?.read,
220248
entry?.view,
221249
entryId,
250+
entryReadabilityStatus,
222251
feed?.id,
223252
feed?.ownerUserId,
224253
hasEntry,
@@ -241,11 +270,13 @@ export const useEntryActions = ({ entryId, view }: { entryId: string; view?: Fee
241270
export const useSortedEntryActions = ({
242271
entryId,
243272
view,
273+
compact,
244274
}: {
245275
entryId: string
246276
view?: FeedViewType
277+
compact?: boolean
247278
}) => {
248-
const entryActions = useEntryActions({ entryId, view })
279+
const entryActions = useEntryActions({ entryId, view, compact })
249280
const orderMap = useToolbarOrderMap()
250281
const mainAction = useMemo(
251282
() =>

apps/desktop/src/renderer/src/modules/command/commands/entry.tsx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,19 @@ import { toast } from "sonner"
77

88
import { toggleShowAISummaryOnce } from "~/atoms/ai-summary"
99
import { toggleShowAITranslationOnce } from "~/atoms/ai-translation"
10+
import { AudioPlayer, getAudioPlayerAtomValue } from "~/atoms/player"
11+
import { useGeneralSettingKey } from "~/atoms/settings/general"
1012
import {
1113
getShowSourceContent,
1214
toggleShowSourceContent,
1315
useSourceContentModal,
1416
} from "~/atoms/source-content"
1517
import { useUserRole } from "~/atoms/user"
18+
import { toggleEntryReadability } from "~/hooks/biz/useEntryActions"
1619
import { navigateEntry } from "~/hooks/biz/useNavigateEntry"
1720
import { getRouteParams } from "~/hooks/biz/useRouteParams"
1821
import { tipcClient } from "~/lib/client"
22+
import { parseHtml } from "~/lib/parse-html"
1923
import { useActivationModal } from "~/modules/activation"
2024
import { useGalleryModal } from "~/modules/entry-content/hooks"
2125
import { useTipModal } from "~/modules/wallet/hooks"
@@ -100,6 +104,8 @@ export const useRegisterEntryCommands = () => {
100104
const role = useUserRole()
101105
const presentActivationModal = useActivationModal()
102106

107+
const voice = useGeneralSettingKey("voice")
108+
103109
useRegisterFollowCommand([
104110
{
105111
id: COMMAND_ID.entry.tip,
@@ -313,6 +319,43 @@ export const useRegisterEntryCommands = () => {
313319
openGalleryModal(entryId)
314320
},
315321
},
322+
{
323+
id: COMMAND_ID.entry.tts,
324+
label: t("entry_content.header.play_tts"),
325+
icon: <i className="i-mgc-voice-cute-re" />,
326+
run: async ({ entryId, entryContent }) => {
327+
if (getAudioPlayerAtomValue().entryId === entryId) {
328+
AudioPlayer.togglePlayAndPause()
329+
} else {
330+
const filePath = await tipcClient?.tts({
331+
id: entryId,
332+
text: parseHtml(entryContent).toText(),
333+
voice,
334+
})
335+
if (filePath) {
336+
AudioPlayer.mount({
337+
type: "audio",
338+
entryId,
339+
src: `file://${filePath}`,
340+
currentTime: 0,
341+
})
342+
}
343+
}
344+
},
345+
},
346+
{
347+
id: COMMAND_ID.entry.readability,
348+
label: t("entry_content.header.readability"),
349+
icon: (props) => (
350+
<i className={props?.isActive ? "i-mgc-docment-cute-fi" : "i-mgc-docment-cute-re"} />
351+
),
352+
run: async ({ entryId, entryUrl }) => {
353+
return toggleEntryReadability({
354+
id: entryId,
355+
url: entryUrl,
356+
})
357+
},
358+
},
316359
])
317360

318361
useRegisterFollowCommand(

apps/desktop/src/renderer/src/modules/command/commands/id.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export const COMMAND_ID = {
1313
toggleAITranslation: "entry:toggle-ai-translation",
1414
exportAsPDF: "entry:export-as-pdf",
1515
imageGallery: "entry:image-gallery",
16+
tts: "entry:tts",
17+
readability: "entry:ability",
1618
},
1719
integration: {
1820
saveToEagle: "integration:save-to-eagle",

apps/desktop/src/renderer/src/modules/command/commands/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,16 @@ export type ImageGalleryCommand = Command<{
7070
fn: ({ entryId }) => void
7171
}>
7272

73+
export type TTSCommand = Command<{
74+
id: typeof COMMAND_ID.entry.tts
75+
fn: ({ entryId, entryContent }) => void
76+
}>
77+
78+
export type ReadabilityCommand = Command<{
79+
id: typeof COMMAND_ID.entry.readability
80+
fn: ({ entryId, entryUrl }) => void
81+
}>
82+
7383
export type EntryCommand =
7484
| TipCommand
7585
| StarCommand
@@ -84,6 +94,8 @@ export type EntryCommand =
8494
| ToggleAISummaryCommand
8595
| ToggleAITranslationCommand
8696
| ImageGalleryCommand
97+
| TTSCommand
98+
| ReadabilityCommand
8799

88100
// Settings commands
89101

apps/desktop/src/renderer/src/modules/entry-content/actions/electron-actions.tsx

Lines changed: 0 additions & 125 deletions
This file was deleted.

0 commit comments

Comments
 (0)