diff --git a/icons/mgc/photo_album_cute_re.svg b/icons/mgc/photo_album_cute_re.svg new file mode 100644 index 0000000000..a385cea648 --- /dev/null +++ b/icons/mgc/photo_album_cute_re.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/locales/app/en.json b/locales/app/en.json index 3a5deadb2a..0176ceae02 100644 --- a/locales/app/en.json +++ b/locales/app/en.json @@ -48,11 +48,13 @@ "entry_content.web_app_notice": "Maybe web app doesn't support this content type. But you can download the desktop app.", "entry_list.zero_unread": "Zero Unread", "entry_list_header.daily_report": "Daily Report", + "entry_list_header.hide_no_image_items": "Hide no images's entry items", "entry_list_header.items": "items", "entry_list_header.new_entries_available": "New entries available", "entry_list_header.refetch": "Refetch", "entry_list_header.refresh": "Refresh", "entry_list_header.show_all": "Show all", + "entry_list_header.show_all_items": "Show all entry items", "entry_list_header.show_unread_only": "Show unread Only", "entry_list_header.switch_to_grid": "Switch to Grid", "entry_list_header.switch_to_masonry": "Switch to Masonry", @@ -109,6 +111,13 @@ "mark_all_read_button.mark_all_as_read": "Mark all as read", "mark_all_read_button.mark_as_read": "Mark {{which}} as read", "mark_all_read_button.undo": "Undo", + "player.back_10s": "Back 10s", + "player.close": "Close", + "player.download": "Download", + "player.forward_10s": "Forward 10s", + "player.open_entry": "Open Entry", + "player.playback_rate": "Playback Rate", + "player.volume": "Volume", "search.empty.no_results": "No results found.", "search.group.entries": "Entries", "search.group.feeds": "Feeds", diff --git a/locales/app/zh-CN.json b/locales/app/zh-CN.json index 651bd0d687..3634579ee3 100644 --- a/locales/app/zh-CN.json +++ b/locales/app/zh-CN.json @@ -38,7 +38,7 @@ "entry_list_header.daily_report": "每日报告", "entry_list_header.items": "内容", "entry_list_header.new_entries_available": "有新内容", - "entry_list_header.refetch": "重新获取", + "entry_list_header.refetch": "刷新", "entry_list_header.refresh": "刷新", "entry_list_header.show_all": "显示全部", "entry_list_header.show_unread_only": "仅显示未读", diff --git a/src/renderer/src/atoms/settings/ui.ts b/src/renderer/src/atoms/settings/ui.ts index 8a14b5d1e7..dd4f7ac0e2 100644 --- a/src/renderer/src/atoms/settings/ui.ts +++ b/src/renderer/src/atoms/settings/ui.ts @@ -30,6 +30,7 @@ export const createDefaultSettings = (): UISettings => ({ // View pictureViewMasonry: true, + pictureViewFilterNoImage: false, // TTS voice: "en-US-AndrewMultilingualNeural", diff --git a/src/renderer/src/modules/entry-column/index.tsx b/src/renderer/src/modules/entry-column/index.tsx index 3e403c08d0..b76e195e15 100644 --- a/src/renderer/src/modules/entry-column/index.tsx +++ b/src/renderer/src/modules/entry-column/index.tsx @@ -15,10 +15,10 @@ import { useTitle, useTypeScriptHappyCallback } from "@renderer/hooks/common" import { FeedViewType } from "@renderer/lib/enum" import { cn, isBizId } from "@renderer/lib/utils" import { useFeed } from "@renderer/queries/feed" -import { entryActions, useEntry } from "@renderer/store/entry" +import { entryActions, getEntry, useEntry } from "@renderer/store/entry" import { useFeedByIdSelector } from "@renderer/store/feed" import { useSubscriptionByFeedId } from "@renderer/store/subscription" -import { memo, useCallback, useEffect, useRef, useState } from "react" +import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react" import { useTranslation } from "react-i18next" import type { ScrollSeekConfiguration, @@ -238,17 +238,34 @@ const ListGird = ({ const masonry = useUISettingKey("pictureViewMasonry") const view = useRouteParamsSelector((s) => s.view) const feedId = useRouteParamsSelector((s) => s.feedId) + const filterNoImage = useUISettingKey("pictureViewFilterNoImage") + const nextData = useMemo(() => { + if (filterNoImage) { + return virtuosoOptions.data.filter((entryId) => { + const entry = getEntry(entryId) + return entry?.entries.media?.length && entry.entries.media.length > 0 + }) + } + return virtuosoOptions.data + }, [virtuosoOptions.data, filterNoImage]) if (masonry && view === FeedViewType.Pictures) { return ( virtuosoOptions.data.length} endReached={virtuosoOptions.endReached} - data={virtuosoOptions.data} + data={nextData} /> ) } - return + return ( + + ) } const AddFeedHelper = () => { diff --git a/src/renderer/src/modules/entry-column/layouts/EntryListHeader.tsx b/src/renderer/src/modules/entry-column/layouts/EntryListHeader.tsx index d486e657bf..94ba8a12d8 100644 --- a/src/renderer/src/modules/entry-column/layouts/EntryListHeader.tsx +++ b/src/renderer/src/modules/entry-column/layouts/EntryListHeader.tsx @@ -96,6 +96,7 @@ export const EntryListHeader: FC<{ {view === FeedViewType.SocialMedia && } {view === FeedViewType.Pictures && } + {view === FeedViewType.Pictures && } {isOnline ? ( @@ -173,6 +174,25 @@ const DailyReportButton: FC = () => { ) } +const FilterNoImageButton = () => { + const enabled = useUISettingKey("pictureViewFilterNoImage") + const { t } = useTranslation() + + return ( + { + setUISetting("pictureViewFilterNoImage", !enabled) + }} + tooltip={t( + enabled ? "entry_list_header.show_all_items" : "entry_list_header.hide_no_image_items", + )} + > + + + ) +} + const SwitchToMasonryButton = () => { const isMasonry = useUISettingKey("pictureViewMasonry") const { t } = useTranslation() @@ -193,7 +213,7 @@ const SwitchToMasonryButton = () => { }) }} tooltip={ - isMasonry + !isMasonry ? t("entry_list_header.switch_to_masonry") : t("entry_list_header.switch_to_grid") } diff --git a/src/renderer/src/modules/feed-column/corner-player.tsx b/src/renderer/src/modules/feed-column/corner-player.tsx index 11631e17f8..e547457d62 100644 --- a/src/renderer/src/modules/feed-column/corner-player.tsx +++ b/src/renderer/src/modules/feed-column/corner-player.tsx @@ -21,6 +21,7 @@ import { AnimatePresence, m } from "framer-motion" import { useEffect, useState } from "react" import Marquee from "react-fast-marquee" import { useHotkeys } from "react-hotkeys-hook" +import { useTranslation } from "react-i18next" const handleClickPlay = () => { AudioPlayer.togglePlayAndPause() @@ -85,6 +86,7 @@ const usePlayerTracker = () => { }, [show]) } const CornerPlayerImpl = () => { + const { t } = useTranslation() const entryId = useAudioPlayerAtomSelector((v) => v.entryId) const status = useAudioPlayerAtomSelector((v) => v.status) const isMute = useAudioPlayerAtomSelector((v) => v.isMute) @@ -156,7 +158,7 @@ const CornerPlayerImpl = () => { AudioPlayer.close()} - label="Close" + label={t("player.close")} /> { view: FeedViewType.Audios, }) } - label="Open Entry" + label={t("player.open_entry")} />
{ window.open(AudioPlayer.get().src, "_blank") }} @@ -193,12 +195,12 @@ const CornerPlayerImpl = () => { AudioPlayer.back(10)} - label="Back 10s" + label={t("player.back_10s")} /> AudioPlayer.forward(10)} - label="Forward 10s" + label={t("player.forward_10s")} tooltipAlign="end" />
diff --git a/src/shared/src/interface/settings.ts b/src/shared/src/interface/settings.ts index fff15fb4d7..567a12ddf1 100644 --- a/src/shared/src/interface/settings.ts +++ b/src/shared/src/interface/settings.ts @@ -30,6 +30,7 @@ export interface UISettings { // view pictureViewMasonry: boolean + pictureViewFilterNoImage: boolean // tts voice: string