Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 1 addition & 31 deletions apps/desktop/changelog/0.6.0.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,3 @@
# What's New in v0.6.0

## Shiny New Things

- Import and export your Actions (394d00f)
- Add a bio, website, and social links to your profile (507a525)
- Upload a profile picture
- Use video duration as an Action condition

## Improvements

- A snazzy new look for your personal profile
- Redesigned the Actions page (1ace5ea)
- Redesigned the RSSHub page (f9aca60)
- Added length limits to certain profile fields
- Simplified default commands in the entry tool (85122fb)
- Enhanced UI labels and descriptions for clarity (2ed9f70)
- Gradually rolling out an experimental unified local database for mobile and desktop (#3897 #3902)
- Polished image-preview styling (cf72753)
- Refined toast notifications (73f8011)

## No Longer Broken

- More reliable automatic recovery after database-migration failures (c2e0c3d)
- Fixed unread counts not clearing in the macOS Docker build (70255af)
- Fixed old entries showing during initial load (24ae065)
- Fixed handling of links starting with `.` (de8eac8)
- Fixed text-to-speech not working (82952b0)
- Fixed star/unstar status not syncing across devices (fbd0b3)

## Thanks

Special thanks to volunteer contributors @kovsu @huanfe1 @cscnk52 @Olexandr88 @0-o0 @kingsword09 @ericyzhu for their valuable contributions
This version has been withdrawn.
33 changes: 33 additions & 0 deletions apps/desktop/changelog/0.6.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# What's New in v0.6.1

## Shiny New Things

- Import and export your Actions (394d00f)
- Add a bio, website, and social links to your profile (507a525)
- Upload a profile picture
- Use video duration as an Action condition

## Improvements

- A snazzy new look for your personal profile
- Redesigned the Actions page (1ace5ea)
- Redesigned the RSSHub page (f9aca60)
- Added length limits to certain profile fields
- Simplified default commands in the entry tool (85122fb)
- Enhanced UI labels and descriptions for clarity (2ed9f70)
- Gradually rolling out an experimental unified local database for mobile and desktop (#3897 #3902)
- Polished image-preview styling (cf72753)
- Refined toast notifications (73f8011)

## No Longer Broken

- More reliable automatic recovery after database-migration failures (c2e0c3d)
- Fixed unread counts not clearing in the macOS Docker build (70255af)
- Fixed old entries showing during initial load (24ae065)
- Fixed handling of links starting with `.` (de8eac8)
- Fixed text-to-speech not working (82952b0)
- Fixed star/unstar status not syncing across devices (fbd0b3)

## Thanks

Special thanks to volunteer contributors @kovsu @huanfe1 @cscnk52 @Olexandr88 @0-o0 @kingsword09 @ericyzhu for their valuable contributions
3 changes: 2 additions & 1 deletion apps/desktop/configs/vite.electron-render.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { dirname, resolve } from "node:path"
import { dirname } from "node:path"
import { resolve } from "node:path/posix"
import { fileURLToPath } from "node:url"

import { tsImport } from "tsx/esm/api"
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/forge.config.cts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
win32: "latest.yml",
}

const keepModules = new Set(["font-list", "vscode-languagedetection", "fast-folder-size"])
const keepModules = new Set(["font-list", "vscode-languagedetection"])
const keepLanguages = new Set(["en", "en_GB", "en-US", "en_US"])

// remove folders & files not to be included in the app
Expand Down Expand Up @@ -260,7 +260,7 @@
files: [],
}
let basePath = ""
makeResults = makeResults.map((result) => {

Check warning on line 263 in apps/desktop/forge.config.cts

View workflow job for this annotation

GitHub Actions / Format, Lint and Typecheck (lts/*)

Assignment to function parameter 'makeResults'

Check warning on line 263 in apps/desktop/forge.config.cts

View workflow job for this annotation

GitHub Actions / auto-fix

Assignment to function parameter 'makeResults'
result.artifacts = result.artifacts.map((artifact) => {
if (artifactRegex.test(artifact)) {
if (!basePath) {
Expand Down
1 change: 0 additions & 1 deletion apps/desktop/layer/main/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
"electron-store": "10.1.0",
"electron-updater": "6.6.2",
"es-toolkit": "1.39.3",
"fast-folder-size": "2.4.0",
"font-list": "1.5.1",
"i18next": "25.2.1",
"js-yaml": "4.1.0",
Expand Down
76 changes: 74 additions & 2 deletions apps/desktop/layer/main/src/ipc/services/app.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import fsp from "node:fs/promises"
import path from "node:path"
import { fileURLToPath } from "node:url"

import { callWindowExpose } from "@follow/shared/bridge"
import { DEV } from "@follow/shared/constants"
import { app, BrowserWindow, clipboard, dialog } from "electron"
import { app, BrowserWindow, clipboard, dialog, shell } from "electron"

import { getCacheSize } from "~/lib/cleaner"
import { i18n } from "~/lib/i18n"
import { store, StoreKey } from "~/lib/store"
import { registerAppTray } from "~/lib/tray"
import { logger } from "~/logger"
import { logger, revealLogFile } from "~/logger"
import { AppManager } from "~/manager/app"
import { WindowManager } from "~/manager/window"
import { cleanupOldRender, loadDynamicRenderEntry } from "~/updater/hot-updater"
Expand Down Expand Up @@ -170,7 +173,7 @@
@IpcMethod()
resolveAppAsarPath(context: IpcContext, input: string): string {
if (input.startsWith("file://")) {
input = fileURLToPath(input)

Check warning on line 176 in apps/desktop/layer/main/src/ipc/services/app.ts

View workflow job for this annotation

GitHub Actions / Format, Lint and Typecheck (lts/*)

Assignment to function parameter 'input'

Check warning on line 176 in apps/desktop/layer/main/src/ipc/services/app.ts

View workflow job for this annotation

GitHub Actions / auto-fix

Assignment to function parameter 'input'
}

if (path.isAbsolute(input)) {
Expand All @@ -179,4 +182,73 @@

return path.join(app.getAppPath(), input)
}

@IpcMethod()
openCacheFolder(_context: IpcContext): void {
const dir = path.join(app.getPath("userData"), "cache")
shell.openPath(dir)
}

@IpcMethod()
getCacheLimit(_context: IpcContext): number {
return store.get(StoreKey.CacheSizeLimit) || 0
}

@IpcMethod()
async clearCache(_context: IpcContext): Promise<void> {
const cachePath = path.join(app.getPath("userData"), "cache", "Cache_Data")
if (process.platform === "win32") {
// Request elevation on Windows

try {
// Create a bat file to delete cache with elevated privileges
const batPath = path.join(app.getPath("temp"), "clear_cache.bat")
await fsp.writeFile(batPath, `@echo off\nrd /s /q "${cachePath}"\ndel "%~f0"`, "utf-8")

// Execute the bat file with admin privileges
await shell.openPath(batPath)
return
} catch (err) {
logger.error("Failed to clear cache with elevation", { error: err })
}
}
await fsp.rm(cachePath, { recursive: true, force: true }).catch(() => {
logger.error("Failed to clear cache")
})
}

// getCacheLimit: t.procedure.action(async () => {
// return store.get(StoreKey.CacheSizeLimit)
// }),

// clearCache: t.procedure.action(async () => {

// }),

// limitCacheSize: t.procedure.input<number>().action(async ({ input }) => {
// logger.info("set limitCacheSize", input)
// if (input === 0) {
// store.delete(StoreKey.CacheSizeLimit)
// } else {
// store.set(StoreKey.CacheSizeLimit, input)
// }
// }),
@IpcMethod()
limitCacheSize(_context: IpcContext, input: number): void {
if (input === 0) {
store.delete(StoreKey.CacheSizeLimit)
} else {
store.set(StoreKey.CacheSizeLimit, input)
}
}

@IpcMethod()
revealLogFile(_context: IpcContext) {
return revealLogFile()
}

@IpcMethod()
getCacheSize(_context: IpcContext) {
return getCacheSize()
}
}
44 changes: 33 additions & 11 deletions apps/desktop/layer/main/src/lib/cleaner.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { statSync } from "node:fs"
import fsp from "node:fs/promises"
import { createRequire } from "node:module"
import path from "node:path"
import { promisify } from "node:util"

import { callWindowExpose } from "@follow/shared/bridge"
import { app, dialog } from "electron"
Expand All @@ -14,13 +12,37 @@ import { WindowManager } from "~/manager/window"
import { t } from "./i18n"
import { store, StoreKey } from "./store"

const esModuleInterop = (module: any) => {
return module.default || module
const getFolderSize = async (dir: string): Promise<number> => {
try {
const files = await fsp.readdir(dir, { withFileTypes: true })
const sizes = await Promise.all(
files.map(async (file) => {
const filePath = path.join(dir, file.name)

if (file.isSymbolicLink()) {
return 0
}

if (file.isDirectory()) {
return await getFolderSize(filePath)
}

if (file.isFile()) {
try {
const { size } = await fsp.stat(filePath)
return size
} catch {
return 0
}
}
return 0
}),
)
return sizes.reduce((acc, size) => acc + size, 0)
} catch {
return 0
}
}
const require = createRequire(import.meta.url)
const fastFolderSize = esModuleInterop(
require("fast-folder-size"),
) as typeof import("fast-folder-size").default

export const clearAllDataAndConfirm = async () => {
const win = WindowManager.getMainWindow()
Expand Down Expand Up @@ -71,12 +93,12 @@ export const clearAllData = async () => {
caller.toast.error(`Error resetting app data: ${error.message}`)
}
}
const fastFolderSizeAsync = promisify(fastFolderSize)

export const getCacheSize = async () => {
const cachePath = path.join(app.getPath("userData"), "cache")

// Size is in bytes
const sizeInBytes = await fastFolderSizeAsync(cachePath).catch((error) => {
const sizeInBytes = await getFolderSize(cachePath).catch((error) => {
logger.error(error)
})
return sizeInBytes || 0
Expand Down Expand Up @@ -155,7 +177,7 @@ export const clearCacheCronJob = () => {
export const checkAndCleanCodeCache = async () => {
const cachePath = path.join(app.getPath("userData"), "Code Cache")

const size = await fastFolderSizeAsync(cachePath).catch((error) => {
const size = await getFolderSize(cachePath).catch((error) => {
logger.error(error)
})

Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/layer/main/src/manager/window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ class WindowManagerStatic {
webviewTag: true,
webSecurity: !DEV,
nodeIntegration: true,
contextIsolation: true,
contextIsolation: false,
},
...this.getPlatformSpecificWindowConfig(),
}
Expand Down
5 changes: 1 addition & 4 deletions apps/desktop/layer/renderer/src/initialize/analytics.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import type { AuthSession } from "@follow/shared/hono"
import { setFirebaseTracker, setOpenPanelTracker, tracker } from "@follow/tracker"
import { setFirebaseTracker, tracker } from "@follow/tracker"

import { QUERY_PERSIST_KEY } from "~/constants/app"

import { ga4 } from "./ga4"
import { op } from "./op"

export const initAnalytics = async () => {
tracker.manager.appendUserProperties({
Expand All @@ -16,8 +15,6 @@ export const initAnalytics = async () => {

setFirebaseTracker(ga4)

setOpenPanelTracker(op)

let session: AuthSession | undefined
try {
const queryData = JSON.parse(window.localStorage.getItem(QUERY_PERSIST_KEY) ?? "{}")
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/layer/renderer/src/lib/load-language.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export const loadLanguageAndApply = async (lang: string) => {
}
EventBus.dispatch("I18N_UPDATE", "")
} else {
if (ELECTRON) return
let importFilePath = ""

if (IN_ELECTRON) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ export const SettingDataControl = () => {
description: t("general.log_file.description"),
buttonText: t("general.log_file.button"),
action: () => {
;(ipcServices as any)?.revealLogFile?.()
ipcServices?.app.revealLogFile?.()
},
},
]}
Expand Down Expand Up @@ -244,7 +244,7 @@ const CleanElectronCache = () => {
{t("data_control.clean_cache.button")}
<MotionButtonBase
onClick={() => {
;(ipcServices as any)?.openCacheFolder?.()
ipcServices?.app.openCacheFolder?.()
}}
className="center flex"
>
Expand All @@ -253,7 +253,7 @@ const CleanElectronCache = () => {
</span>
}
action={async () => {
await (ipcServices as any)?.clearCache?.()
await ipcServices?.app.clearCache?.()
queryClient.setQueryData(["app", "cache", "size"], 0)
}}
buttonText={t("data_control.clean_cache.button")}
Expand All @@ -267,7 +267,7 @@ const AppCacheLimit = () => {
const { data: cacheSize, isLoading: isLoadingCacheSize } = useQuery({
queryKey: ["app", "cache", "size"],
queryFn: async () => {
const byteSize = (await (ipcServices as any)?.getCacheSize?.()) ?? 0
const byteSize = (await ipcServices?.app.getCacheSize?.()) ?? 0
return Math.round(byteSize / 1024 / 1024)
},
refetchOnMount: "always",
Expand All @@ -279,13 +279,13 @@ const AppCacheLimit = () => {
} = useQuery({
queryKey: ["app", "cache", "limit"],
queryFn: async () => {
const size = (await (ipcServices as any)?.getCacheLimit?.()) ?? 0
const size = (await ipcServices?.app.getCacheLimit?.()) ?? 0
return size
},
})

const onChange = (value: number[]) => {
;(ipcServices as any)?.limitCacheSize?.(value[0]!)
ipcServices?.app.limitCacheSize?.(value[0]!)
refetchCacheLimit()
}

Expand All @@ -294,7 +294,7 @@ const AppCacheLimit = () => {
const InfinitySymbol = <CarbonInfinitySymbol />
return (
<SettingItemGroup>
<div className={"mb-3 flex items-center justify-between gap-4"}>
<div className={"mb-3 mt-4 flex items-center justify-between gap-4"}>
<Label className="center flex">
{t("data_control.app_cache_limit.label")}

Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Folo",
"type": "module",
"version": "0.6.0",
"version": "0.6.1",
"private": true,
"description": "Follow everything in one place",
"author": "Folo Team",
Expand Down
2 changes: 1 addition & 1 deletion locales/settings/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@
"appearance.zen_mode.description": "禅定模式是一种不受干扰的阅读模式,让你能够专注于内容而不受任何干扰。启用禅定模式将会隐藏侧边栏。",
"appearance.zen_mode.description_simple": "不受干扰的阅读模式(隐藏侧边栏)",
"appearance.zen_mode.label": "禅定模式",
"common.give_star": "<HeartIcon />喜欢我们的产品吗? <Link>在 GitHub 上给我们「标星」吧!</Link>",
"common.give_star": "<HeartIcon />喜欢我们的产品吗? <Link>在 GitHub 上给我们「Star」吧!</Link>",
"customizeToolbar.more_actions.description": "将显示在下拉菜单中",
"customizeToolbar.more_actions.title": "更多操作",
"customizeToolbar.quick_actions.description": "自定义并重新排列您常用的操作",
Expand Down
Loading
Loading