mirror of
https://github.com/movie-web/native-app.git
synced 2025-09-13 18:13:25 +00:00
add switch theme, remove unneeded search bar context
This commit is contained in:
@@ -1,4 +1,3 @@
|
|||||||
import { useRef } from "react";
|
|
||||||
import { Platform } from "react-native";
|
import { Platform } from "react-native";
|
||||||
import * as Haptics from "expo-haptics";
|
import * as Haptics from "expo-haptics";
|
||||||
import { Tabs } from "expo-router";
|
import { Tabs } from "expo-router";
|
||||||
@@ -8,28 +7,18 @@ import { useTheme, View } from "tamagui";
|
|||||||
import { MovieWebSvg } from "~/components/Icon";
|
import { MovieWebSvg } from "~/components/Icon";
|
||||||
import SvgTabBarIcon from "~/components/SvgTabBarIcon";
|
import SvgTabBarIcon from "~/components/SvgTabBarIcon";
|
||||||
import TabBarIcon from "~/components/TabBarIcon";
|
import TabBarIcon from "~/components/TabBarIcon";
|
||||||
import SearchTabContext from "../../components/ui/SearchTabContext";
|
|
||||||
|
|
||||||
export default function TabLayout() {
|
export default function TabLayout() {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
||||||
const focusSearchInputRef = useRef(() => {});
|
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SearchTabContext.Provider value={{ focusSearchInputRef }}>
|
|
||||||
<Tabs
|
<Tabs
|
||||||
sceneContainerStyle={{
|
sceneContainerStyle={{
|
||||||
backgroundColor: theme.screenBackground.val,
|
backgroundColor: theme.screenBackground.val,
|
||||||
}}
|
}}
|
||||||
screenListeners={({ route }) => ({
|
screenListeners={() => ({
|
||||||
tabPress: () => {
|
tabPress: () => {
|
||||||
void Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
void Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
||||||
switch (route.name) {
|
|
||||||
case "search":
|
|
||||||
focusSearchInputRef.current();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
focus: () => {
|
focus: () => {
|
||||||
void ScreenOrientation.lockAsync(
|
void ScreenOrientation.lockAsync(
|
||||||
@@ -121,6 +110,5 @@ export default function TabLayout() {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</SearchTabContext.Provider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -11,7 +11,6 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
Separator,
|
Separator,
|
||||||
Sheet,
|
Sheet,
|
||||||
Switch,
|
|
||||||
Text,
|
Text,
|
||||||
useTheme,
|
useTheme,
|
||||||
View,
|
View,
|
||||||
@@ -21,6 +20,7 @@ import {
|
|||||||
|
|
||||||
import type { ThemeStoreOption } from "~/stores/theme";
|
import type { ThemeStoreOption } from "~/stores/theme";
|
||||||
import ScreenLayout from "~/components/layout/ScreenLayout";
|
import ScreenLayout from "~/components/layout/ScreenLayout";
|
||||||
|
import { MWSwitch } from "~/components/ui/Switch";
|
||||||
import { checkForUpdate } from "~/lib/update";
|
import { checkForUpdate } from "~/lib/update";
|
||||||
import { getGestureControls, saveGestureControls } from "~/settings";
|
import { getGestureControls, saveGestureControls } from "~/settings";
|
||||||
import { useThemeStore } from "~/stores/theme";
|
import { useThemeStore } from "~/stores/theme";
|
||||||
@@ -76,14 +76,12 @@ export default function SettingsScreen() {
|
|||||||
<XStack width={200} alignItems="center" gap="$4">
|
<XStack width={200} alignItems="center" gap="$4">
|
||||||
<Label minWidth={110}>Gesture controls</Label>
|
<Label minWidth={110}>Gesture controls</Label>
|
||||||
<Separator minHeight={20} vertical />
|
<Separator minHeight={20} vertical />
|
||||||
<Switch
|
<MWSwitch
|
||||||
size="$4"
|
|
||||||
native
|
|
||||||
checked={gestureControlsEnabled}
|
checked={gestureControlsEnabled}
|
||||||
onCheckedChange={handleGestureControlsToggle}
|
onCheckedChange={handleGestureControlsToggle}
|
||||||
>
|
>
|
||||||
<Switch.Thumb animation="quicker" />
|
<MWSwitch.Thumb animation="quicker" />
|
||||||
</Switch>
|
</MWSwitch>
|
||||||
</XStack>
|
</XStack>
|
||||||
</YStack>
|
</YStack>
|
||||||
</View>
|
</View>
|
||||||
|
@@ -1,51 +1,28 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
||||||
import type { ButtonProps } from "tamagui";
|
|
||||||
import React from "react";
|
|
||||||
import { Button, styled } from "tamagui";
|
import { Button, styled } from "tamagui";
|
||||||
|
|
||||||
const PrimaryButton = styled(Button, {
|
export const MWButton = styled(Button, {
|
||||||
|
variants: {
|
||||||
|
type: {
|
||||||
|
primary: {
|
||||||
backgroundColor: "$buttonPrimaryBackground",
|
backgroundColor: "$buttonPrimaryBackground",
|
||||||
color: "$buttonPrimaryText",
|
color: "$buttonPrimaryText",
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
});
|
},
|
||||||
|
secondary: {
|
||||||
const SecondaryButton = styled(Button, {
|
|
||||||
backgroundColor: "$buttonSecondaryBackground",
|
backgroundColor: "$buttonSecondaryBackground",
|
||||||
color: "$buttonSecondaryText",
|
color: "$buttonSecondaryText",
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
});
|
},
|
||||||
|
purple: {
|
||||||
const PurpleButton = styled(Button, {
|
|
||||||
backgroundColor: "$buttonPurpleBackground",
|
backgroundColor: "$buttonPurpleBackground",
|
||||||
color: "white",
|
color: "white",
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
});
|
},
|
||||||
|
cancel: {
|
||||||
const CancelButton = styled(Button, {
|
|
||||||
backgroundColor: "$buttonCancelBackground",
|
backgroundColor: "$buttonCancelBackground",
|
||||||
color: "white",
|
color: "white",
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as const,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const MWButton = React.forwardRef<
|
|
||||||
typeof Button,
|
|
||||||
ButtonProps & {
|
|
||||||
type?: "primary" | "secondary" | "purple" | "cancel";
|
|
||||||
}
|
|
||||||
>((props, ref) => {
|
|
||||||
const { type, ...rest } = props;
|
|
||||||
switch (type) {
|
|
||||||
case "primary":
|
|
||||||
return <PrimaryButton {...rest} ref={ref as any} />;
|
|
||||||
case "secondary":
|
|
||||||
return <SecondaryButton {...rest} ref={ref as any} />;
|
|
||||||
case "purple":
|
|
||||||
return <PurpleButton {...rest} ref={ref as any} />;
|
|
||||||
case "cancel":
|
|
||||||
return <CancelButton {...rest} ref={ref as any} />;
|
|
||||||
default:
|
|
||||||
return <Button {...rest} ref={ref as any} />;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
MWButton.displayName = "MWButton";
|
|
||||||
|
@@ -1,8 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
|
|
||||||
const SearchTabContext = React.createContext({
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
||||||
focusSearchInputRef: { current: () => {} },
|
|
||||||
});
|
|
||||||
|
|
||||||
export default SearchTabContext;
|
|
@@ -1,10 +1,9 @@
|
|||||||
import { useContext, useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { Keyboard } from "react-native";
|
import { Keyboard } from "react-native";
|
||||||
import { FontAwesome5 } from "@expo/vector-icons";
|
import { FontAwesome5 } from "@expo/vector-icons";
|
||||||
|
import { useIsFocused } from "@react-navigation/native";
|
||||||
import { Input, styled, useTheme, View } from "tamagui";
|
import { Input, styled, useTheme, View } from "tamagui";
|
||||||
|
|
||||||
import SearchTabContext from "./SearchTabContext";
|
|
||||||
|
|
||||||
const SearchInput = styled(Input, {
|
const SearchInput = styled(Input, {
|
||||||
backgroundColor: "$searchBackground",
|
backgroundColor: "$searchBackground",
|
||||||
borderColor: "$colorTransparent",
|
borderColor: "$colorTransparent",
|
||||||
@@ -22,17 +21,16 @@ export function SearchBar({
|
|||||||
onSearchChange: (text: string) => void;
|
onSearchChange: (text: string) => void;
|
||||||
}) {
|
}) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
const pageIsFocused = useIsFocused();
|
||||||
const [keyword, setKeyword] = useState("");
|
const [keyword, setKeyword] = useState("");
|
||||||
const [isFocused, setIsFocused] = useState(false);
|
const [isFocused, setIsFocused] = useState(false);
|
||||||
const inputRef = useRef<Input>(null);
|
const inputRef = useRef<Input>(null);
|
||||||
|
|
||||||
const { focusSearchInputRef } = useContext(SearchTabContext);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
focusSearchInputRef.current = () => {
|
if (pageIsFocused) {
|
||||||
inputRef.current?.focus();
|
inputRef.current?.focus();
|
||||||
};
|
}
|
||||||
}, [focusSearchInputRef]);
|
}, [pageIsFocused]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const keyboardDidShowListener = Keyboard.addListener(
|
const keyboardDidShowListener = Keyboard.addListener(
|
||||||
|
27
apps/expo/src/components/ui/Switch.tsx
Normal file
27
apps/expo/src/components/ui/Switch.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import type { SwitchProps } from "tamagui";
|
||||||
|
import { Switch, useTheme } from "tamagui";
|
||||||
|
|
||||||
|
const MWSwitch = (props: SwitchProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
return (
|
||||||
|
<Switch
|
||||||
|
native
|
||||||
|
nativeProps={{
|
||||||
|
trackColor: {
|
||||||
|
true: theme.switchActiveTrackColor.val,
|
||||||
|
false: theme.switchInactiveTrackColor.val,
|
||||||
|
},
|
||||||
|
thumbColor: theme.switchThumbColor.val,
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const MWSwitchThumb = (props: any) => {
|
||||||
|
return <Switch.Thumb animation="quicker" {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
MWSwitch.Thumb = MWSwitchThumb;
|
||||||
|
|
||||||
|
export { MWSwitch };
|
@@ -36,9 +36,8 @@ export async function checkForUpdate(): Promise<string | undefined> {
|
|||||||
|
|
||||||
if (!res) return;
|
if (!res) return;
|
||||||
|
|
||||||
const latestVersion: string = res.data.tag_name;
|
const latestVersion = res.data.tag_name;
|
||||||
const currentVersion: string =
|
const currentVersion = Application.nativeApplicationVersion ?? "0.0.0";
|
||||||
Application.nativeApplicationVersion ?? "0.0.0";
|
|
||||||
|
|
||||||
if (isVersionHigher(latestVersion, currentVersion)) {
|
if (isVersionHigher(latestVersion, currentVersion)) {
|
||||||
return res.data.html_url;
|
return res.data.html_url;
|
||||||
|
@@ -73,6 +73,10 @@ const createThemeConfig = (tokens: Tokens) => ({
|
|||||||
buttonPurpleBackgroundHover: tokens.purple.c400,
|
buttonPurpleBackgroundHover: tokens.purple.c400,
|
||||||
buttonCancelBackground: tokens.ash.c500,
|
buttonCancelBackground: tokens.ash.c500,
|
||||||
buttonCancelBackgroundHover: tokens.ash.c300,
|
buttonCancelBackgroundHover: tokens.ash.c300,
|
||||||
|
|
||||||
|
switchActiveTrackColor: tokens.purple.c300,
|
||||||
|
switchInactiveTrackColor: tokens.ash.c500,
|
||||||
|
switchThumbColor: tokens.white,
|
||||||
});
|
});
|
||||||
|
|
||||||
const openSansFace = {
|
const openSansFace = {
|
||||||
|
@@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"prettier": "@movie-web/prettier-config",
|
"prettier": "@movie-web/prettier-config",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@movie-web/providers": "^2.2.2",
|
"@movie-web/providers": "^2.2.4",
|
||||||
"parse-hls": "^1.0.7",
|
"parse-hls": "^1.0.7",
|
||||||
"srt-webvtt": "^2.0.0",
|
"srt-webvtt": "^2.0.0",
|
||||||
"tmdb-ts": "^1.6.1"
|
"tmdb-ts": "^1.6.1"
|
||||||
|
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@@ -235,8 +235,8 @@ importers:
|
|||||||
packages/provider-utils:
|
packages/provider-utils:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@movie-web/providers':
|
'@movie-web/providers':
|
||||||
specifier: ^2.2.2
|
specifier: ^2.2.4
|
||||||
version: 2.2.2
|
version: 2.2.4
|
||||||
parse-hls:
|
parse-hls:
|
||||||
specifier: ^1.0.7
|
specifier: ^1.0.7
|
||||||
version: 1.0.7
|
version: 1.0.7
|
||||||
@@ -2865,8 +2865,8 @@ packages:
|
|||||||
tslib: 2.6.2
|
tslib: 2.6.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@movie-web/providers@2.2.2:
|
/@movie-web/providers@2.2.4:
|
||||||
resolution: {integrity: sha512-pTlErE5bdu+b68mUW2YAKOJKz2hwSx63auGAfTkGQ+0SHDMlCV9QQ8S8O9IoSsvdXps7/YlWJWOMX8pmKuYbPQ==}
|
resolution: {integrity: sha512-c10ffR7/oPMbVwpD+Lw0/k5jvx51NbywGJtogzRjeXqDr01o5+pitPeN1qSGaqTg5FBlipn7NSesrd+cczDDQw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
cheerio: 1.0.0-rc.12
|
cheerio: 1.0.0-rc.12
|
||||||
cookie: 0.6.0
|
cookie: 0.6.0
|
||||||
|
Reference in New Issue
Block a user