mirror of
https://github.com/movie-web/native-app.git
synced 2025-09-13 14:43: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 * as Haptics from "expo-haptics";
|
||||
import { Tabs } from "expo-router";
|
||||
@@ -8,119 +7,108 @@ import { useTheme, View } from "tamagui";
|
||||
import { MovieWebSvg } from "~/components/Icon";
|
||||
import SvgTabBarIcon from "~/components/SvgTabBarIcon";
|
||||
import TabBarIcon from "~/components/TabBarIcon";
|
||||
import SearchTabContext from "../../components/ui/SearchTabContext";
|
||||
|
||||
export default function TabLayout() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
const focusSearchInputRef = useRef(() => {});
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<SearchTabContext.Provider value={{ focusSearchInputRef }}>
|
||||
<Tabs
|
||||
sceneContainerStyle={{
|
||||
backgroundColor: theme.screenBackground.val,
|
||||
<Tabs
|
||||
sceneContainerStyle={{
|
||||
backgroundColor: theme.screenBackground.val,
|
||||
}}
|
||||
screenListeners={() => ({
|
||||
tabPress: () => {
|
||||
void Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
||||
},
|
||||
focus: () => {
|
||||
void ScreenOrientation.lockAsync(
|
||||
ScreenOrientation.OrientationLock.PORTRAIT_UP,
|
||||
);
|
||||
},
|
||||
})}
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
tabBarActiveTintColor: theme.tabBarIconFocused.val,
|
||||
tabBarStyle: {
|
||||
backgroundColor: theme.tabBarBackground.val,
|
||||
borderTopColor: "transparent",
|
||||
borderTopRightRadius: 20,
|
||||
borderTopLeftRadius: 20,
|
||||
paddingBottom: Platform.select({ ios: 100 }),
|
||||
height: 80,
|
||||
},
|
||||
tabBarItemStyle: {
|
||||
paddingVertical: 18,
|
||||
height: 82,
|
||||
},
|
||||
tabBarLabelStyle: [
|
||||
{
|
||||
marginTop: 2,
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
<Tabs.Screen
|
||||
name="index"
|
||||
options={{
|
||||
title: "Home",
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<TabBarIcon name="home" focused={focused} />
|
||||
),
|
||||
}}
|
||||
screenListeners={({ route }) => ({
|
||||
tabPress: () => {
|
||||
void Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
||||
switch (route.name) {
|
||||
case "search":
|
||||
focusSearchInputRef.current();
|
||||
break;
|
||||
}
|
||||
},
|
||||
focus: () => {
|
||||
void ScreenOrientation.lockAsync(
|
||||
ScreenOrientation.OrientationLock.PORTRAIT_UP,
|
||||
);
|
||||
},
|
||||
})}
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
tabBarActiveTintColor: theme.tabBarIconFocused.val,
|
||||
tabBarStyle: {
|
||||
backgroundColor: theme.tabBarBackground.val,
|
||||
borderTopColor: "transparent",
|
||||
borderTopRightRadius: 20,
|
||||
borderTopLeftRadius: 20,
|
||||
paddingBottom: Platform.select({ ios: 100 }),
|
||||
height: 80,
|
||||
},
|
||||
tabBarItemStyle: {
|
||||
paddingVertical: 18,
|
||||
height: 82,
|
||||
},
|
||||
tabBarLabelStyle: [
|
||||
{
|
||||
marginTop: 2,
|
||||
},
|
||||
],
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="downloads"
|
||||
options={{
|
||||
title: "Downloads",
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<TabBarIcon name="download" focused={focused} />
|
||||
),
|
||||
}}
|
||||
>
|
||||
<Tabs.Screen
|
||||
name="index"
|
||||
options={{
|
||||
title: "Home",
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<TabBarIcon name="home" focused={focused} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="downloads"
|
||||
options={{
|
||||
title: "Downloads",
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<TabBarIcon name="download" focused={focused} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="search"
|
||||
options={{
|
||||
title: "Search",
|
||||
tabBarLabel: "",
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<View
|
||||
top={2}
|
||||
height={56}
|
||||
width={56}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
overflow="hidden"
|
||||
borderRadius={100}
|
||||
backgroundColor={
|
||||
focused ? theme.tabBarIconFocused : theme.tabBarIcon
|
||||
}
|
||||
>
|
||||
<TabBarIcon name="search" color="#FFF" />
|
||||
</View>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="movie-web"
|
||||
options={{
|
||||
title: "movie-web",
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<SvgTabBarIcon focused={focused}>
|
||||
<MovieWebSvg />
|
||||
</SvgTabBarIcon>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="settings"
|
||||
options={{
|
||||
title: "Settings",
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<TabBarIcon name="cog" focused={focused} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Tabs>
|
||||
</SearchTabContext.Provider>
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="search"
|
||||
options={{
|
||||
title: "Search",
|
||||
tabBarLabel: "",
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<View
|
||||
top={2}
|
||||
height={56}
|
||||
width={56}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
overflow="hidden"
|
||||
borderRadius={100}
|
||||
backgroundColor={
|
||||
focused ? theme.tabBarIconFocused : theme.tabBarIcon
|
||||
}
|
||||
>
|
||||
<TabBarIcon name="search" color="#FFF" />
|
||||
</View>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="movie-web"
|
||||
options={{
|
||||
title: "movie-web",
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<SvgTabBarIcon focused={focused}>
|
||||
<MovieWebSvg />
|
||||
</SvgTabBarIcon>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="settings"
|
||||
options={{
|
||||
title: "Settings",
|
||||
tabBarIcon: ({ focused }) => (
|
||||
<TabBarIcon name="cog" focused={focused} />
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
|
@@ -11,7 +11,6 @@ import {
|
||||
Select,
|
||||
Separator,
|
||||
Sheet,
|
||||
Switch,
|
||||
Text,
|
||||
useTheme,
|
||||
View,
|
||||
@@ -21,6 +20,7 @@ import {
|
||||
|
||||
import type { ThemeStoreOption } from "~/stores/theme";
|
||||
import ScreenLayout from "~/components/layout/ScreenLayout";
|
||||
import { MWSwitch } from "~/components/ui/Switch";
|
||||
import { checkForUpdate } from "~/lib/update";
|
||||
import { getGestureControls, saveGestureControls } from "~/settings";
|
||||
import { useThemeStore } from "~/stores/theme";
|
||||
@@ -76,14 +76,12 @@ export default function SettingsScreen() {
|
||||
<XStack width={200} alignItems="center" gap="$4">
|
||||
<Label minWidth={110}>Gesture controls</Label>
|
||||
<Separator minHeight={20} vertical />
|
||||
<Switch
|
||||
size="$4"
|
||||
native
|
||||
<MWSwitch
|
||||
checked={gestureControlsEnabled}
|
||||
onCheckedChange={handleGestureControlsToggle}
|
||||
>
|
||||
<Switch.Thumb animation="quicker" />
|
||||
</Switch>
|
||||
<MWSwitch.Thumb animation="quicker" />
|
||||
</MWSwitch>
|
||||
</XStack>
|
||||
</YStack>
|
||||
</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";
|
||||
|
||||
const PrimaryButton = styled(Button, {
|
||||
backgroundColor: "$buttonPrimaryBackground",
|
||||
color: "$buttonPrimaryText",
|
||||
fontWeight: "bold",
|
||||
export const MWButton = styled(Button, {
|
||||
variants: {
|
||||
type: {
|
||||
primary: {
|
||||
backgroundColor: "$buttonPrimaryBackground",
|
||||
color: "$buttonPrimaryText",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
secondary: {
|
||||
backgroundColor: "$buttonSecondaryBackground",
|
||||
color: "$buttonSecondaryText",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
purple: {
|
||||
backgroundColor: "$buttonPurpleBackground",
|
||||
color: "white",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
cancel: {
|
||||
backgroundColor: "$buttonCancelBackground",
|
||||
color: "white",
|
||||
fontWeight: "bold",
|
||||
},
|
||||
},
|
||||
} as const,
|
||||
});
|
||||
|
||||
const SecondaryButton = styled(Button, {
|
||||
backgroundColor: "$buttonSecondaryBackground",
|
||||
color: "$buttonSecondaryText",
|
||||
fontWeight: "bold",
|
||||
});
|
||||
|
||||
const PurpleButton = styled(Button, {
|
||||
backgroundColor: "$buttonPurpleBackground",
|
||||
color: "white",
|
||||
fontWeight: "bold",
|
||||
});
|
||||
|
||||
const CancelButton = styled(Button, {
|
||||
backgroundColor: "$buttonCancelBackground",
|
||||
color: "white",
|
||||
fontWeight: "bold",
|
||||
});
|
||||
|
||||
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 { FontAwesome5 } from "@expo/vector-icons";
|
||||
import { useIsFocused } from "@react-navigation/native";
|
||||
import { Input, styled, useTheme, View } from "tamagui";
|
||||
|
||||
import SearchTabContext from "./SearchTabContext";
|
||||
|
||||
const SearchInput = styled(Input, {
|
||||
backgroundColor: "$searchBackground",
|
||||
borderColor: "$colorTransparent",
|
||||
@@ -22,17 +21,16 @@ export function SearchBar({
|
||||
onSearchChange: (text: string) => void;
|
||||
}) {
|
||||
const theme = useTheme();
|
||||
const pageIsFocused = useIsFocused();
|
||||
const [keyword, setKeyword] = useState("");
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const inputRef = useRef<Input>(null);
|
||||
|
||||
const { focusSearchInputRef } = useContext(SearchTabContext);
|
||||
|
||||
useEffect(() => {
|
||||
focusSearchInputRef.current = () => {
|
||||
if (pageIsFocused) {
|
||||
inputRef.current?.focus();
|
||||
};
|
||||
}, [focusSearchInputRef]);
|
||||
}
|
||||
}, [pageIsFocused]);
|
||||
|
||||
useEffect(() => {
|
||||
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;
|
||||
|
||||
const latestVersion: string = res.data.tag_name;
|
||||
const currentVersion: string =
|
||||
Application.nativeApplicationVersion ?? "0.0.0";
|
||||
const latestVersion = res.data.tag_name;
|
||||
const currentVersion = Application.nativeApplicationVersion ?? "0.0.0";
|
||||
|
||||
if (isVersionHigher(latestVersion, currentVersion)) {
|
||||
return res.data.html_url;
|
||||
|
@@ -73,6 +73,10 @@ const createThemeConfig = (tokens: Tokens) => ({
|
||||
buttonPurpleBackgroundHover: tokens.purple.c400,
|
||||
buttonCancelBackground: tokens.ash.c500,
|
||||
buttonCancelBackgroundHover: tokens.ash.c300,
|
||||
|
||||
switchActiveTrackColor: tokens.purple.c300,
|
||||
switchInactiveTrackColor: tokens.ash.c500,
|
||||
switchThumbColor: tokens.white,
|
||||
});
|
||||
|
||||
const openSansFace = {
|
||||
|
@@ -29,7 +29,7 @@
|
||||
},
|
||||
"prettier": "@movie-web/prettier-config",
|
||||
"dependencies": {
|
||||
"@movie-web/providers": "^2.2.2",
|
||||
"@movie-web/providers": "^2.2.4",
|
||||
"parse-hls": "^1.0.7",
|
||||
"srt-webvtt": "^2.0.0",
|
||||
"tmdb-ts": "^1.6.1"
|
||||
|
8
pnpm-lock.yaml
generated
8
pnpm-lock.yaml
generated
@@ -235,8 +235,8 @@ importers:
|
||||
packages/provider-utils:
|
||||
dependencies:
|
||||
'@movie-web/providers':
|
||||
specifier: ^2.2.2
|
||||
version: 2.2.2
|
||||
specifier: ^2.2.4
|
||||
version: 2.2.4
|
||||
parse-hls:
|
||||
specifier: ^1.0.7
|
||||
version: 1.0.7
|
||||
@@ -2865,8 +2865,8 @@ packages:
|
||||
tslib: 2.6.2
|
||||
dev: false
|
||||
|
||||
/@movie-web/providers@2.2.2:
|
||||
resolution: {integrity: sha512-pTlErE5bdu+b68mUW2YAKOJKz2hwSx63auGAfTkGQ+0SHDMlCV9QQ8S8O9IoSsvdXps7/YlWJWOMX8pmKuYbPQ==}
|
||||
/@movie-web/providers@2.2.4:
|
||||
resolution: {integrity: sha512-c10ffR7/oPMbVwpD+Lw0/k5jvx51NbywGJtogzRjeXqDr01o5+pitPeN1qSGaqTg5FBlipn7NSesrd+cczDDQw==}
|
||||
dependencies:
|
||||
cheerio: 1.0.0-rc.12
|
||||
cookie: 0.6.0
|
||||
|
Reference in New Issue
Block a user