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