mobile: update ui

This commit is contained in:
Ammar Ahmed
2026-07-01 20:15:26 +05:00
committed by Abdullah Atta
parent bbb4a9d44a
commit 3b362f592c
12 changed files with 185 additions and 99 deletions

View File

@@ -55,9 +55,7 @@ import FormInput, {
createFormRef,
validators
} from "../../ui/input/form-input";
import Paragraph from "../../ui/typography/paragraph";
import { strings } from "@notesnook/intl";
import { DefaultAppStyles } from "../../../utils/styles";
import {
isEncryptedContent,
Note,
@@ -72,6 +70,7 @@ import { Radius, Spacing } from "../../../common/design/spacing";
import { PASSWORD_PLACEHOLDER } from "../../../utils/constants";
import { AppFontSize } from "../../../utils/size";
import { useSettingStore } from "../../../stores/use-setting-store";
import { Checkbox } from "../../ui/checkbox";
export const VaultDialog: React.FC = () => {
const { colors } = useThemeColors();
@@ -632,7 +631,7 @@ export const VaultDialog: React.FC = () => {
descriptionRef.current = data.description || null;
paragraphRef.current = data.paragraph || null;
buttonTitleRef.current = data.buttonTitle || null;
positiveButtonTypeRef.current = data.positiveButtonType || "transparent";
positiveButtonTypeRef.current = data.positiveButtonType || "accent";
customActionTitleRef.current = data.customActionTitle || null;
customActionParagraphRef.current = data.customActionParagraph || null;
onUnlockRef.current = data.onUnlock;
@@ -641,7 +640,7 @@ export const VaultDialog: React.FC = () => {
// Set UI state
setIsBiometryAvailable(available);
setIsBiometryEnrolled(fingerprint);
setBiometricUnlock(fingerprint);
// setBiometricUnlock(fingerprint);
setIcon(data.icon);
setDeleteAll(false);
setLoading(false);
@@ -719,7 +718,11 @@ export const VaultDialog: React.FC = () => {
}}
>
<DialogHeader
title={titleRef.current}
title={
requestType === VaultRequestType.PermanentUnlock
? noteRef.current?.title
: titleRef.current
}
paragraph={
paragraphRef.current || customActionParagraphRef.current || ""
}
@@ -737,7 +740,7 @@ export const VaultDialog: React.FC = () => {
paddingHorizontal: Spacing.LEVEL_3,
gap: isDeleteVault ? 0 : Spacing.LEVEL_4,
marginTop: Spacing.LEVEL_4,
marginBottom: Spacing.LEVEL_1
marginBottom: Spacing.LEVEL_4
}}
>
{(isChangePassword ||
@@ -841,9 +844,14 @@ export const VaultDialog: React.FC = () => {
) : null}
{isCreateVault ? (
<View>
<View
style={{
gap: Spacing.LEVEL_2
}}
>
<FormInput
name="password"
label={strings.password()}
formRef={formRef}
fwdRef={passInputRef}
autoCapitalize="none"
@@ -886,12 +894,7 @@ export const VaultDialog: React.FC = () => {
</View>
) : null}
{biometricUnlock && !isBiometryEnrolled && !isCreateVault ? (
<Paragraph>{strings.vaultEnableBiometrics()}</Paragraph>
) : null}
{!biometricUnlock &&
!isBiometryEnrolled &&
{!isBiometryEnrolled &&
isBiometryAvailable &&
(requestType === VaultRequestType.CopyNote ||
requestType === VaultRequestType.DeleteNote ||
@@ -900,20 +903,16 @@ export const VaultDialog: React.FC = () => {
requestType === VaultRequestType.GoToEditor ||
requestType === VaultRequestType.PermanentUnlock ||
requestType === VaultRequestType.LockNote) ? (
<Button
<Checkbox
title={strings.vaultEnableBiometrics()}
checked={biometricUnlock}
iconSize={12}
style={{
marginTop: -Spacing.LEVEL_1
}}
onPress={() => {
setBiometricUnlock(!biometricUnlock);
}}
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL
}}
icon="fingerprint"
width="100%"
title={strings.unlockWithBiometrics()}
iconColor={
biometricUnlock ? colors.selected.accent : colors.primary.icon
}
type={biometricUnlock ? "transparent" : "plain"}
/>
) : null}
</View>

View File

@@ -57,7 +57,8 @@ export const NotebookItem = ({
disableExpand,
hideNoteCount,
style,
subNotebookButtonStyle
subNotebookButtonStyle,
selectionCheckboxLocation = "right"
}: {
index: number;
item: TreeItem;
@@ -76,6 +77,7 @@ export const NotebookItem = ({
hideNoteCount?: boolean;
style?: ViewStyle;
subNotebookButtonStyle?: ViewStyle;
selectionCheckboxLocation?: "left" | "right";
}) => {
const notebook = item.notebook;
const isFocused = focused;
@@ -194,7 +196,8 @@ export const NotebookItem = ({
gap: Spacing.LEVEL_1
}}
>
{item.depth === 0 ? (
{item.depth === 0 &&
(!selectionEnabled || selectionCheckboxLocation === "right") ? (
<AppIcon
size={AppFontSize.md}
color={
@@ -211,11 +214,34 @@ export const NotebookItem = ({
/>
) : null}
{selectionEnabled && selectionCheckboxLocation === "left" ? (
<View
style={{
justifyContent: "center",
alignItems: "center"
}}
>
<AppIcon
name={selected ? "checkbox" : "box-empty"}
iconFamily="notesnook"
size={16}
color={
selected
? [
colors.selected.accent,
colors.selected.accentForeground
]
: colors.primary.icon
}
/>
</View>
) : null}
<Paragraph
color={
isFocused ? colors.selected.paragraph : colors.primary.paragraph
}
size={AppFontSize.sm}
fontSize="SM"
>
{notebook?.title}
</Paragraph>
@@ -229,7 +255,7 @@ export const NotebookItem = ({
justifyContent: "center"
}}
>
{selectionEnabled ? (
{selectionEnabled && selectionCheckboxLocation === "right" ? (
<View
style={{
justifyContent: "center",
@@ -239,7 +265,7 @@ export const NotebookItem = ({
<AppIcon
name={selected ? "checkbox" : "box-empty"}
iconFamily="notesnook"
size={AppFontSize.md}
size={16}
color={
selected
? [
@@ -250,17 +276,15 @@ export const NotebookItem = ({
}
/>
</View>
) : (
<>
{item.hasChildren || hideNoteCount ? null : (
<Paragraph fontSize="SM" color={colors.secondary.paragraph}>
{totalNotes?.(notebook?.id) || 0}
</Paragraph>
)}
</>
) : null}
{item.hasChildren || hideNoteCount || selectionEnabled ? null : (
<Paragraph fontSize="SM" color={colors.secondary.paragraph}>
{totalNotes?.(notebook?.id) || 0}
</Paragraph>
)}
{onAddNotebook ? (
{onAddNotebook && !item.hasChildren ? (
<IconButton
name="plus"
iconFamily="notesnook"
@@ -303,7 +327,8 @@ export const NotebookItem = ({
style={{
borderRadius: defaultBorderRadius,
width: undefined,
height: undefined
height: undefined,
marginRight: 1.5
}}
iconFamily="notesnook"
name={expanded ? "chevron-up" : "chevron-down"}
@@ -313,7 +338,7 @@ export const NotebookItem = ({
</Pressable>
</View>
{expanded && item.hasChildren && !selectionEnabled ? (
{expanded && item.hasChildren ? (
<View
style={{
width: "100%",

View File

@@ -77,7 +77,7 @@ export const Checkbox = ({
style={{
width: width || undefined,
flexDirection: "row",
alignItems: "center",
alignItems: "flex-start",
justifyContent: "flex-start",
flexShrink: 1,
gap: Spacing.LEVEL_1,
@@ -92,6 +92,9 @@ export const Checkbox = ({
name={checked ? "checkbox" : "box-empty"}
iconFamily="notesnook"
size={iconSize}
style={{
marginTop: 1.5
}}
color={
iconColor ||
(checked
@@ -102,7 +105,7 @@ export const Checkbox = ({
{title ? (
<Paragraph
numberOfLines={1}
numberOfLines={2}
size={fontSize}
fontFamily={fontFamily}
color={colors.primary.paragraph}

View File

@@ -98,7 +98,6 @@ export const IconButton = ({
style={{
justifyContent: "center",
alignItems: "center",
// borderRadius: 100,
width: size,
height: size,
...style

View File

@@ -185,13 +185,13 @@ export function hasFormErrors(errors: FormErrors) {
export const validators = {
required:
(message = "This field is required") =>
(value: string) =>
value?.trim() ? undefined : message,
(value: string) =>
value?.trim() ? undefined : message,
email:
(message = "Please enter a valid email") =>
(value: string) =>
!value?.trim() || isEmail(value.trim()) ? undefined : message,
(value: string) =>
!value?.trim() || isEmail(value.trim()) ? undefined : message,
minLength: (length: number, message?: string) => (value: string) =>
!value || value.length >= length
@@ -200,15 +200,15 @@ export const validators = {
url:
(message = "Please enter a valid URL") =>
(value: string) =>
!value?.trim() || isURL(value.trim(), { allow_underscores: true })
? undefined
: message,
(value: string) =>
!value?.trim() || isURL(value.trim(), { allow_underscores: true })
? undefined
: message,
matchField:
(fieldName: string, message = "Values do not match") =>
(value: string, values: FormValues) =>
value === values[fieldName] ? undefined : message
(value: string, values: FormValues) =>
value === values[fieldName] ? undefined : message
};
interface FormInputProps extends TextInputProps {
@@ -388,7 +388,7 @@ export function FormInput({
<IconButton
name={!secureEntry ? "eye-closed" : "eye-open"}
iconFamily="notesnook"
size={20}
size={16}
top={10}
bottom={10}
onPress={() => {
@@ -409,7 +409,7 @@ export function FormInput({
<IconButton
testID={button.testID}
name={button.icon}
size={button.size || AppFontSize.xl}
size={button.size || 16}
top={10}
bottom={10}
onPress={button.onPress}

View File

@@ -941,6 +941,7 @@ export const useActions = ({
requestType: VaultRequestType.PermanentUnlock,
item: item,
title: strings.unlockNote(),
paragraph: strings.thisNoteLocked(),
buttonTitle: strings.unlock()
});
return;
@@ -962,7 +963,8 @@ export const useActions = ({
requestType: VaultRequestType.CreateVault,
item: item,
title: strings.createVault(),
buttonTitle: strings.lock()
buttonTitle: strings.lock(),
positiveButtonType: "accent"
});
break;
case VAULT_ERRORS.vaultLocked:
@@ -970,7 +972,8 @@ export const useActions = ({
requestType: VaultRequestType.LockNote,
item: item,
title: strings.lockNote(),
buttonTitle: strings.lock()
buttonTitle: strings.lock(),
positiveButtonType: "accent"
});
break;
}

View File

@@ -65,6 +65,9 @@ export const Home = ({ navigation, route }: NavigationProps<"Notes">) => {
});
}}
id={route.name}
style={{
paddingHorizontal: Spacing.LEVEL_2
}}
onPressDefaultRightButton={openEditor}
/>

View File

@@ -25,6 +25,7 @@ import { ActivityIndicator, View } from "react-native";
import { FlatList } from "react-native-actions-sheet";
import { SafeAreaView } from "react-native-safe-area-context";
import { db } from "../../common/database";
import { Spacing } from "../../common/design/spacing";
import Navigation, { NavigationProps } from "../../services/navigation";
import {
createNotebookTreeStores,
@@ -35,10 +36,9 @@ import { useNotebooks } from "../../stores/use-notebook-store";
import { useRelationStore } from "../../stores/use-relation-store";
import { updateNotebook } from "../../utils/notebooks";
import { AppFontSize } from "../../utils/size";
import { DefaultAppStyles } from "../../utils/styles";
import { FloatingButton } from "../../components/container/floating-button";
import { Header } from "../../components/header";
import { NotebookItem } from "../../components/side-menu/notebook-item";
import { Button } from "../../components/ui/button";
import Input from "../../components/ui/input";
import Paragraph from "../../components/ui/typography/paragraph";
import { AddNotebookSheet } from "../../components/sheets/add-notebook";
@@ -193,10 +193,35 @@ const LinkNotebooks = (props: NavigationProps<"LinkNotebooks">) => {
[]
);
const onCreateNotebook = async () => {
const notebooksFeature = await isFeatureAvailable("notebooks");
if (!notebooksFeature.isAllowed) {
ToastManager.show({
message: notebooksFeature.error,
type: "info",
context: "local",
actionText: strings.upgrade(),
func: () => {
ToastManager.hide();
PaywallSheet.present(notebooksFeature);
}
});
return;
}
AddNotebookSheet.present(
undefined,
undefined,
"global",
undefined,
false,
searchQuery.current
);
};
return (
<SafeAreaView
style={{
gap: DefaultAppStyles.GAP_VERTICAL,
gap: Spacing.LEVEL_2,
flex: 1,
backgroundColor: colors.primary.background
}}
@@ -204,10 +229,15 @@ const LinkNotebooks = (props: NavigationProps<"LinkNotebooks">) => {
<Header
title={strings.addToNotebook()}
canGoBack
style={{
backgroundColor: colors.primary.background
}}
rightButton={
hasSelection
? {
name: "restore",
name: "arrow-counter-clockwise",
iconFamily: "notesnook",
size: 20,
onPress: () => {
updateInitialSelectionState(noteIds);
}
@@ -225,9 +255,10 @@ const LinkNotebooks = (props: NavigationProps<"LinkNotebooks">) => {
ListHeaderComponent={
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: Spacing.LEVEL_3,
width: "100%",
paddingVertical: DefaultAppStyles.GAP_VERTICAL
paddingBottom: Spacing.LEVEL_3,
gap: Spacing.LEVEL_3
}}
>
<Input
@@ -238,35 +269,33 @@ const LinkNotebooks = (props: NavigationProps<"LinkNotebooks">) => {
updateNotebooks();
}, 300);
}}
button={{
icon: "plus",
onPress: async () => {
const notebooksFeature =
await isFeatureAvailable("notebooks");
if (!notebooksFeature.isAllowed) {
ToastManager.show({
message: notebooksFeature.error,
type: "info",
context: "local",
actionText: strings.upgrade(),
func: () => {
ToastManager.hide();
PaywallSheet.present(notebooksFeature);
}
});
return;
}
AddNotebookSheet.present(
undefined,
undefined,
"global",
undefined,
false,
searchQuery.current
);
},
color: colors.primary.icon
containerStyle={{
backgroundColor: colors.secondary.background,
borderWidth: 0
}}
button={{
icon: "search",
iconFamily: "notesnook",
onPress: () => {},
color: colors.secondary.icon,
size: 16
}}
/>
<View
style={{
height: 1,
backgroundColor: colors.primary.border
}}
/>
<Button
title={strings.createNotebook()}
icon="plus"
iconPosition="left"
type="accent-outline"
width="100%"
onPress={onCreateNotebook}
/>
{!multiSelect ? (
@@ -302,14 +331,23 @@ const LinkNotebooks = (props: NavigationProps<"LinkNotebooks">) => {
}
/>
{hasSelection ? (
<FloatingButton
<View
style={{
borderTopWidth: 1,
borderTopColor: colors.primary.border,
backgroundColor: colors.primary.background,
padding: Spacing.LEVEL_3
}}
>
<Button
testID="floating-save-button"
icon="check"
alwaysVisible
title={strings.saveChanges()}
type="accent"
width="100%"
disabled={!hasSelection}
onPress={() => onSave()}
/>
) : null}
</View>
</SafeAreaView>
);
};
@@ -357,12 +395,13 @@ const NotebookItemWrapper = React.memo(
return (
<View
style={{
paddingHorizontal: DefaultAppStyles.GAP
paddingHorizontal: Spacing.LEVEL_3
}}
>
<NotebookItem
item={item}
index={index}
selectionCheckboxLocation="left"
expanded={expanded}
onToggleExpanded={async () => {
useNotebookExpandedStore.getState().setExpanded(item.notebook.id);
@@ -395,6 +434,12 @@ const NotebookItemWrapper = React.memo(
: "deselected"
);
}}
style={{
paddingVertical: Spacing.LEVEL_1
}}
subNotebookButtonStyle={{
paddingVertical: Spacing.LEVEL_1
}}
canDisableSelectionMode={false}
selected={selected}
selectionEnabled={selectionEnabled}

File diff suppressed because one or more lines are too long

11
packages/icons/svgs/eye-open.svg Normal file → Executable file
View File

@@ -1 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><!-- Icon from Phosphor by Phosphor Icons - https://github.com/phosphor-icons/core/blob/main/LICENSE --><path fill="currentColor" d="M245.48 125.57c-.34-.78-8.66-19.23-27.24-37.81C201 70.54 171.38 50 128 50S55 70.54 37.76 87.76c-18.58 18.58-26.9 37-27.24 37.81a6 6 0 0 0 0 4.88c.34.77 8.66 19.22 27.24 37.8C55 185.47 84.62 206 128 206s73-20.53 90.24-37.75c18.58-18.58 26.9-37 27.24-37.8a6 6 0 0 0 0-4.88M128 194c-31.38 0-58.78-11.42-81.45-33.93A134.8 134.8 0 0 1 22.69 128a134.6 134.6 0 0 1 23.86-32.06C69.22 73.42 96.62 62 128 62s58.78 11.42 81.45 33.94A134.6 134.6 0 0 1 233.31 128C226.94 140.21 195 194 128 194m0-112a46 46 0 1 0 46 46a46.06 46.06 0 0 0-46-46m0 80a34 34 0 1 1 34-34a34 34 0 0 1-34 34"/></svg>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2899_8437)">
<path d="M7.99935 3C4.66602 3 1.81935 5.07333 0.666016 8C1.81935 10.9267 4.66602 13 7.99935 13C11.3327 13 14.1793 10.9267 15.3327 8C14.1793 5.07333 11.3327 3 7.99935 3ZM7.99935 11.3333C6.15935 11.3333 4.66602 9.84 4.66602 8C4.66602 6.16 6.15935 4.66667 7.99935 4.66667C9.83935 4.66667 11.3327 6.16 11.3327 8C11.3327 9.84 9.83935 11.3333 7.99935 11.3333ZM7.99935 6C6.89268 6 5.99935 6.89333 5.99935 8C5.99935 9.10667 6.89268 10 7.99935 10C9.10602 10 9.99935 9.10667 9.99935 8C9.99935 6.89333 9.10602 6 7.99935 6Z" fill="#666666"/>
</g>
<defs>
<clipPath id="clip0_2899_8437">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 796 B

After

Width:  |  Height:  |  Size: 779 B