diff --git a/apps/expo/src/app/(tabs)/movie-web.tsx b/apps/expo/src/app/(tabs)/movie-web.tsx
index c7657ca..6644026 100644
--- a/apps/expo/src/app/(tabs)/movie-web.tsx
+++ b/apps/expo/src/app/(tabs)/movie-web.tsx
@@ -1,5 +1,60 @@
+import { useState } from "react";
+import { Link } from "expo-router";
+import { H2, H5, Paragraph, View } from "tamagui";
+
import ScreenLayout from "~/components/layout/ScreenLayout";
+import { MWButton } from "~/components/ui/Button";
+import { MWCard } from "~/components/ui/Card";
+import { MWInput } from "~/components/ui/Input";
export default function MovieWebScreen() {
- return ;
+ const [url, setUrl] = useState("https://mw-backend.lonelil.ru");
+
+ return (
+
+
+
+
+ Sync to the cloud
+
+
+ Share your watch progress between devices and keep them synced.
+
+
+ First choose the backend you want to use. If you do not know what
+ this does, use the default and click on 'Get started'.
+
+
+
+
+
+
+
+
+
+
+ Get started
+
+
+
+
+
+ );
}
diff --git a/apps/expo/src/app/sync/_layout.tsx b/apps/expo/src/app/sync/_layout.tsx
new file mode 100644
index 0000000..a6a9e05
--- /dev/null
+++ b/apps/expo/src/app/sync/_layout.tsx
@@ -0,0 +1,14 @@
+import { Stack } from "expo-router";
+
+import { BrandPill } from "~/components/BrandPill";
+
+export default function Layout() {
+ return (
+
+ );
+}
diff --git a/apps/expo/src/app/sync/trust/[url].tsx b/apps/expo/src/app/sync/trust/[url].tsx
new file mode 100644
index 0000000..ba03c54
--- /dev/null
+++ b/apps/expo/src/app/sync/trust/[url].tsx
@@ -0,0 +1,117 @@
+import { Stack, useLocalSearchParams } from "expo-router";
+import { useQuery } from "@tanstack/react-query";
+import { H4, Paragraph, Text, View } from "tamagui";
+
+import ScreenLayout from "~/components/layout/ScreenLayout";
+import { MWButton } from "~/components/ui/Button";
+import { MWCard } from "~/components/ui/Card";
+
+// TODO: extract to function with cleanup and types
+const getBackendMeta = (
+ url: string,
+): Promise<{
+ description: string;
+ hasCaptcha: boolean;
+ name: string;
+ url: string;
+}> => {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
+ return fetch(`${url}/meta`).then((res) => res.json());
+};
+
+export default function Page() {
+ const { url } = useLocalSearchParams();
+
+ const meta = useQuery({
+ queryKey: ["backendMeta", url],
+ queryFn: () => getBackendMeta(url as string),
+ });
+
+ return (
+
+
+
+
+
+ Do you trust this server?
+
+
+
+ {meta.isLoading && "Loading..."}
+ {meta.isError && "Error loading metadata"}
+ {meta.isSuccess && (
+ <>
+ You are connecting to{" "}
+
+ {url}
+
+ . Please confirm you trust it before making an account.
+ >
+ )}
+
+
+
+ {meta.isSuccess && (
+
+
+ {meta.data.name}
+
+
+
+ {meta.data.description}
+
+
+ )}
+
+ I trust this server
+ Go back
+
+
+ Already have an account?{" "}
+
+ Login here
+
+
+
+
+
+ );
+}
diff --git a/apps/expo/src/components/layout/ScreenLayout.tsx b/apps/expo/src/components/layout/ScreenLayout.tsx
index 176581d..9990e6e 100644
--- a/apps/expo/src/components/layout/ScreenLayout.tsx
+++ b/apps/expo/src/components/layout/ScreenLayout.tsx
@@ -1,3 +1,4 @@
+import type { ScrollViewProps } from "tamagui";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { ScrollView } from "tamagui";
import { LinearGradient } from "tamagui/linear-gradient";
@@ -5,26 +6,14 @@ import { LinearGradient } from "tamagui/linear-gradient";
import { Header } from "./Header";
interface Props {
- children?: React.ReactNode;
- onScrollBeginDrag?: () => void;
- onMomentumScrollEnd?: () => void;
showHeader?: boolean;
- scrollEnabled?: boolean;
- keyboardDismissMode?: "none" | "on-drag" | "interactive";
- keyboardShouldPersistTaps?: "always" | "never" | "handled";
- contentContainerStyle?: Record;
}
export default function ScreenLayout({
children,
- onScrollBeginDrag,
- onMomentumScrollEnd,
showHeader = true,
- scrollEnabled,
- keyboardDismissMode,
- keyboardShouldPersistTaps,
- contentContainerStyle,
-}: Props) {
+ ...props
+}: ScrollViewProps & Props) {
const insets = useSafeAreaInsets();
return (
@@ -47,15 +36,10 @@ export default function ScreenLayout({
>
{showHeader && }
{children}
diff --git a/apps/expo/src/components/ui/Button.tsx b/apps/expo/src/components/ui/Button.tsx
index a10ed40..7399765 100644
--- a/apps/expo/src/components/ui/Button.tsx
+++ b/apps/expo/src/components/ui/Button.tsx
@@ -7,21 +7,33 @@ export const MWButton = styled(Button, {
backgroundColor: "$buttonPrimaryBackground",
color: "$buttonPrimaryText",
fontWeight: "bold",
+ pressStyle: {
+ backgroundColor: "$buttonPrimaryBackgroundHover",
+ },
},
secondary: {
backgroundColor: "$buttonSecondaryBackground",
color: "$buttonSecondaryText",
fontWeight: "bold",
+ pressStyle: {
+ backgroundColor: "$buttonSecondaryBackgroundHover",
+ },
},
purple: {
backgroundColor: "$buttonPurpleBackground",
color: "white",
fontWeight: "bold",
+ pressStyle: {
+ backgroundColor: "$buttonPurpleBackgroundHover",
+ },
},
cancel: {
backgroundColor: "$buttonCancelBackground",
color: "white",
fontWeight: "bold",
+ pressStyle: {
+ backgroundColor: "$buttonCancelBackgroundHover",
+ },
},
},
} as const,
diff --git a/apps/expo/src/components/ui/Card.tsx b/apps/expo/src/components/ui/Card.tsx
new file mode 100644
index 0000000..34790f4
--- /dev/null
+++ b/apps/expo/src/components/ui/Card.tsx
@@ -0,0 +1,21 @@
+import { Card, styled, withStaticProperties } from "tamagui";
+
+export const MWCardFrame = styled(Card, {
+ backgroundColor: "$shade400",
+ borderColor: "$shade400",
+
+ variants: {
+ bordered: {
+ true: {
+ borderWidth: 1,
+ borderColor: "$shade500",
+ },
+ },
+ },
+});
+
+export const MWCard = withStaticProperties(MWCardFrame, {
+ Header: Card.Header,
+ Footer: Card.Footer,
+ Background: Card.Background,
+});