mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 15:09:33 +01:00
add support for pinning items to menu
This commit is contained in:
@@ -1,23 +1,23 @@
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Clipboard,
|
||||
Dimensions,
|
||||
StatusBar,
|
||||
Text,
|
||||
|
||||
|
||||
TouchableOpacity,
|
||||
View,
|
||||
View
|
||||
} from 'react-native';
|
||||
import Share from 'react-native-share';
|
||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import {useTracked} from '../../provider';
|
||||
import {Actions} from '../../provider/Actions';
|
||||
import {DDS} from '../../services/DeviceDetection';
|
||||
import { useTracked } from '../../provider';
|
||||
import { Actions } from '../../provider/Actions';
|
||||
import { DDS } from '../../services/DeviceDetection';
|
||||
import {
|
||||
eSendEvent,
|
||||
openVault,
|
||||
sendNoteEditedEvent,
|
||||
ToastEvent,
|
||||
ToastEvent
|
||||
} from '../../services/EventManager';
|
||||
import PremiumService from '../../services/PremiumService';
|
||||
import {
|
||||
@@ -25,27 +25,25 @@ import {
|
||||
COLOR_SCHEME,
|
||||
COLOR_SCHEME_DARK,
|
||||
COLOR_SCHEME_LIGHT,
|
||||
setColorScheme,
|
||||
setColorScheme
|
||||
} from '../../utils/Colors';
|
||||
import {db} from '../../utils/DB';
|
||||
import { db } from '../../utils/DB';
|
||||
import {
|
||||
eOpenLoginDialog,
|
||||
eOpenMoveNoteDialog,
|
||||
eShowGetPremium,
|
||||
eShowGetPremium
|
||||
} from '../../utils/Events';
|
||||
import {deleteItems} from '../../utils/functions';
|
||||
import {MMKV} from '../../utils/mmkv';
|
||||
import {opacity, ph, pv, SIZE, WEIGHT} from '../../utils/SizeUtils';
|
||||
import {sleep, timeConverter} from '../../utils/TimeUtils';
|
||||
import {Button} from '../Button';
|
||||
import {PremiumTag} from '../Premium/PremiumTag';
|
||||
import {PressableButton} from '../PressableButton';
|
||||
import {Toast} from '../Toast';
|
||||
import { deleteItems } from '../../utils/functions';
|
||||
import { MMKV } from '../../utils/mmkv';
|
||||
import { opacity, ph, pv, SIZE } from '../../utils/SizeUtils';
|
||||
import { timeConverter } from '../../utils/TimeUtils';
|
||||
import { PremiumTag } from '../Premium/PremiumTag';
|
||||
import { PressableButton } from '../PressableButton';
|
||||
import { Toast } from '../Toast';
|
||||
import Heading from '../Typography/Heading';
|
||||
import Paragraph from '../Typography/Paragraph';
|
||||
import {ActionSheetColorsSection} from './ActionSheetColorsSection';
|
||||
import {ActionSheetTagsSection} from './ActionSheetTagsSection';
|
||||
import {GetPremium} from './GetPremium';
|
||||
import { ActionSheetColorsSection } from './ActionSheetColorsSection';
|
||||
import { ActionSheetTagsSection } from './ActionSheetTagsSection';
|
||||
const w = Dimensions.get('window').width;
|
||||
|
||||
export const ActionSheetComponent = ({
|
||||
@@ -59,6 +57,8 @@ export const ActionSheetComponent = ({
|
||||
const [state, dispatch] = useTracked();
|
||||
const {colors, premiumUser, user} = state;
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [isPinnedToMenu, setIsPinnedToMenu] = useState(false);
|
||||
|
||||
const [note, setNote] = useState(
|
||||
item
|
||||
? item
|
||||
@@ -84,6 +84,11 @@ export const ActionSheetComponent = ({
|
||||
useEffect(() => {
|
||||
if (item.dateCreated !== null) {
|
||||
setNote({...item});
|
||||
if (item.type !== note) {
|
||||
setIsPinnedToMenu(
|
||||
db.settings.pins.findIndex((i) => i.id === item.id) > -1,
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [item]);
|
||||
|
||||
@@ -313,6 +318,34 @@ export const ActionSheetComponent = ({
|
||||
check: true,
|
||||
on: note.favorite,
|
||||
},
|
||||
{
|
||||
name: isPinnedToMenu ? 'Unpin from Menu' : 'Pin to Menu',
|
||||
icon: 'tag-outline',
|
||||
func: async () => {
|
||||
try {
|
||||
if (isPinnedToMenu) {
|
||||
await db.settings.unpin(note.id);
|
||||
} else {
|
||||
if (item.type === 'notebook') {
|
||||
await db.settings.pin(note.type, {id: note.id});
|
||||
} else if (item.type === 'topic') {
|
||||
await db.settings.pin(note.type, {
|
||||
id: note.notebookId,
|
||||
topic: note.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setIsPinnedToMenu(
|
||||
db.settings.pins.findIndex((i) => i.id === item.id) > -1,
|
||||
);
|
||||
dispatch({type:Actions.MENU_PINS})
|
||||
} catch (e) {}
|
||||
},
|
||||
close: false,
|
||||
check: true,
|
||||
on: isPinnedToMenu,
|
||||
},
|
||||
];
|
||||
|
||||
const _renderRowItem = (rowItem) =>
|
||||
|
||||
@@ -7,5 +7,6 @@ export const dialogActions = {
|
||||
ACTION_PERMANANT_DELETE: 516,
|
||||
ACTION_APPLY_CHANGES: 517,
|
||||
ACTION_UPIN:518,
|
||||
ACTION_NEW_NOTE:519
|
||||
ACTION_NEW_NOTE:519,
|
||||
ACTION_UPIN_MENU:520,
|
||||
};
|
||||
|
||||
@@ -101,3 +101,11 @@ export const TEMPLATE_UNPIN = (type) => { return {
|
||||
negativeText: 'Cancel',
|
||||
action: dialogActions.ACTION_UPIN
|
||||
}};
|
||||
|
||||
export const TEMPLATE_UNPIN_MENU = (name,type) => { return {
|
||||
title: 'Unpin' + name,
|
||||
paragraph: 'Remove this ' + type + 'from menu?',
|
||||
positiveText: 'Unpin',
|
||||
negativeText: 'Cancel',
|
||||
action: dialogActions.ACTION_UPIN_MENU
|
||||
}};
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
FAV_SVG,
|
||||
TRASH_SVG,
|
||||
SETTINGS_SVG,
|
||||
SEARCH_SVG
|
||||
SEARCH_SVG,
|
||||
} from '../../assets/images/assets';
|
||||
import {useTracked} from '../../provider';
|
||||
export const Placeholder = ({type, w, h, color}) => {
|
||||
@@ -20,6 +20,8 @@ export const Placeholder = ({type, w, h, color}) => {
|
||||
return NOTE_SVG(color || colors.accent);
|
||||
case 'notebooks':
|
||||
return NOTEBOOK_SVG(colors.accent);
|
||||
case 'topics':
|
||||
return NOTEBOOK_SVG(colors.accent);
|
||||
case 'tags':
|
||||
return TAG_SVG(colors.accent);
|
||||
case 'favorites':
|
||||
|
||||
@@ -1,21 +1,29 @@
|
||||
import React, {useEffect} from 'react';
|
||||
import {Text, View} from 'react-native';
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {FlatList, View} from 'react-native';
|
||||
import {useTracked} from '../../provider';
|
||||
import {Actions} from '../../provider/Actions';
|
||||
import {eSendEvent} from '../../services/EventManager';
|
||||
import NavigationService from '../../services/Navigation';
|
||||
import {db} from '../../utils/DB';
|
||||
import {refreshNotesPage} from '../../utils/Events';
|
||||
import { sideMenuRef } from '../../utils/Refs';
|
||||
import {SIZE, WEIGHT} from '../../utils/SizeUtils';
|
||||
import {ph, pv, SIZE} from '../../utils/SizeUtils';
|
||||
import {NotebookItem} from '../NotebookItem';
|
||||
import {PressableButton} from '../PressableButton';
|
||||
import Heading from '../Typography/Heading';
|
||||
import Paragraph from '../Typography/Paragraph';
|
||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import BaseDialog from '../Dialog/base-dialog';
|
||||
import DialogHeader from '../Dialog/dialog-header';
|
||||
import DialogButtons from '../Dialog/dialog-buttons';
|
||||
import {getElevation} from '../../utils';
|
||||
import {DDS} from '../../services/DeviceDetection';
|
||||
|
||||
export const TagsSection = () => {
|
||||
const [state, dispatch] = useTracked();
|
||||
const {colors, tags, currentScreen} = state;
|
||||
const {colors, menuPins} = state;
|
||||
|
||||
useEffect(() => {
|
||||
dispatch({type: Actions.TAGS});
|
||||
dispatch({type: Actions.MENU_PINS});
|
||||
}, []);
|
||||
|
||||
const onPress = (item) => {
|
||||
@@ -37,14 +45,143 @@ export const TagsSection = () => {
|
||||
});
|
||||
NavigationService.navigate('NotesPage', params);
|
||||
eSendEvent(refreshNotesPage, params);
|
||||
NavigationService.closeDrawer()
|
||||
NavigationService.closeDrawer();
|
||||
};
|
||||
|
||||
return (
|
||||
<View
|
||||
style={{
|
||||
width: '100%',
|
||||
flexGrow: 1,
|
||||
}}>
|
||||
<FlatList
|
||||
data={menuPins}
|
||||
ListEmptyComponent={
|
||||
<View
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: '10%',
|
||||
}}>
|
||||
<Heading style={{marginBottom: 2.5}} size={SIZE.sm}>
|
||||
Your Pins
|
||||
</Heading>
|
||||
<Paragraph
|
||||
style={{textAlign: 'center'}}
|
||||
color={colors.icon}
|
||||
size={SIZE.xs}>
|
||||
You have not pinned anything yet. You can pin topics and tags
|
||||
here.
|
||||
</Paragraph>
|
||||
</View>
|
||||
}
|
||||
renderItem={({item, index}) => (
|
||||
<PinItem key={item.id} item={item} index={index} onPress={onPress} />
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const PinItem = ({item, index, onPress}) => {
|
||||
const [state, dispatch] = useTracked();
|
||||
const {colors, currentScreen} = state;
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
{visible && (
|
||||
<BaseDialog visible={true}>
|
||||
<View
|
||||
style={{
|
||||
...getElevation(5),
|
||||
width: DDS.isTab ? 350 : '80%',
|
||||
maxHeight: 350,
|
||||
borderRadius: 5,
|
||||
backgroundColor: colors.bg,
|
||||
paddingHorizontal: ph,
|
||||
paddingVertical: pv,
|
||||
}}>
|
||||
<DialogHeader title="Unpin" paragraph="Remove item from menu" />
|
||||
<DialogButtons
|
||||
positiveTitle="Unpin"
|
||||
negativeTitle="Cancel"
|
||||
onPressNegative={() => setVisible(false)}
|
||||
onPressPositive={async () => {
|
||||
await db.settings.unpin(note.id);
|
||||
dispatch({type: Actions.MENU_PINS});
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</BaseDialog>
|
||||
)}
|
||||
<PressableButton
|
||||
color={
|
||||
currentScreen === item.title.toLowerCase()
|
||||
? colors.shade
|
||||
: 'transparent'
|
||||
}
|
||||
selectedColor={colors.accent}
|
||||
alpha={!colors.night ? -0.02 : 0.02}
|
||||
opacity={0.12}
|
||||
onLongPress={() => setVisible(true)}
|
||||
onPress={() => onPress(item)}
|
||||
customStyle={{
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-start',
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
borderRadius: 0,
|
||||
paddingHorizontal: 10,
|
||||
minHeight: 50,
|
||||
borderBottomWidth: 1,
|
||||
borderBottomColor: colors.nav,
|
||||
}}>
|
||||
<View
|
||||
style={{
|
||||
width: 35,
|
||||
height: 35,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'flex-start',
|
||||
}}>
|
||||
{item.type === 'notebook' ? (
|
||||
<Icon color={colors.accent} size={SIZE.md} name="book-outline" />
|
||||
) : item.type === 'tag' ? (
|
||||
<Icon color={colors.accent} size={SIZE.md} name="pound" />
|
||||
) : (
|
||||
<Paragraph color={colors.accent} size={SIZE.md}>
|
||||
T
|
||||
</Paragraph>
|
||||
)}
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
alignItems: 'flex-start',
|
||||
width: '85%',
|
||||
}}>
|
||||
<Paragraph size={SIZE.md} color={colors.heading}>
|
||||
{item.title}
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph
|
||||
style={{marginTop: 2.5}}
|
||||
size={SIZE.xs}
|
||||
color={colors.icon}>
|
||||
{item.type.slice(0, 1).toUpperCase() +
|
||||
item.type.slice(1, item.type.length)}{' '}
|
||||
{item.type === 'topic'
|
||||
? 'in ' + db.notebooks.notebook(item.notebookId).data.title
|
||||
: null}
|
||||
</Paragraph>
|
||||
</View>
|
||||
</PressableButton>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
{tags
|
||||
.filter((o) => o.noteIds.length > 1)
|
||||
.slice(0, tags.length > 10 ? 10 : tags.length)
|
||||
@@ -92,6 +229,4 @@ export const TagsSection = () => {
|
||||
</View>
|
||||
</PressableButton>
|
||||
))}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
*/
|
||||
|
||||
@@ -62,7 +62,7 @@ export const Menu = React.memo(
|
||||
style={{
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
backgroundColor:DDS.isLargeTablet()? colors.nav : colors.bg,
|
||||
backgroundColor: DDS.isLargeTablet() ? colors.nav : colors.bg,
|
||||
paddingTop: insets.top,
|
||||
}}>
|
||||
<ScrollView
|
||||
@@ -81,27 +81,8 @@ export const Menu = React.memo(
|
||||
noTextMode={noTextMode}
|
||||
/>
|
||||
))}
|
||||
|
||||
{noTextMode ? null : <TagsSection />}
|
||||
<ColorSection noTextMode={noTextMode} />
|
||||
<View
|
||||
style={{
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
flexGrow: 1,
|
||||
paddingHorizontal: '10%',
|
||||
}}>
|
||||
<Heading style={{marginBottom: 2.5}} size={SIZE.sm}>
|
||||
Your Pins
|
||||
</Heading>
|
||||
<Paragraph
|
||||
style={{textAlign: 'center'}}
|
||||
color={colors.icon}
|
||||
size={SIZE.xs}>
|
||||
You have not pinned anything yet. You can pin topics and tags
|
||||
here.
|
||||
</Paragraph>
|
||||
</View>
|
||||
<TagsSection />
|
||||
</ScrollView>
|
||||
|
||||
<View
|
||||
|
||||
@@ -188,7 +188,10 @@ export const NotebookItem = ({
|
||||
'Delete',
|
||||
];
|
||||
|
||||
let columnItems = item.type === 'topic' ? [] : ['Pin'];
|
||||
let columnItems =
|
||||
item.type === 'topic'
|
||||
? ['Pin to Menu', 'Unpin from Menu']
|
||||
: ['Pin', 'Pin to Menu', 'Unpin from Menu'];
|
||||
|
||||
ActionSheetEvent(item, false, false, rowItems, columnItems, {
|
||||
notebookID: notebookID,
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
useWindowDimensions,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import {initialWindowMetrics} from 'react-native-safe-area-context';
|
||||
import {initialWindowMetrics, useSafeAreaInsets} from 'react-native-safe-area-context';
|
||||
import {DataProvider, LayoutProvider, RecyclerListView} from 'recyclerlistview';
|
||||
import {useTracked} from '../../provider';
|
||||
import {Actions} from '../../provider/Actions';
|
||||
@@ -51,6 +51,7 @@ const SimpleList = ({
|
||||
const {colors} = state;
|
||||
const searchResults = {...state.searchResults};
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const insets = useSafeAreaInsets();
|
||||
const [dataProvider, setDataProvider] = useState(
|
||||
new DataProvider((r1, r2) => {
|
||||
return r1 !== r2;
|
||||
@@ -154,7 +155,7 @@ const SimpleList = ({
|
||||
style={[
|
||||
{
|
||||
backgroundColor: colors.bg,
|
||||
height: dHeight - 250 - initialWindowMetrics.insets.top,
|
||||
height: dHeight - 250 - insets.top,
|
||||
width: '100%',
|
||||
},
|
||||
]}>
|
||||
|
||||
@@ -42,7 +42,7 @@ class SortDialog extends React.Component {
|
||||
}
|
||||
|
||||
async getSettings() {
|
||||
let settings = await MMKV.getItem('settings');
|
||||
let settings = await MMKV.getItem('appSettings');
|
||||
this.setState({
|
||||
settings: JSON.parse(settings),
|
||||
});
|
||||
|
||||
@@ -30,5 +30,6 @@ export const Actions = {
|
||||
MESSAGE_BOARD_STATE:'messageBoardState',
|
||||
LOADING:"loading",
|
||||
FULLSCREEN:"fullscreen",
|
||||
DEVICE_MODE:"deviceMode"
|
||||
DEVICE_MODE:"deviceMode",
|
||||
MENU_PINS:"menuPins"
|
||||
};
|
||||
|
||||
@@ -81,4 +81,5 @@ export const defaultState = {
|
||||
icon: 'account-outline',
|
||||
},
|
||||
keyword: [],
|
||||
menuPins:[]
|
||||
};
|
||||
|
||||
@@ -17,6 +17,7 @@ export const reducer = (state, action) => {
|
||||
tags: db.tags.all,
|
||||
favorites: db.notes.favorites,
|
||||
colorNotes: db.colors.all,
|
||||
menuPins:db.settings.pins
|
||||
};
|
||||
}
|
||||
case Actions.SYNCING: {
|
||||
@@ -254,6 +255,13 @@ export const reducer = (state, action) => {
|
||||
deviceMode: action.state,
|
||||
};
|
||||
}
|
||||
case Actions.MENU_PINS: {
|
||||
|
||||
return {
|
||||
...state,
|
||||
menuPins: db.settings.pins,
|
||||
};
|
||||
}
|
||||
default:
|
||||
throw new Error('unknown action type');
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ let settings = defaultState.settings;
|
||||
|
||||
async function init() {
|
||||
scale.fontScale = 1;
|
||||
settings = await MMKV.getStringAsync('settings');
|
||||
settings = await MMKV.getStringAsync('appSettings');
|
||||
if (!settings) {
|
||||
settings = defaultState.settings;
|
||||
await MMKV.setStringAsync('settings', JSON.stringify(settings));
|
||||
await MMKV.setStringAsync('appSettings', JSON.stringify(settings));
|
||||
} else {
|
||||
settings = JSON.parse(settings);
|
||||
}
|
||||
@@ -51,7 +51,7 @@ const setTheme = async () => {
|
||||
|
||||
async function set(name, value) {
|
||||
settings[name] = value;
|
||||
await MMKV.setStringAsync('settings', JSON.stringify(settings));
|
||||
await MMKV.setStringAsync('appSettings', JSON.stringify(settings));
|
||||
updateEvent({type: Actions.SETTINGS, settings: settings});
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import {SIZE} from './SizeUtils';
|
||||
export async function setSetting(settings, name, value) {
|
||||
let s = {...settings};
|
||||
s[name] = value;
|
||||
await MMKV.setStringAsync('settings', JSON.stringify(s));
|
||||
await MMKV.setStringAsync('appSettings', JSON.stringify(s));
|
||||
updateEvent({type: Actions.SETTINGS, settings: s});
|
||||
}
|
||||
|
||||
|
||||
@@ -104,8 +104,12 @@ export const Notebook = ({route, navigation}) => {
|
||||
onLoad();
|
||||
}}
|
||||
focused={() => navigation.isFocused()}
|
||||
placeholder={<></>}
|
||||
placeholderText=""
|
||||
placeholderData={{
|
||||
heading: route.params.notebook.title,
|
||||
paragraph: 'You have not added any topics yet.',
|
||||
button: 'Add a Topic',
|
||||
action:_onPressBottomButton
|
||||
}}
|
||||
/>
|
||||
|
||||
<ContainerBottomButton
|
||||
|
||||
Reference in New Issue
Block a user