mobile: support font scaling

This commit is contained in:
ammarahm-ed
2023-09-15 14:59:52 +05:00
parent d08994a314
commit b578d98c7b
25 changed files with 202 additions and 130 deletions

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import { View } from "react-native";
import { Dimensions, View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useMessageStore } from "../../stores/use-message-store";
import { useThemeColors } from "@notesnook/theme";
@@ -32,6 +32,7 @@ export const Card = ({ color, warning }) => {
color = color ? color : colors.primary.accent;
const messageBoardState = useMessageStore((state) => state.message);
const announcement = useMessageStore((state) => state.announcement);
const fontScale = Dimensions.get("window").fontScale;
return !messageBoardState.visible || announcement || warning ? null : (
<View
@@ -44,7 +45,6 @@ export const Card = ({ color, warning }) => {
type="gray"
customStyle={{
paddingVertical: 12,
width: "95%",
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
@@ -54,17 +54,18 @@ export const Card = ({ color, warning }) => {
<View
style={{
flexDirection: "row",
alignItems: "center"
alignItems: "center",
flexShrink: 1
}}
>
<View
style={{
width: 40,
width: 40 * fontScale,
backgroundColor:
messageBoardState.type === "error"
? hexToRGBA(colors.static.red, 0.15)
: hexToRGBA(color, 0.15),
height: 40,
height: 40 * fontScale,
borderRadius: 100,
alignItems: "center",
justifyContent: "center"
@@ -75,6 +76,7 @@ export const Card = ({ color, warning }) => {
color={
messageBoardState.type === "error" ? colors.error.icon : color
}
allowFontScaling
name={messageBoardState.icon}
/>
</View>
@@ -91,7 +93,7 @@ export const Card = ({ color, warning }) => {
</Paragraph>
<Paragraph
style={{
flexWrap: "wrap",
flexWrap: "no-wrap",
flexShrink: 1
}}
color={colors.primary.heading}
@@ -101,22 +103,24 @@ export const Card = ({ color, warning }) => {
</View>
</View>
<View
style={{
width: 40,
height: 40,
justifyContent: "center",
alignItems: "center"
}}
>
<Icon
name="chevron-right"
color={
messageBoardState.type === "error" ? colors.error.icon : color
}
size={SIZE.lg}
/>
</View>
{fontScale > 1 ? null : (
<View
style={{
width: 40,
height: 40,
justifyContent: "center",
alignItems: "center"
}}
>
<Icon
name="chevron-right"
color={
messageBoardState.type === "error" ? colors.error.icon : color
}
size={SIZE.lg}
/>
</View>
)}
</PressableButton>
</View>
);

View File

@@ -16,8 +16,8 @@ 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 React from "react";
import { Platform, View } from "react-native";
import React, { useRef } from "react";
import { Dimensions, Platform, View, useWindowDimensions } from "react-native";
import { FlatList } from "react-native-actions-sheet";
import { db } from "../../common/database";
import { DDS } from "../../services/device-detection";
@@ -54,7 +54,6 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
const { colors } = useThemeColors();
const alias = item.alias || item.title;
const isColor = !!ColorValues[item.title];
if (!item || !item.id) {
return (
<Paragraph style={{ marginVertical: 10, alignSelf: "center" }}>
@@ -62,6 +61,7 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
</Paragraph>
);
}
return (
<FlatList
keyboardShouldPersistTaps="always"
@@ -135,6 +135,7 @@ export const Properties = ({ close = () => {}, item, buttons = [] }) => {
}, 1000);
}}
/>
<Synced item={item} close={close} />
{DDS.isTab ? (

View File

@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React from "react";
import { FlatList, ScrollView, View } from "react-native";
import { Dimensions, FlatList, ScrollView, View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useActions } from "../../hooks/use-actions";
import { DDS } from "../../services/device-detection";
@@ -33,9 +33,11 @@ export const Items = ({ item, buttons, close }) => {
const dimensions = useSettingStore((state) => state.dimensions);
const actions = useActions({ item, close });
const data = actions.filter((i) => buttons.indexOf(i.id) > -1 && !i.hidden);
let width = dimensions.width > 600 ? 600 : dimensions.width;
let columnItemsCount = DDS.isLargeTablet() ? 7 : 5;
const shouldShrink =
Dimensions.get("window").fontScale > 1 &&
Dimensions.get("window").width < 450;
let columnItemsCount = DDS.isLargeTablet() ? 7 : shouldShrink ? 4 : 5;
let columnItemWidth = DDS.isTab
? (width - 12) / columnItemsCount
: (width - 12) / columnItemsCount;
@@ -66,6 +68,7 @@ export const Items = ({ item, buttons, close }) => {
}}
>
<Icon
allowFontScaling
name={item.icon}
size={DDS.isTab ? SIZE.xxl : SIZE.lg}
color={
@@ -78,7 +81,11 @@ export const Items = ({ item, buttons, close }) => {
/>
</PressableButton>
<Paragraph size={SIZE.xs} style={{ textAlign: "center" }}>
<Paragraph
size={SIZE.xs}
textBreakStrategy="simple"
style={{ textAlign: "center" }}
>
{item.title}
</Paragraph>
</View>
@@ -139,6 +146,7 @@ export const Items = ({ item, buttons, close }) => {
>
<Icon
name={item.icon}
allowFontScaling
size={DDS.isTab ? SIZE.xxl : SIZE.md + 4}
color={
item.on
@@ -150,7 +158,11 @@ export const Items = ({ item, buttons, close }) => {
/>
</PressableButton>
<Paragraph size={SIZE.xxs + 1} style={{ textAlign: "center" }}>
<Paragraph
textBreakStrategy="simple"
size={SIZE.xxs + 1}
style={{ textAlign: "center" }}
>
{item.title}
</Paragraph>
</PressableButton>
@@ -163,9 +175,12 @@ export const Items = ({ item, buttons, close }) => {
"copy",
"share",
"export",
"lock-unlock",
"publish"
"lock-unlock"
];
if (!shouldShrink) {
topBarItemsList.push("publish");
}
const topBarItems = data.filter(
(item) => topBarItemsList.indexOf(item.id) > -1
);

View File

@@ -17,10 +17,10 @@ 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 React from "react";
import { View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useThemeColors } from "@notesnook/theme";
import React from "react";
import { View, useWindowDimensions } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import { useUserStore } from "../../stores/use-user-store";
import { openLinkInBrowser } from "../../utils/functions";
import { SIZE } from "../../utils/size";
@@ -33,6 +33,8 @@ export const Synced = ({ item, close }) => {
const user = useUserStore((state) => state.user);
const lastSynced = useUserStore((state) => state.lastSynced);
const dimensions = useWindowDimensions();
const shouldShrink = dimensions.fontScale > 1 && dimensions.width < 450;
return user && lastSynced >= item.dateModified ? (
<View
style={{
@@ -49,7 +51,11 @@ export const Synced = ({ item, close }) => {
borderTopColor: colors.secondary.background
}}
>
<Icon name="shield-key-outline" color={colors.primary.accent} size={SIZE.xxxl} />
<Icon
name="shield-key-outline"
color={colors.primary.accent}
size={SIZE.xxxl}
/>
<View
style={{
@@ -67,15 +73,17 @@ export const Synced = ({ item, close }) => {
>
Encrypted and synced
</Heading>
<Paragraph
style={{
flexWrap: "wrap"
}}
size={SIZE.xs}
color={colors.primary.paragraph}
>
No one can view this {item.itemType || item.type} except you.
</Paragraph>
{shouldShrink ? null : (
<Paragraph
style={{
flexWrap: "wrap"
}}
size={SIZE.xs}
color={colors.primary.paragraph}
>
No one can view this {item.itemType || item.type} except you.
</Paragraph>
)}
</View>
<Button
@@ -92,7 +100,6 @@ export const Synced = ({ item, close }) => {
}
}}
fontSize={SIZE.xs}
title="Learn more"
height={30}
type="grayAccent"
/>

View File

@@ -253,6 +253,57 @@ export default function ReminderSheet({
marginBottom: DDS.isTab ? 25 : undefined
}}
>
{reminderMode === ReminderModes.Permanent ? null : (
<ScrollView
style={{
flexDirection: "row",
borderWidth: 1,
marginTop: 12,
borderRadius: 5,
borderColor: colors.primary.border,
paddingLeft: 12,
height: 50
}}
horizontal
>
{Object.keys(ReminderNotificationModes).map((mode) => (
<Button
key={mode}
title={mode}
style={{
marginRight: 12,
borderRadius: 100
}}
icon={
mode === "Silent"
? "minus-circle"
: mode === "Vibrate"
? "vibrate"
: "volume-high"
}
height={35}
type={
reminderNotificationMode ===
ReminderNotificationModes[
mode as keyof typeof ReminderNotificationModes
]
? "grayAccent"
: "gray"
}
onPress={() => {
const _mode = ReminderNotificationModes[
mode as keyof typeof ReminderNotificationModes
] as Reminder["priority"];
SettingsService.set({
reminderNotificationMode: _mode
});
setReminderNotificatioMode(_mode);
}}
/>
))}
</ScrollView>
)}
<Input
fwdRef={titleRef}
defaultValue={reminder?.title || referencedItem?.title}
@@ -280,15 +331,21 @@ export default function ReminderSheet({
}}
height={80}
wrapperStyle={{
marginBottom: 20
marginBottom: 12
}}
/>
<View
<ScrollView
style={{
flexDirection: "row",
marginBottom: 12
marginBottom: 12,
height: 50,
borderWidth: 1,
borderRadius: 5,
borderColor: colors.primary.border,
paddingLeft: 12
}}
horizontal
>
{Object.keys(ReminderModes).map((mode) => (
<Button
@@ -327,7 +384,7 @@ export default function ReminderSheet({
}}
/>
))}
</View>
</ScrollView>
{reminderMode === ReminderModes.Repeat ? (
<View
@@ -498,53 +555,6 @@ export default function ReminderSheet({
</View>
)}
{reminderMode === ReminderModes.Permanent ? null : (
<View
style={{
flexDirection: "row",
marginBottom: 12,
paddingTop: 12,
borderTopWidth: 1,
borderTopColor: colors.secondary.background
}}
>
{Object.keys(ReminderNotificationModes).map((mode) => (
<Button
key={mode}
title={mode}
style={{
marginRight: 12,
borderRadius: 100
}}
icon={
mode === "Silent"
? "minus-circle"
: mode === "Vibrate"
? "vibrate"
: "volume-high"
}
height={35}
type={
reminderNotificationMode ===
ReminderNotificationModes[
mode as keyof typeof ReminderNotificationModes
]
? "grayAccent"
: "gray"
}
onPress={() => {
const _mode = ReminderNotificationModes[
mode as keyof typeof ReminderNotificationModes
] as Reminder["priority"];
SettingsService.set({
reminderNotificationMode: _mode
});
setReminderNotificatioMode(_mode);
}}
/>
))}
</View>
)}
{reminderMode === ReminderModes.Once ||
reminderMode === ReminderModes.Permanent ? null : (
<View
@@ -595,6 +605,11 @@ export default function ReminderSheet({
}}
/>
</ScrollView>
<View
style={{
height: 10
}}
/>
</View>
);
}

View File

@@ -19,7 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { useThemeColors } from "@notesnook/theme";
import React, { useCallback, useEffect, useState } from "react";
import { View } from "react-native";
import { Dimensions, View } from "react-native";
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
import ToggleSwitch from "toggle-switch-react-native";
import Navigation from "../../services/navigation";
@@ -109,6 +109,7 @@ export const MenuItem = React.memo(
textAlignVertical: "center",
textAlign: "left"
}}
allowFontScaling
name={item.icon}
color={
item.icon === "crown"

View File

@@ -209,13 +209,19 @@ export const PinItem = React.memo(
justifyContent: "center"
}}
>
<Icon color={color} size={SIZE.lg - 2} name={icons[item.type]} />
<Icon
allowFontScaling
color={color}
size={SIZE.lg - 2}
name={icons[item.type]}
/>
<Icon
style={{
position: "absolute",
bottom: -6,
left: -6
}}
allowFontScaling
color={color}
size={SIZE.xs}
name="arrow-top-right-thick"

View File

@@ -113,6 +113,7 @@ export const UserStatus = () => {
<Icon
name="checkbox-blank-circle"
size={11}
allowFontScaling
color={
!user || lastSyncStatus === SyncStatus.Failed
? colors.error.icon
@@ -149,9 +150,15 @@ export const UserStatus = () => {
color={colors.error.icon}
name="sync-alert"
size={SIZE.lg}
allowFontScaling
/>
) : (
<Icon color={colors.primary.accent} name="sync" size={SIZE.lg} />
<Icon
allowFontScaling
color={colors.primary.accent}
name="sync"
size={SIZE.lg}
/>
)
) : null}
</PressableButton>

View File

@@ -134,6 +134,7 @@ export const Button = ({
{icon && !loading && iconPosition === "left" ? (
<Icon
name={icon}
allowFontScaling
style={[{ marginRight: 0 }, iconStyle as any]}
color={iconColor || buttonType?.text || textColor}
size={iconSize}
@@ -170,6 +171,7 @@ export const Button = ({
{icon && !loading && iconPosition === "right" ? (
<Icon
name={icon}
allowFontScaling
style={[{ marginLeft: 0 }, iconStyle as any]}
color={iconColor || buttonType?.text || textColor}
size={iconSize}

View File

@@ -92,6 +92,7 @@ export const IconButton = ({
layout={Layout}
name={name}
style={iconStyle as any}
allowFontScaling
color={
restProps.disabled
? RGB_Linear_Shade(-0.05, hexToRGBA(colors.secondary.background))

View File

@@ -59,7 +59,6 @@ const Heading = ({
<Component
layout={restProps.layout || Layout}
allowFontScaling={true}
maxFontSizeMultiplier={1}
{...restProps}
style={[
{

View File

@@ -45,8 +45,6 @@ const Paragraph = ({
return (
<Component
layout={restProps.layout || Layout}
allowFontScaling
maxFontSizeMultiplier={1}
{...restProps}
style={[
{

View File

@@ -649,7 +649,7 @@ export const useActions = ({ close = () => null, item }) => {
},
{
id: "favorite",
title: item.favorite ? "Unfavorite" : "Favorite",
title: item.favorite ? "Unfav" : "Fav",
icon: item.favorite ? "star-off" : "star-outline",
func: addToFavorites,
close: false,

View File

@@ -52,6 +52,7 @@ export type Settings = {
fontFamily: string;
dateFormat: string;
timeFormat: string;
fontScale: number;
};
export type EditorProps = {

View File

@@ -28,7 +28,8 @@ import {
InteractionManager,
Keyboard,
KeyboardEventListener,
NativeEventSubscription
NativeEventSubscription,
useWindowDimensions
} from "react-native";
import { WebViewMessageEvent } from "react-native-webview";
import { db } from "../../../common/database";
@@ -142,6 +143,8 @@ export const useEditorEvents = (
const handleBack = useRef<NativeEventSubscription>();
const readonly = useEditorStore((state) => state.readonly);
const isPremium = useUserStore((state) => state.premium);
const { fontScale } = useWindowDimensions();
const doubleSpacedLines = useSettingStore(
(state) => state.settings?.doubleSpacedLines
);
@@ -195,7 +198,8 @@ export const useEditorEvents = (
: defaultFontSize,
fontFamily: SettingsService.get().defaultFontFamily,
dateFormat: db.settings?.getDateFormat(),
timeFormat: db.settings?.getTimeFormat()
timeFormat: db.settings?.getTimeFormat(),
fontScale
});
}, [
fullscreen,
@@ -215,7 +219,8 @@ export const useEditorEvents = (
defaultFontFamily,
dateFormat,
timeFormat,
loading
loading,
fontScale
]);
const onBackPress = useCallback(async () => {

View File

@@ -628,7 +628,9 @@ export const settingsGroups: SettingSection[] = [
name: "CORS bypass proxy",
description: "You can set a custom proxy URL to increase your privacy.",
inputProperties: {
defaultValue: "https://cors.notesnook.com"
defaultValue: "https://cors.notesnook.com",
autoCorrect: false,
keyboardType: "url"
},
property: "corsProxy",
icon: "arrow-decision-outline"

View File

@@ -50,7 +50,7 @@ export function setRateAppMessage() {
const recoveryKeyMessage = {
visible: true,
message: "Keep your data safe if you lose password",
message: "Keep your data safe",
actionText: "Save your account recovery key",
onPress: () => {
verifyUser(

View File

@@ -202,7 +202,7 @@ const Tiptap = ({ settings }: { settings: Settings }) => {
>
{settings.noHeader ? null : (
<>
<Tags />
<Tags settings={settings} />
<Title
titlePlaceholder={controller.titlePlaceholder}
readonly={settings.readonly}

View File

@@ -113,7 +113,7 @@ function Header({
}}
>
<ArrowBackIcon
size={27}
size={27 * settings.fontScale}
style={{
position: "absolute"
}}
@@ -152,7 +152,7 @@ function Header({
? "var(--nn_secondary_background)"
: "var(--nn_primary_paragraph)"
}
size={25}
size={25 * settings.fontScale}
style={{
position: "absolute"
}}
@@ -182,7 +182,7 @@ function Header({
? "var(--nn_secondary_background)"
: "var(--nn_primary_paragraph)"
}
size={25}
size={25 * settings.fontScale}
style={{
position: "absolute"
}}
@@ -208,7 +208,7 @@ function Header({
}}
>
<CrownIcon
size={25}
size={25 * settings.fontScale}
style={{
position: "absolute"
}}
@@ -235,7 +235,7 @@ function Header({
}}
>
<MagnifyIcon
size={25}
size={25 * settings.fontScale}
style={{
position: "absolute"
}}
@@ -263,7 +263,7 @@ function Header({
}}
>
<FullscreenIcon
size={25}
size={25 * settings.fontScale}
style={{
position: "absolute"
}}
@@ -291,7 +291,7 @@ function Header({
}}
>
<DotsHorizontalIcon
size={25}
size={25 * settings.fontScale}
style={{
position: "absolute"
}}
@@ -310,6 +310,7 @@ export default React.memo(Header, (prev, next) => {
prev.settings.deviceMode !== next.settings.deviceMode ||
prev.settings.fullscreen !== next.settings.fullscreen ||
prev.settings.premium !== next.settings.premium ||
prev.settings.fontScale !== next.settings.fontScale ||
prev.noHeader !== next.noHeader ||
prev.hasRedo !== next.hasRedo ||
prev.hasUndo !== next.hasUndo

View File

@@ -18,10 +18,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import React, { useRef, useState } from "react";
import { EventTypes } from "../utils";
import { EventTypes, Settings } from "../utils";
import styles from "./styles.module.css";
function Tags(): JSX.Element {
function Tags(props: { settings: Settings }): JSX.Element {
const [tags, setTags] = useState<{ title: string; alias: string }[]>([]);
const editorTags = useRef({
setTags: setTags
@@ -36,6 +36,7 @@ function Tags(): JSX.Element {
}
post(EventTypes.newtag);
};
const fontScale = props.settings?.fontScale || 1;
return (
<div
@@ -83,9 +84,9 @@ function Tags(): JSX.Element {
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="20"
height="20"
viewBox="0 0 24 24"
width={20 * fontScale}
height={20 * fontScale}
viewBox={`0 0 24 24`}
>
<path
fill="var(--nn_primary_accent)"
@@ -123,4 +124,7 @@ function Tags(): JSX.Element {
);
}
export default React.memo(Tags, () => true);
export default React.memo(Tags, (prev, next) => {
if (prev.settings.fontScale !== next.settings.fontScale) return false;
return true;
});

View File

@@ -53,7 +53,7 @@ function Title({
contentEditable={!readonly}
disabled={readonly}
style={{
height: 40,
height: 40 * (settingsController.previous?.fontScale || 1),
fontSize: 25,
width: "100%",
boxSizing: "border-box",

View File

@@ -30,11 +30,13 @@ const modifyToolbarTheme = (toolbarTheme: Theme) => {
paddingX: "20px",
borderBottomWidth: 0
};
const fontScale = settingsController.previous?.fontScale
? settingsController.previous?.fontScale
: 1;
toolbarTheme.iconSizes = {
big: 20,
medium: 18,
small: 18
big: 20 * fontScale,
medium: 18 * fontScale,
small: 18 * fontScale
};
toolbarTheme.fontSizes = {
...toolbarTheme.fontSizes,

View File

@@ -44,6 +44,7 @@ export type Settings = {
fontFamily: string;
timeFormat: string;
dateFormat: string;
fontScale: number;
};
/* eslint-disable no-var */

View File

@@ -76,7 +76,7 @@ export const Clipboard = Extension.create({
}
});
export function transformCopied(slice: Slice) {
export function transformCopied(slice: Slice): any {
// when copying a single list item, we shouldn't retain the
// list formatting but copy it as a paragraph.
const maybeList = slice.content.firstChild;

View File

@@ -75,7 +75,7 @@ export function InsertBlock(props: ToolProps) {
onMouseDown={(e) => e.preventDefault()}
onClick={() => setIsOpen((s) => !s)}
>
<Icon path={Icons.plus} size={18} color={"accent"} />
<Icon path={Icons.plus} size="medium" color={"accent"} />
</Button>
<ResponsivePresenter