Add user preference to disable sidebar swipe-to-open on mobile; cleanup migrations + README in prep for long-term fork maintenance

This commit is contained in:
2026-03-21 17:04:05 -05:00
parent eb5614a03b
commit 5cc8c736e7
12 changed files with 51 additions and 1 deletions

6
README-fork.md Normal file
View File

@@ -0,0 +1,6 @@
# `garrettmills/commafeed`
This is my personal fork of `Athou/commafeed` with some tweaks:
- "Infrequent" tab - like "All" but limits to blogs w/ an average post interval greater than a user-configurable number of days
- User preference to disable the swipe-to-open-menu gesture on mobile

View File

@@ -285,6 +285,7 @@ export interface Settings {
unreadCountTitle: boolean
unreadCountFavicon: boolean
disablePullToRefresh: boolean
disableMobileSwipe: boolean
infrequentThresholdDays: number
primaryColor?: string
sharingSettings: SharingSettings

View File

@@ -4,6 +4,7 @@ import { createSlice, isAnyOf, type PayloadAction } from "@reduxjs/toolkit"
import type { LocalSettings, Settings, UserModel, ViewMode } from "@/app/types"
import {
changeCustomContextMenu,
changeDisableMobileSwipe,
changeDisablePullToRefresh,
changeEntriesToKeepOnTopWhenScrolling,
changeExternalLinkIconDisplayMode,
@@ -142,6 +143,10 @@ export const userSlice = createSlice({
if (!state.settings) return
state.settings.disablePullToRefresh = action.meta.arg
})
builder.addCase(changeDisableMobileSwipe.pending, (state, action) => {
if (!state.settings) return
state.settings.disableMobileSwipe = action.meta.arg
})
builder.addCase(changeInfrequentThresholdDays.pending, (state, action) => {
if (!state.settings) return
state.settings.infrequentThresholdDays = action.meta.arg
@@ -176,6 +181,7 @@ export const userSlice = createSlice({
changeUnreadCountTitle.fulfilled,
changeUnreadCountFavicon.fulfilled,
changeDisablePullToRefresh.fulfilled,
changeDisableMobileSwipe.fulfilled,
changeInfrequentThresholdDays.fulfilled,
changePrimaryColor.fulfilled,
changeSharingSetting.fulfilled,

View File

@@ -131,6 +131,12 @@ export const changeDisablePullToRefresh = createAppAsyncThunk(
}
)
export const changeDisableMobileSwipe = createAppAsyncThunk("settings/disableMobileSwipe", (disableMobileSwipe: boolean, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({ ...settings, disableMobileSwipe })
})
export const changePrimaryColor = createAppAsyncThunk("settings/primaryColor", (primaryColor: string, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return

View File

@@ -9,6 +9,7 @@ import { useAppDispatch, useAppSelector } from "@/app/store"
import type { IconDisplayMode, ScrollMode, SharingSettings } from "@/app/types"
import {
changeCustomContextMenu,
changeDisableMobileSwipe,
changeDisablePullToRefresh,
changeEntriesToKeepOnTopWhenScrolling,
changeExternalLinkIconDisplayMode,
@@ -45,6 +46,7 @@ export function DisplaySettings() {
const unreadCountTitle = useAppSelector(state => state.user.settings?.unreadCountTitle)
const unreadCountFavicon = useAppSelector(state => state.user.settings?.unreadCountFavicon)
const disablePullToRefresh = useAppSelector(state => state.user.settings?.disablePullToRefresh)
const disableMobileSwipe = useAppSelector(state => state.user.settings?.disableMobileSwipe)
const infrequentThresholdDays = useAppSelector(state => state.user.settings?.infrequentThresholdDays)
const sharingSettings = useAppSelector(state => state.user.settings?.sharingSettings)
const primaryColor = useAppSelector(state => state.user.settings?.primaryColor) || Constants.theme.defaultPrimaryColor
@@ -145,6 +147,12 @@ export function DisplaySettings() {
onChange={async e => await dispatch(changeMobileFooter(e.currentTarget.checked))}
/>
<Switch
label={<Trans>On mobile, disable swipe gesture to open the menu</Trans>}
checked={disableMobileSwipe}
onChange={async e => await dispatch(changeDisableMobileSwipe(e.currentTarget.checked))}
/>
<NumberInput
label={<Trans>Infrequent posts threshold (days)</Trans>}
description={<Trans>Feeds posting less often than this (on average) will appear in the Infrequent view</Trans>}

View File

@@ -715,6 +715,10 @@ msgstr "On desktop"
msgid "On mobile"
msgstr "On mobile"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, disable swipe gesture to open the menu"
msgstr "On mobile, disable swipe gesture to open the menu"
#: src/components/settings/DisplaySettings.tsx
msgid "On mobile, show action buttons at the bottom of the screen"
msgstr "On mobile, show action buttons at the bottom of the screen"

View File

@@ -79,6 +79,7 @@ export default function Layout(props: Readonly<LayoutProps>) {
const webSocketConnected = useAppSelector(state => state.server.webSocketConnected)
const treeReloadInterval = useAppSelector(state => state.server.serverInfos?.treeReloadInterval)
const mobileFooter = useAppSelector(state => state.user.settings?.mobileFooter)
const disableMobileSwipe = useAppSelector(state => state.user.settings?.disableMobileSwipe)
const sidebarWidth = useAppSelector(state => state.user.localSettings.sidebarWidth)
const headerInFooter = mobile && !isBrowserExtensionPopup && mobileFooter
const dispatch = useAppDispatch()
@@ -164,6 +165,9 @@ export default function Layout(props: Readonly<LayoutProps>) {
const swipeHandlers = useSwipeable({
onSwiping: e => {
if (disableMobileSwipe) {
return
}
const threshold = document.documentElement.clientWidth / 6
if (e.absX > threshold) {
dispatch(setMobileMenuOpen(e.dir === "Right"))

View File

@@ -145,6 +145,7 @@ public class UserSettings extends AbstractModel {
private boolean unreadCountTitle;
private boolean unreadCountFavicon;
private boolean disablePullToRefresh;
private boolean disableMobileSwipe;
private int infrequentThresholdDays;

View File

@@ -76,6 +76,9 @@ public class Settings implements Serializable {
@Schema(description = "disable pull to refresh", required = true)
private boolean disablePullToRefresh;
@Schema(description = "disable swipe gesture to open mobile menu", required = true)
private boolean disableMobileSwipe;
@Schema(description = "threshold in days for the infrequent view", required = true)
private int infrequentThresholdDays;

View File

@@ -132,6 +132,7 @@ public class UserREST {
s.setUnreadCountTitle(settings.isUnreadCountTitle());
s.setUnreadCountFavicon(settings.isUnreadCountFavicon());
s.setDisablePullToRefresh(settings.isDisablePullToRefresh());
s.setDisableMobileSwipe(settings.isDisableMobileSwipe());
s.setPrimaryColor(settings.getPrimaryColor());
s.setInfrequentThresholdDays(settings.getInfrequentThresholdDays());
@@ -169,6 +170,7 @@ public class UserREST {
s.setUnreadCountTitle(false);
s.setUnreadCountFavicon(true);
s.setDisablePullToRefresh(false);
s.setDisableMobileSwipe(false);
s.setInfrequentThresholdDays(7);
}
return s;
@@ -206,6 +208,7 @@ public class UserREST {
s.setUnreadCountTitle(settings.isUnreadCountTitle());
s.setUnreadCountFavicon(settings.isUnreadCountFavicon());
s.setDisablePullToRefresh(settings.isDisablePullToRefresh());
s.setDisableMobileSwipe(settings.isDisableMobileSwipe());
s.setPrimaryColor(settings.getPrimaryColor());
s.setInfrequentThresholdDays(settings.getInfrequentThresholdDays());

View File

@@ -11,4 +11,12 @@
</addColumn>
</changeSet>
<changeSet id="add-disable-mobile-swipe" author="athou">
<addColumn tableName="USERSETTINGS">
<column name="disableMobileSwipe" type="BOOLEAN" valueBoolean="false">
<constraints nullable="false" />
</column>
</addColumn>
</changeSet>
</databaseChangeLog>

View File

@@ -38,6 +38,6 @@
<include file="changelogs/db.changelog-5.11.xml" />
<include file="changelogs/db.changelog-5.12.xml" />
<include file="changelogs/db.changelog-7.0.xml" />
<include file="changelogs/db.changelog-7.1.xml" />
<include file="changelogs/db.changelog-gmfork.xml" />
</databaseChangeLog>