diff --git a/apps/mobile/app/common/database/index.js b/apps/mobile/app/common/database/index.js index 375934bd7..99dc219fc 100644 --- a/apps/mobile/app/common/database/index.js +++ b/apps/mobile/app/common/database/index.js @@ -28,29 +28,7 @@ import filesystem from "../filesystem"; import Storage from "./storage"; import { RNSqliteDriver } from "./sqlite.kysely"; import { getDatabaseKey } from "./encryption"; - -database.host( - __DEV__ - ? { - API_HOST: "https://api.notesnook.com", - AUTH_HOST: "https://auth.streetwriters.co", - SSE_HOST: "https://events.streetwriters.co", - SUBSCRIPTIONS_HOST: "https://subscriptions.streetwriters.co", - ISSUES_HOST: "https://issues.streetwriters.co" - // API_HOST: "http://192.168.43.5:5264", - // AUTH_HOST: "http://192.168.43.5:8264", - // SSE_HOST: "http://192.168.43.5:7264", - // SUBSCRIPTIONS_HOST: "http://192.168.43.5:9264", - // ISSUES_HOST: "http://192.168.43.5:2624" - } - : { - API_HOST: "https://api.notesnook.com", - AUTH_HOST: "https://auth.streetwriters.co", - SSE_HOST: "https://events.streetwriters.co", - SUBSCRIPTIONS_HOST: "https://subscriptions.streetwriters.co", - ISSUES_HOST: "https://issues.streetwriters.co" - } -); +import SettingsService from "../../services/settings"; export async function setupDatabase(password) { const key = await getDatabaseKey(password); @@ -59,6 +37,15 @@ export async function setupDatabase(password) { console.log("Opening database with key:", !!key); + database.host({ + API_HOST: "https://api.notesnook.com", + AUTH_HOST: "https://auth.streetwriters.co", + SSE_HOST: "https://events.streetwriters.co", + SUBSCRIPTIONS_HOST: "https://subscriptions.streetwriters.co", + ISSUES_HOST: "https://issues.streetwriters.co", + ...(SettingsService.getProperty("serverUrls") || {}) + }); + database.setup({ storage: Storage, eventsource: Platform.OS === "ios" ? EventSource : AndroidEventSource, diff --git a/apps/mobile/app/components/ui/button/index.tsx b/apps/mobile/app/components/ui/button/index.tsx index c69e4a378..f594c38f6 100644 --- a/apps/mobile/app/components/ui/button/index.tsx +++ b/apps/mobile/app/components/ui/button/index.tsx @@ -112,7 +112,7 @@ export const Button = ({ NativeTooltip.show(event, tooltipText, NativeTooltip.POSITIONS.TOP); } }} - disabled={loading} + disabled={loading || restProps.disabled} type={type} accentColor={accentColor} accentText={accentText} @@ -132,6 +132,7 @@ export const Button = ({ justifyContent: "center", alignItems: "center", flexDirection: "row", + opacity: restProps?.disabled ? 0.5 : 1, ...(style as ViewStyle) }} > diff --git a/apps/mobile/app/components/ui/input/index.tsx b/apps/mobile/app/components/ui/input/index.tsx index 7dcab8abf..6316354ad 100644 --- a/apps/mobile/app/components/ui/input/index.tsx +++ b/apps/mobile/app/components/ui/input/index.tsx @@ -41,6 +41,7 @@ import { SIZE } from "../../../utils/size"; import { IconButton } from "../icon-button"; import Paragraph from "../typography/paragraph"; import phone from "phone"; +import isURL from "validator/lib/isURL"; interface InputProps extends TextInputProps { fwdRef?: RefObject; @@ -49,7 +50,8 @@ interface InputProps extends TextInputProps { | "email" | "confirmPassword" | "username" - | "phonenumber"; + | "phonenumber" + | "url"; loading?: boolean; onSubmit?: ( event: NativeSyntheticEvent @@ -151,6 +153,9 @@ const Input = ({ case "confirmPassword": isError = customValidator && value === customValidator(); break; + case "url": + isError = isURL(value); + break; case "phonenumber": { const result = phone(value, { strictDetection: true, diff --git a/apps/mobile/app/screens/settings/components.tsx b/apps/mobile/app/screens/settings/components.tsx index efd2909ac..f1e26f5f0 100644 --- a/apps/mobile/app/screens/settings/components.tsx +++ b/apps/mobile/app/screens/settings/components.tsx @@ -37,6 +37,7 @@ import { } from "./picker/pickers"; import ThemeSelector from "./theme-selector"; import { RestoreBackup } from "./restore-backup"; +import { ServersConfiguration } from "./server-config"; export const components: { [name: string]: ReactElement } = { colorpicker: , @@ -55,5 +56,6 @@ export const components: { [name: string]: ReactElement } = { "theme-selector": , "applock-timer": , autobackupsattachments: , - backuprestore: + backuprestore: , + "server-config": }; diff --git a/apps/mobile/app/screens/settings/server-config.tsx b/apps/mobile/app/screens/settings/server-config.tsx new file mode 100644 index 000000000..c1661658d --- /dev/null +++ b/apps/mobile/app/screens/settings/server-config.tsx @@ -0,0 +1,201 @@ +/* +This file is part of the Notesnook project (https://notesnook.com/) + +Copyright (C) 2023 Streetwriters (Private) Limited + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +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 . +*/ + +import { useThemeColors } from "@notesnook/theme"; +import React, { useState } from "react"; +import { View } from "react-native"; +import { presentDialog } from "../../components/dialog/functions"; +import { Button } from "../../components/ui/button"; +import Input from "../../components/ui/input"; +import { Notice } from "../../components/ui/notice"; +import Paragraph from "../../components/ui/typography/paragraph"; +import SettingsService from "../../services/settings"; +import { HostId, HostIds } from "../../stores/use-setting-store"; +import { useUserStore } from "../../stores/use-user-store"; + +export const ServerIds = ["notesnook-sync", "auth", "sse"] as const; +export type ServerId = (typeof ServerIds)[number]; +type Server = { + id: ServerId; + host: HostId; + title: string; + example: string; + description: string; +}; +type VersionResponse = { + version: string; + id: string; + instance: string; +}; +const SERVERS: Server[] = [ + { + id: "notesnook-sync", + host: "API_HOST", + title: "Sync server", + example: "http://localhost:4326", + description: "Server used to sync your notes & other data between devices." + }, + { + id: "auth", + host: "AUTH_HOST", + title: "Auth server", + example: "http://localhost:5326", + description: "Server used for login/sign up and authentication." + }, + { + id: "sse", + host: "SSE_HOST", + title: "Events server", + example: "http://localhost:7326", + description: "Server used to receive important notifications & events." + } +]; +export function ServersConfiguration() { + const { colors } = useThemeColors(); + const [error, setError] = useState(); + const [success, setSuccess] = useState(); + const [urls, setUrls] = useState>>( + SettingsService.getProperty("serverUrls") || {} + ); + const isLoggedIn = useUserStore((state) => !!state.user); + + return ( + + {isLoggedIn ? ( + + ) : null} + + {SERVERS.map((server) => ( + + setUrls((s) => { + s[server.host] = value; + return s; + }) + } + /> + ))} + + {error ? ( + + {error} + + ) : null} + + {success === true ? ( + + Connected to all servers sucessfully. + + ) : null} + +