diff --git a/apps/mobile/changelog/0.2.2.md b/apps/mobile/changelog/0.2.2.md
new file mode 100644
index 000000000..e62727313
--- /dev/null
+++ b/apps/mobile/changelog/0.2.2.md
@@ -0,0 +1,24 @@
+# What's New in v0.2.2
+
+## Shiny New Things
+
+- Copy AI summaries with one tap
+- Use video duration as an Action condition
+
+## Improvements
+
+- Top indicator now fades smoothly when switching views (fa78bad)
+- Gradually rolling out an experimental unified local database for mobile and desktop (#3897 #3902)
+- Improved image preview
+- Refined Android dropdown-menu styling
+- Fixed star/unstar status not syncing across devices (fbd0b3)
+
+## No Longer Broken
+
+- Fixed login failures caused by corrupted cache in some cases (2bbe512)
+- Fixed inability to follow sources in preview mode (2c04919)
+- Fixed profile-picture upload not working
+
+## Thanks
+
+Special thanks to volunteer contributors @kovsu @huanfe1 @cscnk52 @Olexandr88 @0-o0 @kingsword09 @ericyzhu for their valuable contributions
diff --git a/apps/mobile/changelog/next.md b/apps/mobile/changelog/next.md
index ac3e39f29..000f858e3 100644
--- a/apps/mobile/changelog/next.md
+++ b/apps/mobile/changelog/next.md
@@ -1,26 +1,11 @@
# What's New in vNEXT_VERSION
-## ⚠️ Important
-
-We’ve made some updates to our `user` database to help keep things running smoothly and securely. Some fields—like your name, email, profile image link, handle, bio, and website—now have maximum character limits:
-
-- Name: up to 64 characters
-- Email: up to 64 characters
-- Profile image link: up to 256 characters
-- Handle: up to 36 characters
-- Bio: up to 256 characters
-- Website: up to 256 characters
-
-If you previously entered information that’s longer than these limits, it will be automatically shortened to fit. Other fields, like your email verification status, two-factor authentication, and social links, are not affected by these changes.
-
## Shiny new things
-- 🎉 Say hello to a snazzy new look for your personal profile! We've sprinkled in some cool social attribute settings to spice things up. But hold onto your hats—this is just the appetizer for our grand social vision! 🚀 Stay tuned for more! 😎
-
## Improvements
-- 🌟 Buckle up, folks! Our AI summarization just got a dazzling new animation makeover—smoother, flashier, and ready to impress! Plus, we’ve cranked up the performance so it runs like a dream. Get ready to be wowed! 😎✨
-
## No longer broken
-🎉 Ta-da! We’ve squashed a bunch of pesky bugs you awesome folks in the community pointed out—high fives all around! 🙌 But if something’s still acting wonky, don’t be shy—holler at us with an issue report, pretty please! 😜 Let’s keep the good vibes rolling! 🚀
+## Thanks
+
+Special thanks to volunteer contributors @ for their valuable contributions
diff --git a/apps/mobile/changelog/next.template.md b/apps/mobile/changelog/next.template.md
index 4ef2c94b6..000f858e3 100644
--- a/apps/mobile/changelog/next.template.md
+++ b/apps/mobile/changelog/next.template.md
@@ -5,3 +5,7 @@
## Improvements
## No longer broken
+
+## Thanks
+
+Special thanks to volunteer contributors @ for their valuable contributions
diff --git a/apps/mobile/ios/Folo/Info.plist b/apps/mobile/ios/Folo/Info.plist
index 409ca3d33..84f21c52e 100644
--- a/apps/mobile/ios/Folo/Info.plist
+++ b/apps/mobile/ios/Folo/Info.plist
@@ -32,7 +32,7 @@
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
- 0.2.1
+ 0.2.2
CFBundleSignature
????
CFBundleURLTypes
@@ -52,7 +52,7 @@
CFBundleVersion
- 109
+ 110
ITSAppUsesNonExemptEncryption
LSApplicationCategoryType
diff --git a/apps/mobile/package.json b/apps/mobile/package.json
index b38190210..601ccd599 100644
--- a/apps/mobile/package.json
+++ b/apps/mobile/package.json
@@ -1,6 +1,6 @@
{
"name": "@follow/mobile",
- "version": "0.2.1",
+ "version": "0.2.2",
"private": true,
"main": "src/main.tsx",
"scripts": {
diff --git a/apps/mobile/src/components/layouts/views/SafeNavigationScrollView.tsx b/apps/mobile/src/components/layouts/views/SafeNavigationScrollView.tsx
index ceea9f2ed..e5e8f1c67 100644
--- a/apps/mobile/src/components/layouts/views/SafeNavigationScrollView.tsx
+++ b/apps/mobile/src/components/layouts/views/SafeNavigationScrollView.tsx
@@ -1,4 +1,5 @@
import { useTypeScriptHappyCallback } from "@follow/hooks"
+import { cn } from "@follow/utils"
import { useSetAtom, useStore } from "jotai"
import type { PropsWithChildren } from "react"
import { use, useImperativeHandle, useLayoutEffect, useRef, useState } from "react"
@@ -134,7 +135,7 @@ export const SafeNavigationScrollView = ({
{...props}
>
-
+
{children}
{ScrollViewBottom}
diff --git a/apps/mobile/src/components/ui/grouped/GroupedList.tsx b/apps/mobile/src/components/ui/grouped/GroupedList.tsx
index 92d994c8b..8a0d3f3f0 100644
--- a/apps/mobile/src/components/ui/grouped/GroupedList.tsx
+++ b/apps/mobile/src/components/ui/grouped/GroupedList.tsx
@@ -29,6 +29,7 @@ interface GroupedInsetListCardProps {
}
interface BaseCellClassNames {
+ className?: string
leftClassName?: string
rightClassName?: string
}
@@ -146,11 +147,11 @@ export const GroupedInsetListNavigationLink: FC<
disabled?: boolean
postfix?: React.ReactNode
} & BaseCellClassNames
-> = ({ label, icon, onPress, disabled, leftClassName, rightClassName, postfix }) => {
+> = ({ label, icon, onPress, disabled, className, leftClassName, rightClassName, postfix }) => {
const rightIconColor = useColor("tertiaryLabel")
return (
-
+
{({ pressed }) => (
void
} & BaseCellClassNames
-> = ({ label, description, children, leftClassName, rightClassName, icon, onPress }) => {
+> = ({ label, description, children, className, leftClassName, rightClassName, icon, onPress }) => {
return (
diff --git a/apps/mobile/src/lib/api-fetch.ts b/apps/mobile/src/lib/api-fetch.ts
index 0ea57a528..5bb94ddcd 100644
--- a/apps/mobile/src/lib/api-fetch.ts
+++ b/apps/mobile/src/lib/api-fetch.ts
@@ -12,7 +12,7 @@ import { proxyEnv } from "./proxy-env"
export const apiFetch = ofetch.create({
retry: false,
-
+ credentials: "omit",
baseURL: proxyEnv.API_URL,
onRequest: async (ctx) => {
const { options, request } = ctx
diff --git a/apps/mobile/src/modules/screen/TimelineViewSelector.tsx b/apps/mobile/src/modules/screen/TimelineViewSelector.tsx
index 2e02c1a9d..c10984fea 100644
--- a/apps/mobile/src/modules/screen/TimelineViewSelector.tsx
+++ b/apps/mobile/src/modules/screen/TimelineViewSelector.tsx
@@ -1,16 +1,12 @@
import { useViewWithSubscription } from "@follow/store/subscription/hooks"
import { useUnreadByView } from "@follow/store/unread/hooks"
+import { cn } from "@follow/utils"
import * as React from "react"
import { useEffect } from "react"
import { useTranslation } from "react-i18next"
import type { StyleProp, ViewStyle } from "react-native"
import { ScrollView, Text, useWindowDimensions, View } from "react-native"
-import Animated, {
- interpolate,
- interpolateColor,
- useAnimatedStyle,
- useSharedValue,
-} from "react-native-reanimated"
+import Animated, { interpolate, interpolateColor, useAnimatedStyle } from "react-native-reanimated"
import { ReAnimatedPressable } from "@/src/components/common/AnimatedComponents"
import { TIMELINE_VIEW_SELECTOR_HEIGHT } from "@/src/constants/ui"
@@ -28,7 +24,7 @@ import { TimelineViewSelectorContextMenu } from "./TimelineViewSelectorContextMe
const ACTIVE_WIDTH = 180
const INACTIVE_WIDTH = 48
-const ACTIVE_TEXT_WIDTH = 85
+const ACTIVE_TEXT_WIDTH = 95
export function TimelineViewSelector() {
const activeViews = useViewWithSubscription()
@@ -69,15 +65,16 @@ function ItemWrapper({
index,
activeColor,
children,
- isActive,
onPress,
style,
+ className,
}: {
children: React.ReactNode
index: number
isActive: boolean
activeColor: string
onPress: () => void
+ className?: string
style?: Exclude, number>
}) {
const { width: windowWidth } = useWindowDimensions()
@@ -88,13 +85,14 @@ function ItemWrapper({
windowWidth - (INACTIVE_WIDTH + 12) * (activeViews.length - 1) - 8 * 2,
ACTIVE_WIDTH,
)
-
- const textWidth = useSharedValue(0)
const bgColor = useColor("gray5")
return (
({
backgroundColor: interpolateColor(
@@ -105,22 +103,13 @@ function ItemWrapper({
width: interpolate(
dragProgress.get(),
[index - 1, index, index + 1],
- [INACTIVE_WIDTH, Math.max(activeWidth, textWidth.value + INACTIVE_WIDTH), INACTIVE_WIDTH],
+ [INACTIVE_WIDTH, Math.max(activeWidth, INACTIVE_WIDTH), INACTIVE_WIDTH],
"clamp",
),
...style,
}))}
>
- {
- if (isActive) {
- textWidth.set(nativeEvent.layout.width)
- }
- }}
- >
- {children}
-
+ {children}
)
}
@@ -192,7 +181,7 @@ function ViewItem({
({
width: interpolate(
dragProgress.get(),
@@ -202,21 +191,28 @@ function ViewItem({
),
}))}
>
-
+
{t(view.name)}
{/* Unread indicator for inactive items */}
({
+ left: 30,
+ top: 10,
backgroundColor: textColor,
borderColor,
display: unreadCount ? "flex" : "none",
diff --git a/apps/mobile/src/modules/subscription/items/UnreadCount.tsx b/apps/mobile/src/modules/subscription/items/UnreadCount.tsx
index 26e9b6a10..0167a6e4d 100644
--- a/apps/mobile/src/modules/subscription/items/UnreadCount.tsx
+++ b/apps/mobile/src/modules/subscription/items/UnreadCount.tsx
@@ -22,7 +22,12 @@ export function UnreadCount({
if (!unread) return null
return showUnreadCount ? (
-
+
{unread > max ? `${max}+` : unread}
) : (
diff --git a/packages/internal/store/src/entry/store.ts b/packages/internal/store/src/entry/store.ts
index 555eb57f7..c079f38e0 100644
--- a/packages/internal/store/src/entry/store.ts
+++ b/packages/internal/store/src/entry/store.ts
@@ -606,7 +606,7 @@ class EntrySyncServices {
cookie: options.cookie,
}
: undefined,
- credentials: options?.cookie ? undefined : "include",
+ credentials: options?.cookie ? "omit" : "include",
body: JSON.stringify({
ids: nextIds,
}),