mobile: add reminder screen

This commit is contained in:
Ammar Ahmed
2026-07-11 11:22:57 +05:00
committed by Abdullah Atta
parent cb7c63b9ae
commit e6db31eb8b
10 changed files with 884 additions and 620 deletions

View File

@@ -101,7 +101,7 @@ export const SectionHeader = React.memo<
alignSelf: "center",
textAlignVertical: "center"
}}
color={colors.secondary.paragraph}
color={colors.primary.accent}
>
{!item.title || item.title === ""
? screen === "Search"

View File

@@ -16,28 +16,28 @@ 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 <http://www.gnu.org/licenses/>.
*/
import { getFormattedReminderTime } from "@notesnook/common";
import { Reminder } from "@notesnook/core";
import { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React from "react";
import React, { useState } from "react";
import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { notesnook } from "../../../../e2e/test.ids";
import { Radius, Spacing } from "../../../common/design/spacing";
import useIsSelected from "../../../hooks/use-selected";
import AddReminder from "../../../screens/add-reminder";
import { eSendEvent } from "../../../services/event-manager";
import { useSelectionStore } from "../../../stores/use-selection-store";
import {
selectItem,
useSelectionStore
} from "../../../stores/use-selection-store";
import { eCloseSheet } from "../../../utils/events";
import { AppFontSize, defaultBorderRadius } from "../../../utils/size";
import { DefaultAppStyles } from "../../../utils/styles";
import { Properties } from "../../properties";
import AppIcon from "../../ui/AppIcon";
import { IconButton } from "../../ui/icon-button";
import { ReminderTime } from "../../ui/reminder-time";
import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
import SelectionWrapper from "../selection-wrapper";
import { selectItem } from "../../../stores/use-selection-store";
const ReminderItem = React.memo(
({
@@ -50,6 +50,7 @@ const ReminderItem = React.memo(
isSheet: boolean;
}) => {
const { colors } = useThemeColors();
const [checked, setChecked] = useState(false);
const openReminder = () => {
if (selectItem(item)) return;
AddReminder.present(item, undefined);
@@ -59,148 +60,129 @@ const ReminderItem = React.memo(
};
const selectionMode = useSelectionStore((state) => state.selectionMode);
const [selected] = useIsSelected(item);
// Subtitle segments (reminder time · recurring mode · disabled), rendered as
// plain text separated by a dot to match the redesign.
const subtitleSegments = [
getFormattedReminderTime(item, false),
item.mode === "repeat" && item.recurringMode
? strings.reminderRecurringMode[item.recurringMode]()
: undefined,
item.disabled ? strings.disabled() : undefined
].filter(Boolean) as string[];
return (
<SelectionWrapper onPress={openReminder} item={item} isSheet={isSheet}>
<SelectionWrapper
onPress={() => {
if (selectItem(item)) return;
setChecked(!checked);
}}
item={item}
isSheet={isSheet}
hideSeparator
style={{
borderWidth: 1,
borderColor: colors.primary.border,
borderRadius: Radius.S,
marginBottom: Spacing.LEVEL_2,
backgroundColor: selected ? colors.primary.shade : undefined
}}
wrapperStyle={{
paddingHorizontal: Spacing.LEVEL_3
}}
>
{/* Leading "done" checkbox — visual only for now, not yet wired. */}
<AppIcon
name={checked ? "checkbox" : "box-empty"}
iconFamily="notesnook"
color={
checked
? [colors.primary.accent, colors.primary.accentForeground]
: colors.primary.icon
}
size={16}
style={{
marginRight: Spacing.LEVEL_1
}}
/>
<View
style={{
opacity: item.disabled ? 0.5 : 1,
maxWidth: "80%",
flexGrow: 1
flexGrow: 1,
flexShrink: 1,
gap: Spacing.LEVEL_1,
opacity: item.disabled ? 0.5 : 1
}}
>
<Heading
numberOfLines={1}
<View
style={{
flexWrap: "wrap"
flexDirection: "row",
justifyContent: "space-between"
}}
size={AppFontSize.md}
>
{item.title}
</Heading>
<Heading
fontSize="MD"
style={{
flexShrink: 1
}}
color={colors.primary.heading}
>
{item.title}
</Heading>
<IconButton
testID={notesnook.listitem.menu}
color={colors.secondary.icon}
name="dots-three"
iconFamily="notesnook"
size={20}
onPress={() => Properties.present(item, isSheet)}
style={{
justifyContent: "center",
height: undefined,
width: undefined,
borderRadius: 100,
alignItems: "center"
}}
/>
</View>
{item.description ? (
<Paragraph
style={{
flexWrap: "wrap"
}}
numberOfLines={2}
>
{item.description}
</Paragraph>
<Paragraph fontSize="SM">{item.description}</Paragraph>
) : null}
<View
style={{
flexDirection: "row",
alignItems: "center",
flexWrap: "wrap",
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL
gap: Spacing.LEVEL_1
}}
>
{item.disabled ? (
<View
style={{
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius,
flexDirection: "row",
paddingHorizontal: DefaultAppStyles.GAP_SMALL,
alignItems: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL,
justifyContent: "flex-start",
alignSelf: "flex-start",
marginRight: 10,
height: 30
}}
>
<Icon
name="bell-off-outline"
size={AppFontSize.md}
color={colors.error.icon}
/>
{subtitleSegments.map((segment, i) => (
<React.Fragment key={segment}>
{i > 0 ? (
<View
style={{
width: 4,
height: 4,
borderRadius: 100,
backgroundColor: colors.secondary.icon
}}
/>
) : null}
<Paragraph
size={AppFontSize.xs}
fontSize="SM"
lineHeight="100%"
color={colors.secondary.paragraph}
style={{ marginLeft: 5 }}
>
{strings.disabled()}
{segment}
</Paragraph>
</View>
) : null}
{item.mode === "repeat" && item.recurringMode ? (
<View
style={{
backgroundColor: colors.secondary.background,
borderRadius: defaultBorderRadius,
flexDirection: "row",
paddingHorizontal: DefaultAppStyles.GAP_SMALL,
alignItems: "center",
marginTop: DefaultAppStyles.GAP_VERTICAL_SMALL,
justifyContent: "flex-start",
alignSelf: "flex-start",
marginRight: DefaultAppStyles.GAP_SMALL,
height: 30
}}
>
<Icon
name="reload"
size={AppFontSize.md}
color={colors.primary.accent}
/>
<Paragraph
size={AppFontSize.xs}
color={colors.secondary.paragraph}
style={{ marginLeft: 5 }}
>
{strings.reminderRecurringMode[item.recurringMode]()}
</Paragraph>
</View>
) : null}
<ReminderTime
reminder={item}
checkIsActive={false}
fontSize={AppFontSize.xxs}
style={{
justifyContent: "flex-start",
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL / 2,
alignSelf: "flex-start"
}}
/>
</React.Fragment>
))}
</View>
</View>
{selectionMode === "note" || selectionMode === "trash" ? (
<>
<View
style={{
height: 35,
width: 35,
alignItems: "center",
justifyContent: "center"
}}
>
<AppIcon
name={selected ? "checkbox-outline" : "checkbox-blank-outline"}
color={selected ? colors.selected.icon : colors.primary.icon}
size={AppFontSize.lg}
/>
</View>
</>
) : (
<IconButton
testID={notesnook.listitem.menu}
color={colors.primary.paragraph}
name="dots-horizontal"
size={AppFontSize.xl}
onPress={() => Properties.present(item, isSheet)}
style={{
justifyContent: "center",
height: 35,
width: 35,
borderRadius: 100,
alignItems: "center"
}}
/>
)}
</SelectionWrapper>
);
},

View File

@@ -24,7 +24,7 @@ import { useIsCompactModeEnabled } from "../../../hooks/use-is-compact-mode-enab
import { useTabStore } from "../../../screens/editor/tiptap/use-tab-store";
import { useSelectionStore } from "../../../stores/use-selection-store";
import { Pressable } from "../../ui/pressable";
import { View } from "react-native";
import { View, ViewStyle } from "react-native";
import { Spacing } from "../../../common/design/spacing";
type SelectionWrapperProps = PropsWithChildren<{
@@ -35,6 +35,9 @@ type SelectionWrapperProps = PropsWithChildren<{
color?: string;
index?: number;
hasGroupHeader?: boolean;
style?: ViewStyle;
wrapperStyle?: ViewStyle;
hideSeparator?: boolean;
}>;
const SelectionWrapper = ({
@@ -45,7 +48,10 @@ const SelectionWrapper = ({
children,
color,
hasGroupHeader,
index = 0
index = 0,
style,
wrapperStyle,
hideSeparator
}: SelectionWrapperProps) => {
const itemId = useRef(item.id);
const { colors, isDark } = useThemeColors();
@@ -72,7 +78,7 @@ const SelectionWrapper = ({
return (
<>
{hasGroupHeader ? null : (
{hasGroupHeader || hideSeparator ? null : (
<View
style={{
paddingHorizontal: Spacing.LEVEL_3
@@ -91,7 +97,8 @@ const SelectionWrapper = ({
style={{
backgroundColor: isEditingNote
? colors.selected.background
: undefined
: undefined,
...wrapperStyle
}}
>
<Pressable
@@ -106,7 +113,8 @@ const SelectionWrapper = ({
style={{
paddingHorizontal: Spacing.LEVEL_3,
paddingBottom: Spacing.LEVEL_2,
paddingTop: hasGroupHeader ? 0 : Spacing.LEVEL_2
paddingTop: hasGroupHeader ? 0 : Spacing.LEVEL_2,
...style
}}
>
<View

View File

@@ -60,6 +60,7 @@ const BOTTOM_BAR_ITEMS: ActionId[] = [
"duplicate",
"launcher-shortcut",
"expiry-date",
"disable-reminder",
"trash"
];

View File

@@ -506,10 +506,8 @@ export const useActions = ({
actions.push(
{
id: "disable-reminder",
title: !item.disabled
? strings.turnOffReminder()
: strings.turnOnReminder(),
icon: !item.disabled ? "bell-off-outline" : "bell",
title: !item.disabled ? strings.disable() : strings.enable(),
icon: !item.disabled ? "bell-z" : "bell",
onPress: async () => {
close();
await db.reminders.add({
@@ -524,7 +522,7 @@ export const useActions = ({
{
id: "edit-reminder",
title: strings.editReminder(),
icon: "pencil",
icon: "pencil-simple",
onPress: async () => {
AddReminder.present(item);
close();

File diff suppressed because it is too large Load Diff

View File

@@ -538,6 +538,10 @@ msgstr "{mode, select, create {Create app lock {keyboardType}} change {Change ap
msgid "{mode, select, day {Daily} week {Weekly} month {Monthly} year {Yearly} other {Unknown mode}}"
msgstr "{mode, select, day {Daily} week {Weekly} month {Monthly} year {Yearly} other {Unknown mode}}"
#: src/strings.ts:2991
msgid "{mode, select, once {The reminder will occur once.} day {The reminder will occur daily.} week {Custom schedule active} month {Custom schedule active} year {The reminder will repeat every year.} other {}}"
msgstr "{mode, select, once {The reminder will occur once.} day {The reminder will occur daily.} week {Custom schedule active} month {Custom schedule active} year {The reminder will repeat every year.} other {}}"
#: src/strings.ts:622
msgid "{mode, select, repeat {Repeat} once {Once} permanent {Permanent} other {Unknown mode}}"
msgstr "{mode, select, repeat {Repeat} once {Once} permanent {Permanent} other {Unknown mode}}"
@@ -766,6 +770,10 @@ msgstr "Add shortcut"
msgid "Add shortcuts for notebooks and tags here."
msgstr "Add shortcuts for notebooks and tags here."
#: src/strings.ts:3013
msgid "Add some details..."
msgstr "Add some details..."
#: src/strings.ts:596
msgid "Add tag"
msgstr "Add tag"
@@ -803,6 +811,10 @@ msgstr "Add your first notebook"
msgid "Adjust the line height of the editor"
msgstr "Adjust the line height of the editor"
#: src/strings.ts:3002
msgid "Adjusts to last day in shorter months"
msgstr "Adjusts to last day in shorter months"
#: src/strings.ts:2232
msgid "Advanced"
msgstr "Advanced"
@@ -819,6 +831,10 @@ msgstr "Advanced settings"
msgid "After scanning the QR code image, the app will display a code that you can enter below."
msgstr "After scanning the QR code image, the app will display a code that you can enter below."
#: src/strings.ts:3010
msgid "Alert mode"
msgstr "Alert mode"
#: src/strings.ts:2371
msgid "Align left"
msgstr "Align left"
@@ -895,6 +911,10 @@ msgstr "All tools in this group will be removed from the toolbar."
msgid "All your backups are stored in 'Phone Storage/Notesnook/backups/' folder"
msgstr "All your backups are stored in 'Phone Storage/Notesnook/backups/' folder"
#: src/strings.ts:3008
msgid "All-day reminder"
msgstr "All-day reminder"
#: src/strings.ts:108
msgid "Already have an account?"
msgstr "Already have an account?"
@@ -2150,6 +2170,10 @@ msgstr "Create new key"
msgid "Create notebook"
msgstr "Create notebook"
#: src/strings.ts:3014
msgid "Create Reminder"
msgstr "Create Reminder"
#: src/strings.ts:1519
msgid "Create shortcut of this notebook in side menu"
msgstr "Create shortcut of this notebook in side menu"
@@ -4549,6 +4573,10 @@ msgstr "Monthly"
msgid "More"
msgstr "More"
#: src/strings.ts:3007
msgid "More options"
msgstr "More options"
#: src/strings.ts:669
msgid "Most relevant first"
msgstr "Most relevant first"
@@ -5950,6 +5978,10 @@ msgstr "Reload app"
msgid "Relogin to your Account"
msgstr "Relogin to your Account"
#: src/strings.ts:3009
msgid "Remains active throughout the day."
msgstr "Remains active throughout the day."
#: src/strings.ts:1847
msgid "Remembered your password?"
msgstr "Remembered your password?"
@@ -5979,6 +6011,10 @@ msgstr "reminder"
msgid "Reminder"
msgstr "Reminder"
#: src/strings.ts:2989
msgid "Reminder frequency"
msgstr "Reminder frequency"
#: src/strings.ts:1292
msgid "Reminder notifications"
msgstr "Reminder notifications"
@@ -6547,10 +6583,22 @@ msgstr "Select backups folder"
msgid "Select date"
msgstr "Select date"
#: src/strings.ts:3003
msgid "Select date & time"
msgstr "Select date & time"
#: src/strings.ts:3005
msgid "Select Dates"
msgstr "Select Dates"
#: src/strings.ts:351
msgid "Select day of the week to repeat the reminder."
msgstr "Select day of the week to repeat the reminder."
#: src/strings.ts:2999
msgid "Select Days"
msgstr "Select Days"
#: src/strings.ts:1814
msgid "Select files to import"
msgstr "Select files to import"
@@ -6615,6 +6663,14 @@ msgstr "Select the languages the spell checker should check in."
msgid "Select the release track for Notesnook."
msgstr "Select the release track for Notesnook."
#: src/strings.ts:3004
msgid "Select time"
msgstr "Select time"
#: src/strings.ts:3006
msgid "Select Time"
msgstr "Select Time"
#: src/strings.ts:2980
msgid "Selected note"
msgstr "Selected note"
@@ -6849,6 +6905,10 @@ msgstr "Share to cloud"
msgid "Share ZIP"
msgstr "Share ZIP"
#: src/strings.ts:3011
msgid "Short Detail"
msgstr "Short Detail"
#: src/strings.ts:305
msgid "shortcut"
msgstr "shortcut"
@@ -7380,6 +7440,10 @@ msgstr "The password for decrypting the Colornote backup file."
msgid "The password/pin for unlocking the app."
msgstr "The password/pin for unlocking the app."
#: src/strings.ts:3001
msgid "The reminder will occur on the selected day."
msgstr "The reminder will occur on the selected day."
#: src/strings.ts:350
msgid "The reminder will repeat daily at {date}."
msgstr "The reminder will repeat daily at {date}."
@@ -8234,6 +8298,10 @@ msgstr "What happens to my data if I switch plans?"
msgid "What is your refund policy?"
msgstr "What is your refund policy?"
#: src/strings.ts:3012
msgid "What needs to be done?"
msgstr "What needs to be done?"
#: src/strings.ts:1718
msgid "What went wrong?"
msgstr "What went wrong?"

View File

@@ -538,6 +538,10 @@ msgstr ""
msgid "{mode, select, day {Daily} week {Weekly} month {Monthly} year {Yearly} other {Unknown mode}}"
msgstr ""
#: src/strings.ts:2991
msgid "{mode, select, once {The reminder will occur once.} day {The reminder will occur daily.} week {Custom schedule active} month {Custom schedule active} year {The reminder will repeat every year.} other {}}"
msgstr ""
#: src/strings.ts:622
msgid "{mode, select, repeat {Repeat} once {Once} permanent {Permanent} other {Unknown mode}}"
msgstr ""
@@ -766,6 +770,10 @@ msgstr ""
msgid "Add shortcuts for notebooks and tags here."
msgstr ""
#: src/strings.ts:3013
msgid "Add some details..."
msgstr ""
#: src/strings.ts:596
msgid "Add tag"
msgstr ""
@@ -803,6 +811,10 @@ msgstr ""
msgid "Adjust the line height of the editor"
msgstr ""
#: src/strings.ts:3002
msgid "Adjusts to last day in shorter months"
msgstr ""
#: src/strings.ts:2232
msgid "Advanced"
msgstr ""
@@ -819,6 +831,10 @@ msgstr ""
msgid "After scanning the QR code image, the app will display a code that you can enter below."
msgstr ""
#: src/strings.ts:3010
msgid "Alert mode"
msgstr ""
#: src/strings.ts:2371
msgid "Align left"
msgstr ""
@@ -895,6 +911,10 @@ msgstr ""
msgid "All your backups are stored in 'Phone Storage/Notesnook/backups/' folder"
msgstr ""
#: src/strings.ts:3008
msgid "All-day reminder"
msgstr ""
#: src/strings.ts:108
msgid "Already have an account?"
msgstr ""
@@ -2139,6 +2159,10 @@ msgstr ""
msgid "Create notebook"
msgstr ""
#: src/strings.ts:3014
msgid "Create Reminder"
msgstr ""
#: src/strings.ts:1519
msgid "Create shortcut of this notebook in side menu"
msgstr ""
@@ -4529,6 +4553,10 @@ msgstr ""
msgid "More"
msgstr ""
#: src/strings.ts:3007
msgid "More options"
msgstr ""
#: src/strings.ts:669
msgid "Most relevant first"
msgstr ""
@@ -5924,6 +5952,10 @@ msgstr ""
msgid "Relogin to your Account"
msgstr ""
#: src/strings.ts:3009
msgid "Remains active throughout the day."
msgstr ""
#: src/strings.ts:1847
msgid "Remembered your password?"
msgstr ""
@@ -5953,6 +5985,10 @@ msgstr ""
msgid "Reminder"
msgstr ""
#: src/strings.ts:2989
msgid "Reminder frequency"
msgstr ""
#: src/strings.ts:1292
msgid "Reminder notifications"
msgstr ""
@@ -6521,10 +6557,22 @@ msgstr ""
msgid "Select date"
msgstr ""
#: src/strings.ts:3003
msgid "Select date & time"
msgstr ""
#: src/strings.ts:3005
msgid "Select Dates"
msgstr ""
#: src/strings.ts:351
msgid "Select day of the week to repeat the reminder."
msgstr ""
#: src/strings.ts:2999
msgid "Select Days"
msgstr ""
#: src/strings.ts:1814
msgid "Select files to import"
msgstr ""
@@ -6589,6 +6637,14 @@ msgstr ""
msgid "Select the release track for Notesnook."
msgstr ""
#: src/strings.ts:3004
msgid "Select time"
msgstr ""
#: src/strings.ts:3006
msgid "Select Time"
msgstr ""
#: src/strings.ts:2980
msgid "Selected note"
msgstr ""
@@ -6815,6 +6871,10 @@ msgstr ""
msgid "Share ZIP"
msgstr ""
#: src/strings.ts:3011
msgid "Short Detail"
msgstr ""
#: src/strings.ts:305
msgid "shortcut"
msgstr ""
@@ -7339,6 +7399,10 @@ msgstr ""
msgid "The password/pin for unlocking the app."
msgstr ""
#: src/strings.ts:3001
msgid "The reminder will occur on the selected day."
msgstr ""
#: src/strings.ts:350
msgid "The reminder will repeat daily at {date}."
msgstr ""
@@ -8184,6 +8248,10 @@ msgstr ""
msgid "What is your refund policy?"
msgstr ""
#: src/strings.ts:3012
msgid "What needs to be done?"
msgstr ""
#: src/strings.ts:1718
msgid "What went wrong?"
msgstr ""

View File

@@ -2985,5 +2985,31 @@ Continue without attachments?`,
linkedReferences: () => t`Linked References`,
selectParagraphs: () => t`Select paragraphs`,
addLink: () => t`Add Link`,
linkAdded: () => t`Link added`
linkAdded: () => t`Link added`,
reminderFrequency: () => t`Reminder frequency`,
reminderFrequencyDescription: (mode: string) =>
select(mode, {
once: "The reminder will occur once.",
day: "The reminder will occur daily.",
week: "Custom schedule active",
month: "Custom schedule active",
year: "The reminder will repeat every year.",
other: ""
}),
reminderSelectDays: () => t`Select Days`,
reminderSelectedDayHelp: () =>
t`The reminder will occur on the selected day.`,
reminderSelecetDateHelp: () => t`Adjusts to last day in shorter months`,
selectDateAndTime: () => t`Select date & time`,
selectTimeHeading: () => t`Select time`,
selectDatesPlaceholder: () => t`Select Dates`,
selectTimePlaceholder: () => t`Select Time`,
moreOptions: () => t`More options`,
allDayReminder: () => t`All-day reminder`,
allDayReminderDescription: () => t`Remains active throughout the day.`,
alertMode: () => t`Alert mode`,
reminderShortDetail: () => t`Short Detail`,
reminderTitlePlaceholder: () => t`What needs to be done?`,
reminderDetailsPlaceholder: () => t`Add some details...`,
createReminder: () => t`Create Reminder`
};