mobile: fix various bugs

This commit is contained in:
Ammar Ahmed
2025-02-26 16:03:59 +05:00
committed by Abdullah Atta
parent 3375439e35
commit 4e897dde47
25 changed files with 136 additions and 125 deletions

View File

@@ -42,6 +42,7 @@ import { TipManager } from "./services/tip-manager";
import { changeSystemBarColors, useThemeStore } from "./stores/use-theme-store";
import { useUserStore } from "./stores/use-user-store";
import RNBootSplash from "react-native-bootsplash";
import AppLocked from "./components/app-lock";
I18nManager.allowRTL(false);
I18nManager.forceRTL(false);
@@ -88,6 +89,7 @@ const App = (props: { configureMode: "note-preview" }) => {
<Toast />
</ScopedThemeProvider>
<DialogProvider />
<AppLocked />
</GestureHandlerRootView>
</SafeAreaProvider>
);

View File

@@ -20,7 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import React, { useCallback, useEffect, useRef } from "react";
import {
AppStateStatus,
BackHandler,
Platform,
TextInput,
useWindowDimensions,
@@ -45,17 +44,16 @@ import SettingsService from "../../services/settings";
import { useSettingStore } from "../../stores/use-setting-store";
import { useUserStore } from "../../stores/use-user-store";
import { NotesnookModule } from "../../utils/notesnook-module";
import { AppFontSize } from "../../utils/size";
import { Toast } from "../../components/toast";
import { Button } from "../../components/ui/button";
import { IconButton } from "../../components/ui/icon-button";
import Input from "../../components/ui/input";
import Seperator from "../../components/ui/seperator";
import Heading from "../../components/ui/typography/heading";
import Paragraph from "../../components/ui/typography/paragraph";
import { Toast } from "../toast";
import { Button } from "../ui/button";
import { IconButton } from "../ui/icon-button";
import Input from "../ui/input";
import Seperator from "../ui/seperator";
import Heading from "../ui/typography/heading";
import Paragraph from "../ui/typography/paragraph";
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
import { strings } from "@notesnook/intl";
import { DefaultAppStyles } from "../../utils/styles";
import { AppFontSize } from "../../utils/size";
const getUser = () => {
const user = MMKV.getString("user");
@@ -84,7 +82,7 @@ const verifyUserPassword = async (password: string) => {
}
};
const AppLockedScreen = () => {
const AppLocked = () => {
const initialLaunchBiometricRequest = useRef(true);
const { colors } = useThemeColors();
const user = getUser();
@@ -184,7 +182,13 @@ const AppLockedScreen = () => {
(prevState === "background" || initialLaunchBiometricRequest.current)
) {
if (SettingsService.shouldLockAppOnEnterForeground()) {
if (useSettingStore.getState().appDidEnterBackgroundForAction) {
useSettingStore.getState().setAppDidEnterBackgroundForAction(false);
return;
}
DatabaseLogger.info("Locking app on entering foreground");
useUserStore.getState().lockApp(true);
}
if (
@@ -205,24 +209,14 @@ const AppLockedScreen = () => {
}
}, [appState, onUnlockAppRequested, appLocked]);
useEffect(() => {
let handler: any;
if (appLocked) {
handler = BackHandler.addEventListener("hardwareBackPress", () => {
return true;
});
}
return () => {
handler?.remove();
};
}, [appLocked]);
return (
return appLocked ? (
<KeyboardAwareScrollView
style={{
backgroundColor: colors.primary.background,
width: "100%",
height: "100%"
height: "100%",
position: "absolute",
zIndex: 999
}}
contentContainerStyle={{
justifyContent: "center",
@@ -242,9 +236,9 @@ const AppLockedScreen = () => {
: Platform.OS == "ios"
? "95%"
: "100%",
paddingHorizontal: DefaultAppStyles.GAP,
paddingHorizontal: 12,
marginBottom: 30,
marginTop: DefaultAppStyles.GAP,
marginTop: 15,
alignSelf: "center"
}}
>
@@ -283,7 +277,7 @@ const AppLockedScreen = () => {
<View
style={{
width: "100%",
padding: DefaultAppStyles.GAP,
padding: 12,
backgroundColor: colors.primary.background
}}
>
@@ -345,7 +339,7 @@ const AppLockedScreen = () => {
</View>
</View>
</KeyboardAwareScrollView>
);
) : null;
};
export default AppLockedScreen;
export default AppLocked;

View File

@@ -217,7 +217,7 @@ export const Login = ({ changeMode }) => {
title={strings.forgotPassword()}
style={{
alignSelf: "flex-end",
height: 30,
paddingVertical: DefaultAppStyles.GAP_VERTICAL_SMALL,
paddingHorizontal: 0
}}
onPress={() => {
@@ -247,7 +247,6 @@ export const Login = ({ changeMode }) => {
style={{
width: 250
}}
height={50}
type="accent"
title={!loading ? strings.continue() : null}
/>
@@ -257,19 +256,16 @@ export const Login = ({ changeMode }) => {
title={strings.cancelLogin()}
style={{
alignSelf: "center",
height: 30,
marginTop: DefaultAppStyles.GAP_VERTICAL
marginTop: DefaultAppStyles.GAP_VERTICAL,
width: 250
}}
onPress={() => {
if (loading) return;
setStep(LoginSteps.emailAuth);
setLoading(false);
}}
textStyle={{
textDecorationLine: "underline"
}}
fontSize={AppFontSize.xs}
type="errorShade"
type="secondaryAccented"
/>
)}

View File

@@ -295,7 +295,7 @@ export const FluidPanels = forwardRef<TabsRef, TabProps>(function FluidTabs(
const gesture = Gesture.Pan()
.maxPointers(1)
.enabled(enabled && !disabled)
.activeOffsetX([-20, 20])
.activeOffsetX([-10, 10])
.failOffsetY([-10, 10])
.onBegin((event) => {
locked.value = false;

View File

@@ -53,6 +53,7 @@ import { TimeSince } from "../../ui/time-since";
import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
import dayjs from "dayjs";
import { useRoute } from "@react-navigation/native";
type NoteItemProps = {
item: Note | BaseTrashItem<Note>;
@@ -80,6 +81,7 @@ const NoteItem = ({
locked,
noOpen = false
}: NoteItemProps) => {
const route = useRoute();
const isEditingNote = useTabStore(
(state) =>
state.tabs.find((t) => t.id === state.currentTab)?.session?.noteId ===
@@ -93,7 +95,6 @@ const NoteItem = ({
const primaryColors = isEditingNote ? colors.selected : colors.primary;
const selectionMode = useSelectionStore((state) => state.selectionMode);
const [selected] = useIsSelected(item);
return (
<>
<View
@@ -264,6 +265,7 @@ const NoteItem = ({
{notebooks?.items
?.filter(
(item) =>
route.name !== "Notebook" ||
item.id !== useNavigationStore.getState().focusedRouteId
)
.map((item) => (

View File

@@ -210,7 +210,6 @@ export const SelectionHeader = React.memo(
{
title: strings.manageTags(),
onPress: async () => {
await sleep(100);
ManageTagsSheet.present(selectedItemsList);
},
visible: type === "note",
@@ -219,17 +218,17 @@ export const SelectionHeader = React.memo(
{
title: strings.export(),
onPress: async () => {
await sleep(100);
ExportNotesSheet.present(selectedItemsList);
},
visible: type === "note",
icon: "export"
},
{
title: strings.linkNotebook(),
title: strings.addToNotebook(),
onPress: async () => {
await sleep(100);
// MoveNoteSheet.present();
Navigation.navigate("LinkNotebooks", {
noteIds: selectedItemsList
});
},
visible: type === "note",
icon: "plus"

View File

@@ -103,12 +103,12 @@ export const AddNotebookSheet = ({
useNotebookStore.getState().refresh();
}
if (showMoveNotesOnComplete && id) {
if (showMoveNotesOnComplete && id && !notebook?.id) {
ToastManager.show({
heading: "Notebook added",
heading: strings.notebookAdded(),
type: "success",
context: "global",
actionText: "Link notes",
actionText: strings.addNotes(),
duration: 8000,
func: async () => {
Navigation.navigate("MoveNotes", {

View File

@@ -17,6 +17,7 @@ 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 { strings } from "@notesnook/intl";
import { useThemeColors } from "@notesnook/theme";
import React, { Fragment, useState } from "react";
import {
@@ -39,9 +40,11 @@ import {
} from "../../../services/event-manager";
import Exporter from "../../../services/exporter";
import PremiumService from "../../../services/premium";
import { useSettingStore } from "../../../stores/use-setting-store";
import { useUserStore } from "../../../stores/use-user-store";
import { getElevationStyle } from "../../../utils/elevation";
import { AppFontSize, defaultBorderRadius, ph, pv } from "../../../utils/size";
import { AppFontSize, defaultBorderRadius } from "../../../utils/size";
import { DefaultAppStyles } from "../../../utils/styles";
import { sleep } from "../../../utils/time";
import { Dialog } from "../../dialog";
import DialogHeader from "../../dialog/dialog-header";
@@ -52,15 +55,15 @@ import { Pressable } from "../../ui/pressable";
import Seperator from "../../ui/seperator";
import Heading from "../../ui/typography/heading";
import Paragraph from "../../ui/typography/paragraph";
import { strings } from "@notesnook/intl";
import { DefaultAppStyles } from "../../../utils/styles";
const ExportNotesSheet = ({
ids,
update
update,
close
}: {
ids: string[];
update: ((props: PresentSheetOptions) => void) | undefined;
close: ((ctx?: string) => void) | undefined;
}) => {
const { colors } = useThemeColors();
const [exporting, setExporting] = useState(false);
@@ -297,11 +300,11 @@ const ExportNotesSheet = ({
width={250}
fontSize={AppFontSize.md}
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL,
borderRadius: 100
marginTop: DefaultAppStyles.GAP_VERTICAL
}}
onPress={async () => {
if (!result?.filePath) return;
close?.();
if (Platform.OS === "android") {
Linking.openURL(result.fileDir).catch((e) => {
ToastManager.error(e as Error);
@@ -326,11 +329,14 @@ const ExportNotesSheet = ({
width={250}
fontSize={AppFontSize.md}
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL,
borderRadius: 100
marginTop: DefaultAppStyles.GAP_VERTICAL
}}
onPress={async () => {
if (!result) return;
close?.();
useSettingStore
.getState()
.setAppDidEnterBackgroundForAction(true);
if (Platform.OS === "ios") {
Share.open({
url: result?.fileDir + result.fileName
@@ -350,12 +356,11 @@ const ExportNotesSheet = ({
/>
<Button
title={strings.exportAgain()}
type="inverted"
type="secondaryAccented"
width={250}
fontSize={AppFontSize.md}
style={{
marginTop: DefaultAppStyles.GAP_VERTICAL,
borderRadius: 100
marginTop: DefaultAppStyles.GAP_VERTICAL
}}
onPress={async () => {
setComplete(false);
@@ -376,7 +381,7 @@ ExportNotesSheet.present = async (ids?: string[], allNotes?: boolean) => {
const exportNoteIds = allNotes ? await db.notes.all?.ids() : ids || [];
presentSheet({
component: (ref, close, update) => (
<ExportNotesSheet ids={exportNoteIds} update={update} />
<ExportNotesSheet ids={exportNoteIds} update={update} close={close} />
),
keyboardHandlerDisabled: true
});

View File

@@ -233,7 +233,7 @@ export const NotebookItem = ({
size={AppFontSize.md}
testID={`add-notebook-${index}`}
top={0}
left={50}
left={0}
bottom={0}
right={40}
style={{

View File

@@ -210,7 +210,7 @@ export const Toast = ({ context = "global" }) => {
toastOptions.type === "error" ? "errorShade" : "secondaryAccented"
}
onPress={toastOptions.func}
title={"Link notes"}
title={toastOptions.actionText}
height={35}
style={{
zIndex: 10

View File

@@ -623,7 +623,7 @@ export const useActions = ({
function addTo() {
Navigation.navigate("LinkNotebooks", {
note: item as Note
noteIds: [item.id]
});
close();
//MoveNoteSheet.present(item as Note);
@@ -949,7 +949,7 @@ export const useActions = ({
{
id: "notebooks",
title: strings.linkNotebooks(),
title: strings.addToNotebook(),
icon: "book-outline",
onPress: addTo
},

View File

@@ -714,7 +714,8 @@ export const useAppEvents = () => {
SettingsService.canLockAppInBackground() &&
!useSettingStore.getState().requestBiometrics &&
!useUserStore.getState().appLocked &&
!useUserStore.getState().disableAppLockRequests
!useUserStore.getState().disableAppLockRequests &&
!useSettingStore.getState().appDidEnterBackgroundForAction
) {
if (SettingsService.shouldLockAppOnEnterForeground()) {
DatabaseLogger.log(`AppEvents: Locking app on enter background`);

View File

@@ -148,7 +148,6 @@ AppNavigation.displayName = "AppNavigation";
let Intro: any = null;
let Auth: any = null;
let FluidPanelsView: any = null;
let AppLock: any = null;
let LinkNotebooks: any = null;
let MoveNotebook: any = null;
let MoveNotes: any = null;
@@ -208,14 +207,6 @@ export const RootNavigation = () => {
}}
/>
<RootStack.Screen
name="AppLock"
getComponent={() => {
AppLock = AppLock || require("../screens/app-lock").default;
return AppLock;
}}
/>
<RootStack.Screen
name="LinkNotebooks"
getComponent={() => {

View File

@@ -90,6 +90,7 @@ async function updateInitialSelectionState(items: string[]) {
}
const LinkNotebooks = (props: NavigationProps<"LinkNotebooks">) => {
const noteIds = props.route.params?.noteIds;
const { colors } = useThemeColors();
const [notebooks, loading] = useNotebooks();
const tree = useNotebookTreeStore((state) => state.tree);
@@ -148,10 +149,7 @@ const LinkNotebooks = (props: NavigationProps<"LinkNotebooks">) => {
);
useEffect(() => {
const items = props.route.params.note
? [props.route.params.note.id]
: selectedItemsList;
updateInitialSelectionState(items);
updateInitialSelectionState(noteIds);
return () => {
useNotebookSelectionStore.setState({
initialState: {},
@@ -160,15 +158,10 @@ const LinkNotebooks = (props: NavigationProps<"LinkNotebooks">) => {
canEnableMultiSelectMode: true
});
};
}, [props.route.params.note, selectedItemsList]);
}, [noteIds]);
const onSave = async () => {
const noteIds = props.route.params.note
? [props.route.params.note.id]
: selectedItemsList;
const changedNotebooks = useNotebookSelectionStore.getState().selection;
for (const id in changedNotebooks) {
const item = await db.notebooks.notebook(id);
if (!item) continue;
@@ -206,17 +199,14 @@ const LinkNotebooks = (props: NavigationProps<"LinkNotebooks">) => {
}}
>
<Header
title="Link Notebooks"
title={strings.addToNotebook()}
canGoBack
rightButton={
hasSelection
? {
name: "restore",
onPress: () => {
const items = props.route.params.note
? [props.route.params.note.id]
: selectedItemsList;
updateInitialSelectionState(items);
updateInitialSelectionState(noteIds);
}
}
: undefined

View File

@@ -73,6 +73,9 @@ const ProfilePicPlaceholder = (props) => {
};
const onChangePicture = () => {
useUserStore.setState({
disableAppLockRequests: true
});
const theme =
useThemeStore.getState().colorScheme === "dark"
? useThemeStore.getState().darkTheme
@@ -93,7 +96,8 @@ const onChangePicture = () => {
cropperToolbarTitle: strings.editProfilePicture(),
cropperActiveWidgetColor: theme.scopes.base.primary.accent,
cropperToolbarWidgetColor: theme.scopes.base.primary.icon
}).then(async (image) => {
})
.then(async (image) => {
if (!image.data) return;
await db.settings.setProfile({
profilePicture: "data:image/jpeg;base64," + image.data
@@ -101,6 +105,13 @@ const onChangePicture = () => {
useUserStore.setState({
profile: db.settings.getProfile()
});
})
.finally(() => {
setTimeout(() => {
useUserStore.setState({
disableAppLockRequests: false
});
}, 1000);
});
};

View File

@@ -38,6 +38,7 @@ import filesystem from "../common/filesystem";
import downloadAttachment from "../common/filesystem/download-attachment";
import { cacheDir } from "../common/filesystem/utils";
import { unlockVault } from "../utils/unlock-vault";
import { useUserStore } from "../stores/use-user-store";
const FolderNames: { [name: string]: string } = {
txt: "Text",
@@ -52,7 +53,15 @@ async function getPath(type: string) {
(await filesystem.checkAndCreateDir(`/exported/${type}/`));
if (Platform.OS === "android") {
useUserStore.setState({
disableAppLockRequests: true
});
const file = await ScopedStorage.openDocumentTree(true);
setTimeout(() => {
useUserStore.setState({
disableAppLockRequests: false
});
}, 1000);
if (!file) return;
path = file.uri;
}

View File

@@ -82,7 +82,7 @@ export interface RouteParams extends ParamListBase {
Settings: GenericRouteParam;
Auth: AuthParams;
LinkNotebooks: {
note?: Note;
noteIds: string[];
};
MoveNotebook: {
selectedNotebooks: Notebook[];

View File

@@ -1,74 +1,74 @@
/* open-sans-regular - latin */
@font-face {
font-family: "Open Sans";
font-family: "Inter";
font-display: swap;
font-style: normal;
font-weight: 400;
src: local("Open Sans"), url(./fonts/OpenSans-Regular.ttf) format("truetype");
src: local("Inter"), url(./fonts/Inter-Regular.ttf) format("truetype");
}
/* open-sans-italic - latin */
@font-face {
font-family: "Open Sans";
font-family: "Inter";
font-display: swap;
font-style: italic;
font-weight: 400;
src: local("Open Sans"), url(./fonts/OpenSans-Italic.ttf) format("truetype");
src: local("Inter"), url(./fonts/Inter-Italic.ttf) format("truetype");
}
/* open-sans-600 - latin */
@font-face {
font-family: "Open Sans";
font-family: "Inter";
font-display: swap;
font-style: normal;
font-weight: 500;
src: local("Open Sans"), url(./fonts/OpenSans-Medium.ttf) format("truetype");
src: local("Inter"), url(./fonts/Inter-Medium.ttf) format("truetype");
}
/* open-sans-600italic - latin */
@font-face {
font-family: "Open Sans";
font-family: "Inter";
font-display: swap;
font-style: italic;
font-weight: 500;
src: local("Open Sans"),
url(./fonts/OpenSans-MediumItalic.ttf) format("truetype");
src: local("Inter"),
url(./fonts/Inter-MediumItalic.ttf) format("truetype");
}
/* open-sans-600 - latin */
@font-face {
font-family: "Open Sans";
font-family: "Inter";
font-display: swap;
font-style: normal;
font-weight: 600;
src: local("Open Sans"), url(./fonts/OpenSans-SemiBold.ttf) format("truetype");
src: local("Inter"), url(./fonts/Inter-SemiBold.ttf) format("truetype");
}
/* open-sans-600italic - latin */
@font-face {
font-family: "Open Sans";
font-family: "Inter";
font-display: swap;
font-style: italic;
font-weight: 600;
src: local("Open Sans"),
url(./fonts/OpenSans-SemiBoldItalic.ttf) format("truetype");
src: local("Inter"),
url(./fonts/Inter-SemiBoldItalic.ttf) format("truetype");
}
/* open-sans-700 - latin */
@font-face {
font-family: "Open Sans";
font-family: "Inter";
font-display: swap;
font-style: normal;
font-weight: 700;
src: local("Open Sans"), url(./fonts/OpenSans-Bold.ttf) format("truetype");
src: local("Inter"), url(./fonts/Inter-Bold.ttf) format("truetype");
}
/* open-sans-700italic - latin */
@font-face {
font-family: "Open Sans";
font-family: "Inter";
font-display: swap;
font-style: italic;
font-weight: 700;
src: local("Open Sans"),
url(./fonts/OpenSans-BoldItalic.ttf) format("truetype");
src: local("Inter"),
url(./fonts/Inter-BoldItalic.ttf) format("truetype");
}

View File

@@ -12,11 +12,11 @@
<style>
body {
height: 100%;
font-family: "Open Sans";
font-family: "Inter";
}
p {
font-family: "Open Sans";
font-family: "Inter";
/* color: var(--nn_primary_paragraph) ## TODO: use fixed color */
}

View File

@@ -75,7 +75,7 @@
border-radius: 0;
padding: 1rem 0.6rem !important;
color: var(--nn_primary_paragraph);
font-family: "Open Sans";
font-family: "Inter";
padding: 12px 6px;
}

View File

@@ -74,7 +74,7 @@ function Tags(props: { settings: Settings; loading?: boolean }): JSX.Element {
marginRight: 5,
borderRadius: 100,
padding: "0px 10px",
fontFamily: "Open Sans",
fontFamily: "Inter",
display: "flex",
alignItems: "center",
height: "30px",
@@ -119,7 +119,7 @@ function Tags(props: { settings: Settings; loading?: boolean }): JSX.Element {
borderRadius: 100,
padding: "0px 10px",
height: "30px",
fontFamily: "Open Sans",
fontFamily: "Inter",
fontSize: 13,
color: "var(--nn_primary_icon)",
userSelect: "none",

View File

@@ -91,7 +91,7 @@ function Title({
paddingRight: 10,
paddingLeft: 10,
fontWeight: 600,
fontFamily: getFontById(fontFamily)?.font || "Open Sans",
fontFamily: getFontById(fontFamily)?.font || "Inter",
boxSizing: "border-box",
fontSize: 25,
zIndex: -1,
@@ -122,7 +122,7 @@ function Title({
paddingRight: 10,
paddingLeft: 10,
fontWeight: 600,
fontFamily: getFontById(fontFamily)?.font || "Open Sans",
fontFamily: getFontById(fontFamily)?.font || "Inter",
backgroundColor: "transparent",
color: "var(--nn_primary_heading)",
caretColor: "var(--nn_primary_accent)",

View File

@@ -3984,6 +3984,10 @@ msgstr "notebook"
msgid "Notebook"
msgstr "Notebook"
#: src/strings.ts:2452
msgid "Notebook added"
msgstr "Notebook added"
#: src/strings.ts:306
msgid "notebooks"
msgstr "notebooks"

View File

@@ -3964,6 +3964,10 @@ msgstr ""
msgid "Notebook"
msgstr ""
#: src/strings.ts:2452
msgid "Notebook added"
msgstr ""
#: src/strings.ts:306
msgid "notebooks"
msgstr ""

View File

@@ -2456,5 +2456,8 @@ Use this if changes from other devices are not appearing on this device. This wi
used: () => t`used`,
editProfile: () => t`Edit profile`,
linkNotes: () => t`Link notes`,
linkingNotesTo: (title: string) => t`Select notes to link to "${title}"`
linkingNotesTo: (title: string) => t`Select notes to link to "${title}"`,
addToNotebook: () => t`Add to notebook`,
notebookAdded: () => t`Notebook added`,
addNotes: () => t`Add notes`
};