mirror of
https://github.com/RSSNext/Folo.git
synced 2026-10-16 20:51:43 +08:00
fix(mobile): lock Hide Special Badges on a free plan, as desktop does
The paid lock missed this Appearance switch, which desktop also marks paid, so on a free or trial plan it flipped back off without a reason. It now shows the paid badge and offers the upgrade, and a test checks that each settings screen locks the paid settings it changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
import { readdirSync, readFileSync } from "node:fs"
|
||||
|
||||
import { PAID_SETTINGS, SettingPaidLevels } from "@follow/shared/settings/constants"
|
||||
import { describe, expect, it } from "vitest"
|
||||
|
||||
const routesDir = new URL("../routes/", import.meta.url)
|
||||
|
||||
// The setter each namespace's settings screens save with, and the hook that says the plan lacks one
|
||||
const SETTING_HOOKS = {
|
||||
general: { setter: "setGeneralSetting", lockedHook: "useGeneralPaidSettingLocked" },
|
||||
ui: { setter: "setUISetting", lockedHook: "useUIPaidSettingLocked" },
|
||||
} as const
|
||||
|
||||
// A call with the key as its first argument, however the formatter wraps it
|
||||
const callsWithKey = (source: string, fn: string, key: string) =>
|
||||
new RegExp(String.raw`\b${fn}\(\s*"${key}"\s*[,)]`).test(source)
|
||||
|
||||
describe("PaidSettingCell", () => {
|
||||
it("locks every paid setting a settings screen changes", () => {
|
||||
const unlocked: string[] = []
|
||||
|
||||
for (const file of readdirSync(routesDir).filter((name) => name.endsWith(".tsx"))) {
|
||||
const source = readFileSync(new URL(file, routesDir), "utf8")
|
||||
|
||||
for (const [namespace, { setter, lockedHook }] of Object.entries(SETTING_HOOKS)) {
|
||||
const paidSettings: Record<string, SettingPaidLevels> =
|
||||
PAID_SETTINGS[namespace as keyof typeof SETTING_HOOKS]
|
||||
for (const [key, level] of Object.entries(paidSettings)) {
|
||||
// Free plans have these, so nothing locks them
|
||||
if (level === SettingPaidLevels.Free || level === SettingPaidLevels.FreeLimited) continue
|
||||
|
||||
// A switch for a paid setting without its lock refuses to turn on without saying why
|
||||
if (callsWithKey(source, setter, key) && !callsWithKey(source, lockedHook, key)) {
|
||||
unlocked.push(`${file}: ${key}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(unlocked).toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -2,7 +2,7 @@ import { getUnreadAll } from "@follow/store/unread/getters"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
import type { AppColorScheme } from "@/src/atoms/settings/ui"
|
||||
import { setUISetting, useUISettingKey } from "@/src/atoms/settings/ui"
|
||||
import { setUISetting, useUIPaidSettingLocked, useUISettingKey } from "@/src/atoms/settings/ui"
|
||||
import {
|
||||
NavigationBlurEffectHeaderView,
|
||||
SafeNavigationScrollView,
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
setBadgeCountAsyncWithPermission,
|
||||
} from "@/src/lib/permission"
|
||||
|
||||
import { PaidSettingCell } from "../components/PaidSettingCell"
|
||||
import { ReadingScreen } from "./Reading"
|
||||
|
||||
const fontSizePresets = [
|
||||
@@ -82,6 +83,7 @@ export const AppearanceScreen = () => {
|
||||
)
|
||||
const showUnreadCountBadgeMobile = useUISettingKey("showUnreadCountBadgeMobile")
|
||||
const hideExtraBadge = useUISettingKey("hideExtraBadge")
|
||||
const isHideExtraBadgeLocked = useUIPaidSettingLocked("hideExtraBadge")
|
||||
const thumbnailRatio = useUISettingKey("thumbnailRatio")
|
||||
|
||||
// Font scaling settings
|
||||
@@ -164,18 +166,20 @@ export const AppearanceScreen = () => {
|
||||
|
||||
<GroupedInsetListSectionHeader label={t("appearance.subscriptions")} marginSize="small" />
|
||||
<GroupedInsetListCard>
|
||||
<GroupedInsetListCell
|
||||
<PaidSettingCell
|
||||
label={t("appearance.hide_extra_badge.label")}
|
||||
description={t("appearance.hide_extra_badge.description_mobile")}
|
||||
locked={isHideExtraBadgeLocked}
|
||||
>
|
||||
<Switch
|
||||
size="sm"
|
||||
value={hideExtraBadge}
|
||||
disabled={isHideExtraBadgeLocked}
|
||||
onValueChange={(val) => {
|
||||
setUISetting("hideExtraBadge", val)
|
||||
}}
|
||||
/>
|
||||
</GroupedInsetListCell>
|
||||
</PaidSettingCell>
|
||||
<GroupedInsetListCell
|
||||
label={t("appearance.thumbnail_ratio.title")}
|
||||
description={t("appearance.thumbnail_ratio.description")}
|
||||
|
||||
Reference in New Issue
Block a user