Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 19 additions & 18 deletions app/folder/[id].tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useCallback, useEffect, useState } from 'react';
import { ActivityIndicator, Alert, ScrollView, StyleSheet, View } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { t } from '../../src/i18n';
import { useFocusEffect, useLocalSearchParams, useRouter } from 'expo-router';
import * as Haptics from 'expo-haptics';
import { LibraryHeader } from '../../src/components/library/LibraryHeader';
Expand Down Expand Up @@ -91,28 +92,28 @@ export default function FolderScreen() {
}
} catch (error) {
if (__DEV__) console.warn('[FolderScreen] create note failed', error);
Alert.alert('Could not create note', 'Please try again.');
Alert.alert(t.library.couldNotCreateNote, t.common.pleaseTryAgain);
} finally {
creatingNoteRef.current = false;
}
}, [folder, router]);

const confirmDeleteNote = useCallback((note: NoteMetadata) => {
Alert.alert(
'Delete note?',
`"${note.title}" will be permanently deleted.`,
t.library.deleteNoteTitle,
t.library.deleteNoteMessage(note.title),
[
{ text: 'Cancel', style: 'cancel' },
{ text: t.common.cancel, style: 'cancel' },
{
text: 'Delete',
text: t.common.delete,
style: 'destructive',
onPress: async () => {
try {
await deleteNote(note.id);
await refresh();
} catch (error) {
if (__DEV__) console.warn('[FolderScreen] delete note failed', error);
Alert.alert('Could not delete note', 'Please try again.');
Alert.alert(t.library.couldNotDeleteNote, t.common.pleaseTryAgain);
}
},
},
Expand All @@ -127,7 +128,7 @@ export default function FolderScreen() {
style={[styles.flex, { backgroundColor: theme.colors.background }]}
>
<LibraryHeader
title="Folder"
title={t.common.folder}
showBack
onBack={() => router.replace('/')}
/>
Expand All @@ -141,7 +142,7 @@ export default function FolderScreen() {
return (
<SafeAreaView edges={['top']} style={[styles.flex, { backgroundColor: theme.colors.background }]}>
<LibraryHeader
title={folder?.name ?? 'Folder'}
title={folder?.name ?? t.common.folder}
showBack
onBack={() => router.replace('/')}
rightIcon="create-outline"
Expand All @@ -150,8 +151,8 @@ export default function FolderScreen() {

{notes.length === 0 ? (
<EmptyState
title="Empty folder"
subtitle={`Tap the plus button to add a note to ${folder?.name ?? 'this folder'}.`}
title={t.library.emptyFolderTitle}
subtitle={t.library.emptyFolderSubtitle(folder?.name ?? t.library.thisFolder)}
iconName="folder-open-outline"
/>
) : (
Expand Down Expand Up @@ -194,25 +195,25 @@ export default function FolderScreen() {
? [
{
key: 'rename',
label: 'Rename',
label: t.common.rename,
onPress: () => setAction({ kind: 'renameNote', note: action.note }),
},
{
key: 'moveRoot',
label: 'Move to Root',
label: t.library.moveToRoot,
onPress: async () => {
await moveNote(action.note.id, null);
await refresh();
},
},
{
key: 'move',
label: 'Move to Folder',
label: t.library.moveToFolder,
onPress: () => setAction({ kind: 'moveNote', note: action.note }),
},
{
key: 'delete',
label: 'Delete',
label: t.common.delete,
destructive: true,
onPress: () => confirmDeleteNote(action.note),
},
Expand All @@ -224,9 +225,9 @@ export default function FolderScreen() {

<RenameDialog
visible={action?.kind === 'renameNote'}
title="Rename note"
title={t.library.renameNoteTitle}
initialValue={action?.kind === 'renameNote' ? action.note.title : ''}
placeholder="Note title"
placeholder={t.library.noteTitlePlaceholder}
onCancel={() => setAction(null)}
onConfirm={async (value) => {
if (action?.kind === 'renameNote') {
Expand All @@ -239,9 +240,9 @@ export default function FolderScreen() {

<RenameDialog
visible={action?.kind === 'renameFolder'}
title="Rename folder"
title={t.library.renameFolderTitle}
initialValue={folder?.name ?? ''}
placeholder="Folder name"
placeholder={t.library.folderNamePlaceholder}
onCancel={() => setAction(null)}
onConfirm={async (value) => {
if (folder) {
Expand Down
76 changes: 38 additions & 38 deletions app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
renameFolder,
} from '../src/services/foldersRepo';
import type { BackgroundType, FolderMetadata, NoteMetadata } from '../src/types/note';
import { t } from '../src/i18n';

type Action =
| { kind: 'newItem' }
Expand Down Expand Up @@ -160,7 +161,7 @@ export default function LibraryScreen() {
}
} catch (error) {
if (__DEV__) console.warn('[LibraryScreen] create note failed', error);
Alert.alert('Could not create note', 'Please try again.');
Alert.alert(t.library.couldNotCreateNote, t.common.pleaseTryAgain);
} finally {
creatingNoteRef.current = false;
}
Expand All @@ -172,20 +173,20 @@ export default function LibraryScreen() {

const confirmDeleteNote = useCallback((note: NoteMetadata) => {
Alert.alert(
'Delete note?',
`"${note.title}" will be permanently deleted.`,
t.library.deleteNoteTitle,
t.library.deleteNoteMessage(note.title),
[
{ text: 'Cancel', style: 'cancel' },
{ text: t.common.cancel, style: 'cancel' },
{
text: 'Delete',
text: t.common.delete,
style: 'destructive',
onPress: async () => {
try {
await deleteNote(note.id);
await refresh();
} catch (error) {
if (__DEV__) console.warn('[LibraryScreen] delete note failed', error);
Alert.alert('Could not delete note', 'Please try again.');
Alert.alert(t.library.couldNotDeleteNote, t.common.pleaseTryAgain);
}
},
},
Expand All @@ -195,20 +196,20 @@ export default function LibraryScreen() {

const confirmDeleteFolderKeepNotes = useCallback((folder: FolderMetadata) => {
Alert.alert(
'Delete folder?',
`"${folder.name}" will be deleted. Its notes will stay in your library.`,
t.library.deleteFolderTitle,
t.library.deleteFolderMessage(folder.name),
[
{ text: 'Cancel', style: 'cancel' },
{ text: t.common.cancel, style: 'cancel' },
{
text: 'Delete Folder',
text: t.library.deleteFolderLabel,
style: 'destructive',
onPress: async () => {
try {
await deleteFolder(folder.id, 'orphan-notes');
await refresh();
} catch (error) {
if (__DEV__) console.warn('[LibraryScreen] delete folder failed', error);
Alert.alert('Could not delete folder', 'Please try again.');
Alert.alert(t.library.couldNotDeleteFolder, t.common.pleaseTryAgain);
}
},
},
Expand All @@ -217,22 +218,21 @@ export default function LibraryScreen() {
}, [refresh]);

const confirmDeleteFolderAndNotes = useCallback((folder: FolderMetadata, noteCount: number) => {
const noteText = noteCount === 1 ? '1 note' : `${noteCount} notes`;
Alert.alert(
'Delete folder and notes?',
`"${folder.name}" and ${noteText} inside it will be permanently deleted.`,
t.library.deleteFolderAndNotesTitle,
t.library.deleteFolderAndNotesMessage(folder.name, t.library.noteCount(noteCount)),
[
{ text: 'Cancel', style: 'cancel' },
{ text: t.common.cancel, style: 'cancel' },
{
text: 'Delete All',
text: t.library.deleteAllLabel,
style: 'destructive',
onPress: async () => {
try {
await deleteFolder(folder.id, 'delete-notes');
await refresh();
} catch (error) {
if (__DEV__) console.warn('[LibraryScreen] delete folder notes failed', error);
Alert.alert('Could not delete folder', 'Please try again.');
Alert.alert(t.library.couldNotDeleteFolder, t.common.pleaseTryAgain);
}
},
},
Expand All @@ -248,7 +248,7 @@ export default function LibraryScreen() {
{
key: 'openNotes',
icon: 'heart-outline',
accessibilityLabel: 'Support OpenNotes',
accessibilityLabel: t.library.supportA11y,
onPress: () => setAction({ kind: 'openNotes' }),
},
]}
Expand All @@ -259,8 +259,8 @@ export default function LibraryScreen() {
</View>
) : sortedFolders.length === 0 && rootNotes.length === 0 ? (
<EmptyState
title="No notes yet"
subtitle="Tap the plus button to create your first note or folder."
title={t.library.emptyTitle}
subtitle={t.library.emptySubtitle}
iconName="document-outline"
/>
) : (
Expand All @@ -269,7 +269,7 @@ export default function LibraryScreen() {
showsVerticalScrollIndicator={false}
>
{sortedFolders.length > 0 ? (
<LibrarySection title="Folders">
<LibrarySection title={t.library.foldersSection}>
<View style={styles.list}>
{sortedFolders.map((folder) => (
<FolderCard
Expand All @@ -289,7 +289,7 @@ export default function LibraryScreen() {
) : null}

{rootNotes.length > 0 ? (
<LibrarySection title={sortedFolders.length > 0 ? 'Notes' : ''}>
<LibrarySection title={sortedFolders.length > 0 ? t.library.notesSection : ''}>
<View style={styles.list}>
{rootNotes.map((note) => (
<NoteCard
Expand Down Expand Up @@ -341,16 +341,16 @@ export default function LibraryScreen() {

<ItemActionsMenu
visible={action?.kind === 'newItem'}
title="Create"
title={t.library.createTitle}
actions={[
{
key: 'note',
label: 'New Note',
label: t.library.newNote,
onPress: () => setAction({ kind: 'createNoteBackground' }),
},
{
key: 'folder',
label: 'New Folder',
label: t.library.newFolder,
onPress: handleCreateFolder,
},
]}
Expand All @@ -371,17 +371,17 @@ export default function LibraryScreen() {
? [
{
key: 'rename',
label: 'Rename',
label: t.common.rename,
onPress: () => setAction({ kind: 'renameNote', note: action.note }),
},
{
key: 'move',
label: 'Move to Folder',
label: t.library.moveToFolder,
onPress: () => setAction({ kind: 'moveNote', note: action.note }),
},
{
key: 'delete',
label: 'Delete',
label: t.common.delete,
destructive: true,
onPress: () => confirmDeleteNote(action.note),
},
Expand All @@ -399,19 +399,19 @@ export default function LibraryScreen() {
? [
{
key: 'rename',
label: 'Rename',
label: t.common.rename,
onPress: () =>
setAction({ kind: 'renameFolder', folder: action.folder }),
},
{
key: 'orphan',
label: 'Delete (keep notes)',
label: t.library.deleteKeepNotesLabel,
destructive: true,
onPress: () => confirmDeleteFolderKeepNotes(action.folder),
},
{
key: 'deleteNotes',
label: 'Delete folder and all notes',
label: t.library.deleteFolderAndNotesLabel,
destructive: true,
onPress: () =>
confirmDeleteFolderAndNotes(
Expand All @@ -427,9 +427,9 @@ export default function LibraryScreen() {

<RenameDialog
visible={action?.kind === 'renameNote'}
title="Rename note"
title={t.library.renameNoteTitle}
initialValue={action?.kind === 'renameNote' ? action.note.title : ''}
placeholder="Note title"
placeholder={t.library.noteTitlePlaceholder}
onCancel={() => setAction(null)}
onConfirm={async (value) => {
if (action?.kind === 'renameNote') {
Expand All @@ -442,9 +442,9 @@ export default function LibraryScreen() {

<RenameDialog
visible={action?.kind === 'renameFolder'}
title="Rename folder"
title={t.library.renameFolderTitle}
initialValue={action?.kind === 'renameFolder' ? action.folder.name : ''}
placeholder="Folder name"
placeholder={t.library.folderNamePlaceholder}
onCancel={() => setAction(null)}
onConfirm={async (value) => {
if (action?.kind === 'renameFolder') {
Expand All @@ -457,10 +457,10 @@ export default function LibraryScreen() {

<RenameDialog
visible={action?.kind === 'createFolder'}
title="New folder"
title={t.library.newFolderTitle}
initialValue=""
placeholder="Folder name"
confirmLabel="Create"
placeholder={t.library.folderNamePlaceholder}
confirmLabel={t.common.create}
onCancel={() => setAction(null)}
onConfirm={async (value) => {
if (!value.trim()) {
Expand Down
2 changes: 2 additions & 0 deletions ios/OpenNotes.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoLocalization/ExpoLocalization_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage/RNCAsyncStorage_resources.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle",
Expand All @@ -299,6 +300,7 @@
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoLocalization_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCAsyncStorage_resources.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle",
Expand Down
Loading
Loading