diff --git a/apps/mobile/app/screens/notes/common.ts b/apps/mobile/app/screens/notes/common.ts
index e2d48b606..1907dec3a 100644
--- a/apps/mobile/app/screens/notes/common.ts
+++ b/apps/mobile/app/screens/notes/common.ts
@@ -17,19 +17,18 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
+import { db } from "../../common/database";
import { DDS } from "../../services/device-detection";
import { eSendEvent } from "../../services/event-manager";
import Navigation from "../../services/navigation";
import { useMenuStore } from "../../stores/use-menu-store";
+import { NotesScreenParams } from "../../stores/use-navigation-store";
import { useTagStore } from "../../stores/use-tag-store";
-import { db } from "../../common/database";
import { eOnLoadNote } from "../../utils/events";
import { openLinkInBrowser } from "../../utils/functions";
import { tabBarRef } from "../../utils/global-refs";
-import { editorController, editorState } from "../editor/tiptap/utils";
-import { NotesScreenParams } from "../../stores/use-navigation-store";
import { TopicType } from "../../utils/types";
-import { ChangeEmail } from "../../components/sheets/change-email";
+import { editorController, editorState } from "../editor/tiptap/utils";
export function toCamelCase(title: string) {
return title.slice(0, 1).toUpperCase() + title.slice(1);
diff --git a/apps/mobile/app/screens/settings/components.tsx b/apps/mobile/app/screens/settings/components.tsx
index 1b8afe04a..7e0e5f700 100644
--- a/apps/mobile/app/screens/settings/components.tsx
+++ b/apps/mobile/app/screens/settings/components.tsx
@@ -22,12 +22,14 @@ import { AccentColorPicker, HomagePageSelector } from "./appearance";
import { AutomaticBackupsSelector } from "./backup-restore";
import DebugLogs from "./debug";
import { ConfigureToolbar } from "./editor/configure-toolbar";
+import SoundPicker from "./sound-picker";
import { Subscription } from "./subscription";
export const components: { [name: string]: ReactElement } = {
- colorpicker: ,
+ colorpicker: ,
homeselector: ,
autobackups: ,
subscription: ,
configuretoolbar: ,
- "debug-logs":
+ "debug-logs": ,
+ "sound-picker":
};
diff --git a/apps/mobile/app/screens/settings/settings-data.tsx b/apps/mobile/app/screens/settings/settings-data.tsx
index ef5f7c67b..9c3058746 100644
--- a/apps/mobile/app/screens/settings/settings-data.tsx
+++ b/apps/mobile/app/screens/settings/settings-data.tsx
@@ -68,6 +68,9 @@ import { useDragState } from "./editor/state";
import { verifyUser } from "./functions";
import { SettingSection } from "./types";
import { getTimeLeft } from "./user-section";
+import notifee from "@notifee/react-native";
+
+type User = any;
export const settingsGroups: SettingSection[] = [
{
@@ -878,6 +881,30 @@ export const settingsGroups: SettingSection[] = [
Notifications.setupReminders();
}
}
+ },
+ {
+ id: "reminder-sound",
+ type: "screen",
+ name: "Change notification sound",
+ description:
+ "Set the notification sound for reminder notifications",
+ component: "sound-picker",
+ icon: "bell-ring",
+ hidden: () => Platform.OS === "android"
+ },
+ {
+ id: "reminder-sound",
+ name: "Change notification sound",
+ description:
+ "Set the notification sound for reminder notifications",
+ icon: "bell-ring",
+ hidden: () => Platform.OS === "ios",
+ modifer: async () => {
+ const id = await Notifications.getChannelId("urgent");
+ if (id) {
+ await notifee.openNotificationSettings(id);
+ }
+ }
}
]
}
diff --git a/apps/mobile/app/screens/settings/sound-picker.tsx b/apps/mobile/app/screens/settings/sound-picker.tsx
new file mode 100644
index 000000000..ec9173c5a
--- /dev/null
+++ b/apps/mobile/app/screens/settings/sound-picker.tsx
@@ -0,0 +1,170 @@
+/*
+This file is part of the Notesnook project (https://notesnook.com/)
+
+Copyright (C) 2022 Streetwriters (Private) Limited
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+import React, { useEffect, useState } from "react";
+import { FlatList, Platform, View } from "react-native";
+import NotificationSounds, {
+ playSampleSound,
+ Sound,
+ stopSampleSound
+} from "react-native-notification-sounds";
+import Icon from "react-native-vector-icons/MaterialCommunityIcons";
+import { IconButton } from "../../components/ui/icon-button";
+import { PressableButton } from "../../components/ui/pressable";
+import Paragraph from "../../components/ui/typography/paragraph";
+import Notifications from "../../services/notifications";
+import SettingsService from "../../services/settings";
+import { useSettingStore } from "../../stores/use-setting-store";
+import { useThemeStore } from "../../stores/use-theme-store";
+import { SIZE } from "../../utils/size";
+
+const SoundItem = ({
+ playingSoundId,
+ selectedSoundId,
+ item,
+ index,
+ setPlaying
+}: {
+ playingSoundId?: string;
+ selectedSoundId?: string;
+ item: Sound;
+ index: number;
+ setPlaying: (sound: Sound | undefined) => void;
+}) => {
+ const colors = useThemeStore((state) => state.colors);
+ const isPlaying = playingSoundId === item.soundID;
+
+ return (
+ {
+ SettingsService.set({
+ notificationSound:
+ item.soundID === "defaultSound"
+ ? undefined
+ : {
+ ...item,
+ platform: Platform.OS
+ }
+ });
+ Notifications.setupReminders();
+ }}
+ >
+
+
+
+ {item?.title}
+
+
+
+ {item.soundID === "defaultSound" ? null : (
+ {
+ if (isPlaying) {
+ stopSampleSound();
+ } else {
+ playSampleSound(item);
+ setPlaying(item);
+ setTimeout(() => {
+ setPlaying(undefined);
+ stopSampleSound();
+ }, 5 * 1000);
+ }
+ }}
+ />
+ )}
+
+ );
+};
+
+export default function SoundPicker() {
+ const [sounds, setSounds] = useState([]);
+ const [ringtones, setRingtones] = useState([]);
+ const [playing, setPlaying] = useState();
+ const notificationSound = useSettingStore(
+ (state) => state.settings.notificationSound
+ );
+
+ useEffect(() => {
+ NotificationSounds.getNotifications("notification").then((results) =>
+ setSounds([
+ {
+ soundID: "defaultSound",
+ title: "Default sound",
+ url: ""
+ },
+ ...results
+ ])
+ );
+
+ NotificationSounds.getNotifications("ringtone").then((results) =>
+ setRingtones([
+ {
+ soundID: "defaultSound",
+ title: "Default sound",
+ url: ""
+ },
+ ...results
+ ])
+ );
+ }, []);
+
+ return (
+
+ (
+
+ )}
+ />
+
+ );
+}
diff --git a/apps/mobile/app/services/notifications.ts b/apps/mobile/app/services/notifications.ts
index 73e5cb929..94b210f23 100644
--- a/apps/mobile/app/services/notifications.ts
+++ b/apps/mobile/app/services/notifications.ts
@@ -280,8 +280,9 @@ async function scheduleNotification(
)
continue;
const iosProperties: { [name: string]: any } = {};
+ const notificationSound = SettingsService.get().notificationSound;
if (priority === "urgent") {
- iosProperties["sound"] = "default";
+ iosProperties["sound"] = notificationSound?.url || "default";
}
const reminderTime = SettingsService.get().defaultSnoozeTime;
@@ -301,7 +302,6 @@ async function scheduleNotification(
}
});
}
- console.log(trigger);
await notifee.createTriggerNotification(
{
id: trigger.id,
@@ -321,6 +321,7 @@ async function scheduleNotification(
mainComponent: "notesnook"
},
actions: androidActions,
+ sound: notificationSound?.url,
style: !description
? undefined
: {
@@ -330,6 +331,7 @@ async function scheduleNotification(
},
ios: {
interruptionLevel: "active",
+ criticalVolume: 1.0,
critical:
reminder.priority === "silent" || reminder.priority === "urgent"
? false
@@ -363,6 +365,7 @@ function loadNote(id: string, jump: boolean) {
}
async function getChannelId(id: "silent" | "vibrate" | "urgent" | "default") {
+ const notificationSound = SettingsService.get().notificationSound;
switch (id) {
case "default":
return await notifee.createChannel({
@@ -378,15 +381,18 @@ async function getChannelId(id: "silent" | "vibrate" | "urgent" | "default") {
case "vibrate":
return await notifee.createChannel({
id: "com.streetwriters.notesnook.silent",
- name: "Silent",
+ name: "Vibrate",
vibration: true
});
case "urgent":
return await notifee.createChannel({
id: "com.streetwriters.notesnook.urgent",
name: "Urgent",
+ description:
+ "This channel is used to show notifications with sound & vibration.",
vibration: true,
- sound: "default"
+ sound: notificationSound?.url || "default",
+ bypassDnd: true
});
}
}
@@ -775,7 +781,8 @@ const Notifications = {
getScheduledNotificationIds,
checkAndRequestPermissions,
clearAllTriggers,
- setupReminders
+ setupReminders,
+ getChannelId
};
export default Notifications;
diff --git a/apps/mobile/app/stores/use-setting-store.ts b/apps/mobile/app/stores/use-setting-store.ts
index 2538778c7..0e353494d 100644
--- a/apps/mobile/app/stores/use-setting-store.ts
+++ b/apps/mobile/app/stores/use-setting-store.ts
@@ -17,13 +17,14 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-import { Dimensions } from "react-native";
+import { Dimensions,PlatformOSType } from "react-native";
import Config from "react-native-config";
import { FileType } from "react-native-scoped-storage";
import create, { State } from "zustand";
import { ACCENT } from "../utils/color-scheme";
import { initialWindowMetrics } from "react-native-safe-area-context";
import { Reminder } from "../services/notifications";
+import { Sound } from "react-native-notification-sounds";
export type Settings = {
showToolbarOnTop?: boolean;
@@ -70,7 +71,8 @@ export type Settings = {
defaultSnoozeTime?: string;
reminderNotificationMode: Reminder["priority"];
corsProxy: string;
- disableRealtimeSync?:boolean
+ disableRealtimeSync?: boolean;
+ notificationSound?: Sound & { platform: PlatformOSType };
};
type DimensionsType = {
@@ -146,7 +148,8 @@ export const useSettingStore = create((set) => ({
reminderNotifications: true,
defaultSnoozeTime: "5",
corsProxy: "https://cors.notesnook.com",
- reminderNotificationMode: "urgent"
+ reminderNotificationMode: "urgent",
+ notificationSound: undefined
},
sheetKeyboardHandler: true,
fullscreen: false,
diff --git a/apps/mobile/native/package.json b/apps/mobile/native/package.json
index 76330aff9..9cc1770a9 100644
--- a/apps/mobile/native/package.json
+++ b/apps/mobile/native/package.json
@@ -56,7 +56,8 @@
"@ammarahmed/notifee-react-native": "7.3.1",
"react-native-modal-datetime-picker":"14.0.0",
"@react-native-community/datetimepicker":"6.6.0",
- "react-native-date-picker": "4.2.6"
+ "react-native-date-picker": "4.2.6",
+ "react-native-notification-sounds": "0.5.5"
},
"devDependencies": {
diff --git a/apps/mobile/package-lock.json b/apps/mobile/package-lock.json
index cdc75779c..fe2bbfc2c 100644
--- a/apps/mobile/package-lock.json
+++ b/apps/mobile/package-lock.json
@@ -98,6 +98,7 @@
"react-native-keychain": "4.0.5",
"react-native-mmkv-storage": "^0.8.0",
"react-native-modal-datetime-picker": "14.0.0",
+ "react-native-notification-sounds": "0.5.5",
"react-native-orientation": "https://github.com/yamill/react-native-orientation.git",
"react-native-privacy-snapshot": "https://github.com/standardnotes/react-native-privacy-snapshot.git",
"react-native-reanimated": "2.13.0",
@@ -18424,6 +18425,15 @@
"react-native": ">=0.65.0"
}
},
+ "node_modules/react-native-notification-sounds": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/react-native-notification-sounds/-/react-native-notification-sounds-0.5.5.tgz",
+ "integrity": "sha512-Pw4mRDbusYVmi8+Cwxcpx1BI9gwFY4CpWx8N+gMNDd1n7WRJS/Shi3Igo1luo3zLPkVVrpyZbpuZaE8cG9Q3Cg==",
+ "peerDependencies": {
+ "react": "^16.8.1",
+ "react-native": ">=0.64.1"
+ }
+ },
"node_modules/react-native-orientation": {
"version": "3.1.3",
"resolved": "git+ssh://git@github.com/yamill/react-native-orientation.git#b45830cce0837fa668838554e023979497673c82",
@@ -24392,6 +24402,7 @@
"react-native-keychain": "4.0.5",
"react-native-mmkv-storage": "^0.8.0",
"react-native-modal-datetime-picker": "14.0.0",
+ "react-native-notification-sounds": "0.5.5",
"react-native-orientation": "https://github.com/yamill/react-native-orientation.git",
"react-native-privacy-snapshot": "https://github.com/standardnotes/react-native-privacy-snapshot.git",
"react-native-reanimated": "2.13.0",
@@ -35176,6 +35187,11 @@
"prop-types": "^15.7.2"
}
},
+ "react-native-notification-sounds": {
+ "version": "0.5.5",
+ "resolved": "https://registry.npmjs.org/react-native-notification-sounds/-/react-native-notification-sounds-0.5.5.tgz",
+ "integrity": "sha512-Pw4mRDbusYVmi8+Cwxcpx1BI9gwFY4CpWx8N+gMNDd1n7WRJS/Shi3Igo1luo3zLPkVVrpyZbpuZaE8cG9Q3Cg=="
+ },
"react-native-orientation": {
"version": "git+ssh://git@github.com/yamill/react-native-orientation.git#b45830cce0837fa668838554e023979497673c82",
"from": "react-native-orientation@https://github.com/yamill/react-native-orientation.git"