Skip to content

Commit 21d6ae3

Browse files
authored
chore(desktop): Release v1.1.3 for hotfix
chore(desktop): Release v1.1.3 for hotfix
2 parents 8ab1f70 + 81fe198 commit 21d6ae3

File tree

48 files changed

+578
-561
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+578
-561
lines changed

README.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,10 @@
1717
<a href="https://x.com/intent/follow?screen_name=folo_is"><img src="https://img.shields.io/badge/Follow-blue?color=1d9bf0&logo=x&labelColor=black&style=flat-square" /></a>
1818
<a href="https://discord.gg/followapp" target="_blank"><img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fdiscord.com%2Fapi%2Finvites%2Ffollowapp%3Fwith_counts%3Dtrue&query=approximate_member_count&color=5865F2&label=Discord&labelColor=black&logo=discord&logoColor=white&style=flat-square"/></a>
1919
<br />
20-
<a href="https://github.com/RSSNext/Folo/releases"><img src="https://img.shields.io/github/package-json/v/RSSNext/Folo?filename=%2Fapps%2Fmobile%2Fpackage.json&style=flat-square&logo=folo&logoColor=white&label=Mobile&labelColor=black&color=FF5C00" /></a>
2120
<a href="https://apps.apple.com/us/app/folo-follow-everything/id6739802604"><img src="https://img.shields.io/itunes/v/6739802604?style=flat-square&logo=apple&label=App%20Store&color=FF5C00&labelColor=black" /></a>
2221
<a href="https://play.google.com/store/apps/details?id=is.follow" target="_blank"><img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fplay.cuzi.workers.dev%2Fplay%3Fi%3Dis.follow%26gl%3DUS%26hl%3Den%26l%3DAndroid%26m%3D%24version&style=flat-square&logo=google-play&label=Google%20Play&labelColor=black&color=FF5C00"/></a>
23-
<a href="https://github.com/RSSNext/Folo/releases"><img src="https://img.shields.io/github/package-json/v/RSSNext/Folo?filename=%2Fapps%2Fdesktop%2Fpackage.json&style=flat-square&logo=folo&logoColor=white&label=Desktop&labelColor=black&color=FF5C00" /></a>
24-
<a href="https://apps.apple.com/us/app/folo-follow-everything/id6739802604"><img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Ffolo-mac-app-store-version.rss3.workers.dev%2F&query=version&prefix=v&style=flat-square&logo=apple&label=Mac%20App%20Store&labelColor=black&color=FF5C00&cacheSeconds=3600" /></a>
25-
<a href="https://apps.microsoft.com/detail/9nvfzpv0v0ht?mode=direct"><img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Ffolo-microsoft-store-version.rss3.workers.dev%2F&query=version&style=flat-square&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMyAzaDguNTN2OC41M0gzek0xMi40NjkgM2g4LjUzdjguNTNoLTguNTN6TTMgMTIuNDdoOC41M1YyMUgzek0xMi40NjkgMTIuNDdoOC41M1YyMWgtOC41M3oiLz48L3N2Zz4%3D&logoColor=white&label=Microsoft%20Store&labelColor=black&color=FF5C00&cacheSeconds=3600&prefix=v" /></a>
22+
<a href="https://apps.apple.com/us/app/folo-follow-everything/id6739802604"><img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.folo.is%2Fupdates%2Fdistribution%2Fmas&query=data.storeVersion&prefix=v&style=flat-square&logo=apple&label=Mac%20App%20Store&labelColor=black&color=FF5C00&cacheSeconds=3600" /></a>
23+
<a href="https://apps.microsoft.com/detail/9nvfzpv0v0ht?mode=direct"><img src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.folo.is%2Fupdates%2Fdistribution%2Fmss&query=data.storeVersion&style=flat-square&logo=data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMyAzaDguNTN2OC41M0gzek0xMi40NjkgM2g4LjUzdjguNTNoLTguNTN6TTMgMTIuNDdoOC41M1YyMUgzek0xMi40NjkgMTIuNDdoOC41M1YyMWgtOC41M3oiLz48L3N2Zz4%3D&logoColor=white&label=Microsoft%20Store&labelColor=black&color=FF5C00&cacheSeconds=3600&prefix=v" /></a>
2624
<br />
2725
<br />
2826
<!-- <a href="https://github.com/RSSNext/Folo" target="_blank"><img src="https://github.com/user-attachments/assets/59b957fb-59ed-4ef0-994e-f6a402a6fe2b" alt="GitHub Trending" height="55"/></a>
@@ -32,6 +30,7 @@
3230
<a href="https://apps.apple.com/us/app/folo-follow-everything/id6739802604" target="_blank"><img src="https://github.com/user-attachments/assets/198a0165-b8c9-45c1-9116-b473a13a8d0c" alt="Folo Desktop" width="46%"/></a>
3331
<br />
3432
<br />
33+
3534
</p>
3635
</div>
3736

@@ -54,10 +53,10 @@ Feel free to try it using the following methods:
5453

5554
You can also install using the following methods maintained by our community:
5655

57-
- If you are using Arch Linux, you can install package [folo-appimage](https://aur.archlinux.org/packages/folo-appimage) that maintained by [timochan](https://github.com/ttimochan) and [grtsinry43](https://github.com/grtsinry43).
58-
- If you are using Nix, you can install package [follow](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/fo/follow/package.nix) that maintained by [iosmanthus](https://github.com/iosmanthus).
59-
- If you are using macOS with [Homebrew](https://brew.sh), you can install cask [folo](https://formulae.brew.sh/cask/folo) that maintained by [realSunyz](https://github.com/realSunyz).
60-
- If you are using Windows with [Scoop](https://scoop.sh), you can install manifest [folo](https://github.com/cscnk52/cetacea/blob/master/bucket/folo.json) that maintained by [cscnk52](https://github.com/cscnk52).
56+
- If you are using Arch Linux, you can install the package [folo-appimage](https://aur.archlinux.org/packages/folo-appimage) that is maintained by [timochan](https://github.com/ttimochan) and [grtsinry43](https://github.com/grtsinry43).
57+
- If you are using Nix, you can install the package [follow](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/fo/follow/package.nix) that is maintained by [iosmanthus](https://github.com/iosmanthus).
58+
- If you are using macOS with [Homebrew](https://brew.sh), you can install the cask [folo](https://formulae.brew.sh/cask/folo) that is maintained by [realSunyz](https://github.com/realSunyz).
59+
- If you are using Windows with [Scoop](https://scoop.sh), you can install the manifest [folo](https://github.com/cscnk52/cetacea/blob/master/bucket/folo.json) that is maintained by [cscnk52](https://github.com/cscnk52).
6160

6261
| [![Discord](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fdiscord.com%2Fapi%2Finvites%2Ffollowapp%3Fwith_counts%3Dtrue&query=approximate_member_count&color=5865F2&label=Discord&labelColor=black&logo=discord&logoColor=white&style=flat-square)](https://discord.gg/followapp) | Join our Discord server to connect with developers, request features, and receive support. |
6362
| :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------- |
@@ -108,9 +107,9 @@ You are welcome to join the open source community to build together, please chec
108107

109108
## 🔏 Code signing policy
110109

111-
Folo for Windows uses free code signing provided by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/).
110+
Folo for Windows uses free code signing provided by [SignPath.io](https://about.signpath.io/), a certificate by [SignPath Foundation](https://signpath.org/).
112111

113-
Folo for macOS and iOS are signed and notarized by [Apple Developer Program](https://developer.apple.com/programs/).
112+
Folo for macOS and iOS is signed and notarized by [Apple Developer Program](https://developer.apple.com/programs/).
114113

115114
All released files are verified with [GitHub artifact attestations](https://github.com/RSSNext/Folo/attestations) to ensure their provenance and integrity.
116115

apps/desktop/layer/main/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"i18next": "25.6.0",
4242
"js-yaml": "4.1.0",
4343
"ky": "1.14.0",
44-
"linkedom": "0.18.12",
44+
"linkedom": "0.18.11",
4545
"lowdb": "7.0.1",
4646
"msedge-tts": "2.0.2",
4747
"node-machine-id": "1.1.12",

apps/desktop/layer/renderer/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333

3434
<!-- Apple Meta Tags -->
3535
<meta name="apple-itunes-app" content="app-id=6739802604" />
36-
<meta name="apple-mobile-web-app-capable" content="yes" />
36+
<meta name="mobile-web-app-capable" content="yes" />
3737
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
3838
<meta name="apple-mobile-web-app-title" content="Folo" />
3939

apps/desktop/layer/renderer/src/atoms/settings/ai.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ export const isServerShortcut = (shortcut: AIShortcut) => !!shortcut.defaultProm
111111
export const createDefaultSettings = (): WebAISettings => ({
112112
...defaultAISettings,
113113
shortcuts: normalizeShortcuts(defaultAISettings.shortcuts),
114-
panelStyle: AIChatPanelStyle.Fixed,
114+
panelStyle: AIChatPanelStyle.Floating,
115115
showSplineButton: true,
116116
})
117117

@@ -224,5 +224,4 @@ export const removeMCPService = (id: string) => {
224224
//// Enhance Init Ai Settings
225225
export const initializeDefaultAISettings = () => {
226226
initializeDefaultSettings()
227-
if (getAISettings().panelStyle === AIChatPanelStyle.Fixed) setAIPanelVisibility(true)
228227
}

apps/desktop/layer/renderer/src/hooks/biz/useNavigateEntry.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getReadonlyRoute, getStableRouterNavigate } from "@follow/components/atoms/route.js"
22
import { useMobile } from "@follow/components/hooks/useMobile.js"
33
import { useSheetContext } from "@follow/components/ui/sheet/context.js"
4-
import { FeedViewType } from "@follow/constants"
4+
import type { FeedViewType } from "@follow/constants"
55
import { getEntry } from "@follow/store/entry/getter"
66
import { getSubscriptionByFeedId } from "@follow/store/subscription/getter"
77
import { tracker } from "@follow/tracker"
@@ -18,11 +18,9 @@ import {
1818
ROUTE_FEED_IN_INBOX,
1919
ROUTE_FEED_IN_LIST,
2020
ROUTE_FEED_PENDING,
21-
ROUTE_TIMELINE_OF_VIEW,
22-
ROUTE_VIEW_ALL,
2321
} from "~/constants"
2422

25-
import { useRouteParamsSelector } from "./useRouteParams"
23+
import { getTimelineIdByView, useRouteParamsSelector } from "./useRouteParams"
2624

2725
export type NavigateEntryOptions = Partial<{
2826
timelineId: string
@@ -86,8 +84,7 @@ const parseNavigateEntryOptions = (options: NavigateEntryOptions): ParsedNavigat
8684
finalFeedId = encodeURIComponent(finalFeedId)
8785

8886
if (finalView !== undefined && !timelineId) {
89-
finalTimelineId =
90-
finalView === FeedViewType.All ? ROUTE_VIEW_ALL : `${ROUTE_TIMELINE_OF_VIEW}${finalView}`
87+
finalTimelineId = getTimelineIdByView(finalView)
9188
}
9289

9390
return {
@@ -109,7 +106,7 @@ export function getNavigateEntryPath(options: NavigateEntryOptions | ParsedNavig
109106

110107
/*
111108
* /timeline/:timelineId/:feedId/:entryId
112-
* timelineId: view-1
109+
* timelineId: articles | social-media | view-1 (legacy) | ...
113110
* feedId: xxx, folder-xxx, list-xxx, inbox-xxx
114111
* entryId: xxx
115112
*/

apps/desktop/layer/renderer/src/hooks/biz/usePeekModal.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { useModalStack } from "~/components/ui/modal/stacked/hooks"
1111
import { EntryModalPreview } from "~/components/ui/peek-modal/EntryModalPreview"
1212
import { EntryMoreActions } from "~/components/ui/peek-modal/EntryMoreActions"
1313
import { EntryToastPreview } from "~/components/ui/peek-modal/EntryToastPreview"
14-
import { getRouteParams } from "~/hooks/biz/useRouteParams"
14+
import { getRouteParams, getTimelineIdByView } from "~/hooks/biz/useRouteParams"
1515

1616
export const usePeekModal = () => {
1717
const { present } = useModalStack()
@@ -42,7 +42,7 @@ export const usePeekModal = () => {
4242
const feedId = useEntry(entryId, (state) => state.feedId)
4343
const subscription = feedId ? getSubscriptionById(feedId) : undefined
4444
const view = subscription?.view ?? getRouteParams().view
45-
45+
const timelineId = getTimelineIdByView(view)
4646
return (
4747
<PeekModal
4848
rightActions={[
@@ -52,7 +52,7 @@ export const usePeekModal = () => {
5252
icon: <EntryMoreActions entryId={entryId} />,
5353
},
5454
]}
55-
to={feedId ? `/timeline/view-${view}/${feedId}/${entryId}` : undefined}
55+
to={feedId ? `/timeline/${timelineId}/${feedId}/${entryId}` : undefined}
5656
>
5757
{children}
5858
</PeekModal>

apps/desktop/layer/renderer/src/hooks/biz/useRouteParams.ts

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,59 @@ export interface BizRouteParams {
4343
timelineId?: string
4444
}
4545

46+
const VIEW_SLUG_BY_VIEW: Record<FeedViewType, string> = {
47+
[FeedViewType.All]: ROUTE_VIEW_ALL,
48+
[FeedViewType.Articles]: "articles",
49+
[FeedViewType.SocialMedia]: "social-media",
50+
[FeedViewType.Pictures]: "pictures",
51+
[FeedViewType.Videos]: "videos",
52+
[FeedViewType.Audios]: "audios",
53+
[FeedViewType.Notifications]: "notifications",
54+
}
55+
56+
const VIEW_PARAM_ALIAS_MAP: Record<string, FeedViewType> = Object.entries(VIEW_SLUG_BY_VIEW).reduce(
57+
(acc, [view, slug]) => {
58+
if (slug === ROUTE_VIEW_ALL) return acc
59+
const numericView = Number(view)
60+
if (Number.isNaN(numericView)) return acc
61+
acc[slug] = numericView as FeedViewType
62+
return acc
63+
},
64+
{} as Record<string, FeedViewType>,
65+
)
66+
67+
const FEED_VIEW_VALUES = new Set<FeedViewType>(
68+
Object.values(FeedViewType).filter((value): value is FeedViewType => typeof value === "number"),
69+
)
70+
71+
const isFeedViewTypeValue = (value: number): value is FeedViewType =>
72+
Number.isInteger(value) && FEED_VIEW_VALUES.has(value as FeedViewType)
73+
74+
export const getTimelineIdByView = (view: FeedViewType) =>
75+
VIEW_SLUG_BY_VIEW[view] ?? `${ROUTE_TIMELINE_OF_VIEW}${view}`
76+
4677
export function parseView(input: string | undefined): FeedViewType | undefined {
47-
if (input === ROUTE_VIEW_ALL) return FeedViewType.All
48-
if (input?.startsWith(ROUTE_TIMELINE_OF_VIEW)) {
49-
const view = Number.parseInt(input?.slice(ROUTE_TIMELINE_OF_VIEW.length), 10)
50-
if (Object.values(FeedViewType).includes(view)) {
51-
return view as FeedViewType
78+
if (!input) return undefined
79+
80+
const normalizedInput = input.toLowerCase()
81+
82+
if (normalizedInput === ROUTE_VIEW_ALL) return FeedViewType.All
83+
84+
const aliasView = VIEW_PARAM_ALIAS_MAP[normalizedInput]
85+
if (aliasView !== undefined) return aliasView
86+
87+
if (normalizedInput.startsWith(ROUTE_TIMELINE_OF_VIEW)) {
88+
const view = Number.parseInt(normalizedInput.slice(ROUTE_TIMELINE_OF_VIEW.length), 10)
89+
if (isFeedViewTypeValue(view)) {
90+
return view
5291
}
5392
}
93+
94+
const numericView = Number.parseInt(normalizedInput, 10)
95+
96+
if (isFeedViewTypeValue(numericView)) {
97+
return numericView
98+
}
5499
}
55100

56101
const parseRouteParams = (params: Params<any>, _searchParams: URLSearchParams): BizRouteParams => {

apps/desktop/layer/renderer/src/hooks/biz/useTimelineList.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,29 @@ import { useSubscriptionStore } from "@follow/store/subscription/store"
44
import { useMemo } from "react"
55

66
import { useUISettingKey } from "~/atoms/settings/ui"
7-
import { ROUTE_TIMELINE_OF_VIEW, ROUTE_VIEW_ALL } from "~/constants/app"
7+
import { ROUTE_VIEW_ALL } from "~/constants/app"
8+
9+
import { getTimelineIdByView, parseView } from "./useRouteParams"
810

911
const ALL_TIMELINE_IDS = getViewList({ includeAll: true }).map((view) =>
10-
view.view === FeedViewType.All ? ROUTE_VIEW_ALL : `${ROUTE_TIMELINE_OF_VIEW}${view.view}`,
12+
getTimelineIdByView(view.view),
1113
)
1214

15+
const normalizeTimelineId = (id: string) => {
16+
const view = parseView(id)
17+
return view !== undefined ? getTimelineIdByView(view) : id
18+
}
19+
20+
const filterKnownTimelineIds = (ids: string[]) => {
21+
const seen = new Set<string>()
22+
return ids.filter((id) => {
23+
if (!ALL_TIMELINE_IDS.includes(id)) return false
24+
if (seen.has(id)) return false
25+
seen.add(id)
26+
return true
27+
})
28+
}
29+
1330
export const computeTimelineTabLists = ({
1431
timelineTabs,
1532
hasAudiosSubscription,
@@ -19,16 +36,17 @@ export const computeTimelineTabLists = ({
1936
hasAudiosSubscription: boolean
2037
hasNotificationsSubscription: boolean
2138
}) => {
22-
const savedVisible = (timelineTabs?.visible ?? []).filter((id) => ALL_TIMELINE_IDS.includes(id))
23-
const savedHidden = (timelineTabs?.hidden ?? []).filter((id) => ALL_TIMELINE_IDS.includes(id))
39+
const savedVisible = filterKnownTimelineIds(
40+
(timelineTabs?.visible ?? []).map(normalizeTimelineId),
41+
)
42+
const savedHidden = filterKnownTimelineIds((timelineTabs?.hidden ?? []).map(normalizeTimelineId))
2443
const extras = ALL_TIMELINE_IDS.filter(
2544
(id) => !savedVisible.includes(id) && !savedHidden.includes(id),
2645
)
2746

2847
const isDefaultHidden = (id: string) => {
29-
if (id === `${ROUTE_TIMELINE_OF_VIEW}${FeedViewType.Audios}`) return !hasAudiosSubscription
30-
if (id === `${ROUTE_TIMELINE_OF_VIEW}${FeedViewType.Notifications}`)
31-
return !hasNotificationsSubscription
48+
if (id === getTimelineIdByView(FeedViewType.Audios)) return !hasAudiosSubscription
49+
if (id === getTimelineIdByView(FeedViewType.Notifications)) return !hasNotificationsSubscription
3250
return false
3351
}
3452

apps/desktop/layer/renderer/src/modules/ai-chat-session/store.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,5 +95,3 @@ export const hydrateSessionsFromLocalDb = async () => {
9595
aiChatSessionStoreActions.setError(error instanceof Error ? error.message : "hydrate_failed")
9696
}
9797
}
98-
99-
void hydrateSessionsFromLocalDb()

apps/desktop/layer/renderer/src/modules/ai-chat/components/3d-models/AISplineLoader.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export const AISplineLoader = ({ className }: { className?: string }) => {
109109
)
110110

111111
return (
112-
<div ref={containerRef} className={cn("size-20", className)}>
112+
<div ref={containerRef} className={cn("size-16", className)}>
113113
<Spline scene={resolvedAIIconUrl} onLoad={handleLoad} className="size-full" />
114114
</div>
115115
)

0 commit comments

Comments
 (0)