feat: send notification for new entries with Gotify, ntfy or Pushover, configurable per feed.

This commit is contained in:
Louis POIROT--HATTERMANN
2026-02-15 17:19:43 +01:00
parent ca2c687f26
commit e54151d2eb
26 changed files with 974 additions and 30 deletions

View File

@@ -27,6 +27,7 @@ const createFeed = (id: number, unread: number): Subscription => ({
feedUrl: "",
feedLink: "",
iconUrl: "",
notifyOnNewEntries: true,
})
const root = createCategory("root")

View File

@@ -29,6 +29,7 @@ export interface Subscription {
newestItemTime?: number
filter?: string
filterLegacy?: string
notifyOnNewEntries: boolean
}
export interface Category {
@@ -110,6 +111,7 @@ export interface FeedModificationRequest {
categoryId?: string
position?: number
filter?: string
notifyOnNewEntries?: boolean
}
export interface GetEntriesRequest {
@@ -249,6 +251,17 @@ export interface SharingSettings {
buffer: boolean
}
export type NotificationService = "disabled" | "ntfy" | "gotify" | "pushover"
export interface NotificationSettings {
enabled: boolean
type?: Exclude<NotificationService, "disabled">
serverUrl?: string
token?: string
userKey?: string
topic?: string
}
export interface Settings {
language?: string
readingMode: ReadingMode
@@ -271,6 +284,7 @@ export interface Settings {
disablePullToRefresh: boolean
primaryColor?: string
sharingSettings: SharingSettings
notificationSettings: NotificationSettings
}
export interface LocalSettings {
@@ -290,6 +304,7 @@ export interface SubscribeRequest {
url: string
title: string
categoryId?: string
notifyOnNewEntries: boolean
}
export interface TagRequest {

View File

@@ -11,6 +11,7 @@ import {
changeMarkAllAsReadConfirmation,
changeMarkAllAsReadNavigateToUnread,
changeMobileFooter,
changeNotificationSettings,
changePrimaryColor,
changeReadingMode,
changeReadingOrder,
@@ -148,6 +149,13 @@ export const userSlice = createSlice({
if (!state.settings) return
state.settings.sharingSettings[action.meta.arg.site] = action.meta.arg.value
})
builder.addCase(changeNotificationSettings.pending, (state, action) => {
if (!state.settings) return
state.settings.notificationSettings = {
...state.settings.notificationSettings,
...action.meta.arg,
}
})
builder.addMatcher(
isAnyOf(
@@ -167,7 +175,8 @@ export const userSlice = createSlice({
changeUnreadCountFavicon.fulfilled,
changeDisablePullToRefresh.fulfilled,
changePrimaryColor.fulfilled,
changeSharingSetting.fulfilled
changeSharingSetting.fulfilled,
changeNotificationSettings.fulfilled
),
() => {
showNotification({

View File

@@ -1,7 +1,7 @@
import { createAppAsyncThunk } from "@/app/async-thunk"
import { client } from "@/app/client"
import { reloadEntries } from "@/app/entries/thunks"
import type { IconDisplayMode, ReadingMode, ReadingOrder, ScrollMode, SharingSettings } from "@/app/types"
import type { IconDisplayMode, NotificationSettings, ReadingMode, ReadingOrder, ScrollMode, SharingSettings } from "@/app/types"
export const reloadSettings = createAppAsyncThunk("settings/reload", async () => await client.user.getSettings().then(r => r.data))
@@ -157,3 +157,18 @@ export const changeSharingSetting = createAppAsyncThunk(
})
}
)
export const changeNotificationSettings = createAppAsyncThunk(
"settings/notificationSettings",
(notificationUpdate: Partial<NotificationSettings>, thunkApi) => {
const { settings } = thunkApi.getState().user
if (!settings) return
client.user.saveSettings({
...settings,
notificationSettings: {
...settings.notificationSettings,
...notificationUpdate,
},
})
}
)