mirror of
https://github.com/zimplexing/OrionTV.git
synced 2026-03-03 01:07:31 +08:00
refactor: enhance LoginModal and StyledButton components for improved functionality
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -23,5 +23,5 @@ expo-env.d.ts
|
||||
web/**
|
||||
.bmad-core
|
||||
.kilocodemodes
|
||||
.roomode
|
||||
.roomodes
|
||||
yarn-errors.log
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import { Modal, View, Text, TextInput, StyleSheet, ActivityIndicator } from "react-native";
|
||||
import React, { useState, useRef } from "react";
|
||||
import { Modal, View, TextInput, StyleSheet, ActivityIndicator } from "react-native";
|
||||
import Toast from "react-native-toast-message";
|
||||
import useAuthStore from "@/stores/authStore";
|
||||
import { useSettingsStore } from "@/stores/settingsStore";
|
||||
@@ -16,6 +16,8 @@ const LoginModal = () => {
|
||||
const [username, setUsername] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const passwordInputRef = useRef<TextInput>(null);
|
||||
const loginButtonRef = useRef<View>(null);
|
||||
|
||||
const handleLogin = async () => {
|
||||
const isLocalStorage = serverConfig?.StorageType === "localstorage";
|
||||
@@ -32,7 +34,7 @@ const LoginModal = () => {
|
||||
hideLoginModal();
|
||||
setUsername("");
|
||||
setPassword("");
|
||||
} catch (error) {
|
||||
} catch {
|
||||
Toast.show({ type: "error", text1: "登录失败", text2: "用户名或密码错误" });
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
@@ -53,17 +55,28 @@ const LoginModal = () => {
|
||||
value={username}
|
||||
onChangeText={setUsername}
|
||||
autoFocus
|
||||
returnKeyType="next"
|
||||
onSubmitEditing={() => passwordInputRef.current?.focus()}
|
||||
/>
|
||||
)}
|
||||
<TextInput
|
||||
ref={passwordInputRef}
|
||||
style={styles.input}
|
||||
placeholder="请输入密码"
|
||||
placeholderTextColor="#888"
|
||||
secureTextEntry
|
||||
value={password}
|
||||
onChangeText={setPassword}
|
||||
returnKeyType="next"
|
||||
onSubmitEditing={() => loginButtonRef.current?.focus()}
|
||||
/>
|
||||
<StyledButton text={isLoading ? "" : "登录"} onPress={handleLogin} disabled={isLoading} style={styles.button}>
|
||||
<StyledButton
|
||||
ref={loginButtonRef}
|
||||
text={isLoading ? "" : "登录"}
|
||||
onPress={handleLogin}
|
||||
disabled={isLoading}
|
||||
style={styles.button}
|
||||
>
|
||||
{isLoading && <ActivityIndicator color="#fff" />}
|
||||
</StyledButton>
|
||||
</ThemedView>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React from "react";
|
||||
import { Animated, Pressable, StyleSheet, StyleProp, ViewStyle, PressableProps, TextStyle } from "react-native";
|
||||
import React, { forwardRef } from "react";
|
||||
import { Animated, Pressable, StyleSheet, StyleProp, ViewStyle, PressableProps, TextStyle, View } from "react-native";
|
||||
import { ThemedText } from "./ThemedText";
|
||||
import { Colors } from "@/constants/Colors";
|
||||
import { useButtonAnimation } from "@/hooks/useAnimation";
|
||||
@@ -13,133 +13,130 @@ interface StyledButtonProps extends PressableProps {
|
||||
textStyle?: StyleProp<TextStyle>;
|
||||
}
|
||||
|
||||
export const StyledButton: React.FC<StyledButtonProps> = ({
|
||||
children,
|
||||
text,
|
||||
variant = "default",
|
||||
isSelected = false,
|
||||
style,
|
||||
textStyle,
|
||||
...rest
|
||||
}) => {
|
||||
const colorScheme = "dark";
|
||||
const colors = Colors[colorScheme];
|
||||
const [isFocused, setIsFocused] = React.useState(false);
|
||||
const animationStyle = useButtonAnimation(isFocused);
|
||||
export const StyledButton = forwardRef<View, StyledButtonProps>(
|
||||
({ children, text, variant = "default", isSelected = false, style, textStyle, ...rest }, ref) => {
|
||||
const colorScheme = "dark";
|
||||
const colors = Colors[colorScheme];
|
||||
const [isFocused, setIsFocused] = React.useState(false);
|
||||
const animationStyle = useButtonAnimation(isFocused);
|
||||
|
||||
const variantStyles = {
|
||||
default: StyleSheet.create({
|
||||
const variantStyles = {
|
||||
default: StyleSheet.create({
|
||||
button: {
|
||||
backgroundColor: colors.border,
|
||||
},
|
||||
text: {
|
||||
color: colors.text,
|
||||
},
|
||||
selectedButton: {
|
||||
backgroundColor: colors.tint,
|
||||
},
|
||||
focusedButton: {
|
||||
backgroundColor: colors.link,
|
||||
borderColor: colors.background,
|
||||
},
|
||||
selectedText: {
|
||||
color: Colors.dark.text,
|
||||
},
|
||||
}),
|
||||
primary: StyleSheet.create({
|
||||
button: {
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
text: {
|
||||
color: colors.text,
|
||||
},
|
||||
focusedButton: {
|
||||
backgroundColor: colors.link,
|
||||
borderColor: colors.background,
|
||||
},
|
||||
selectedButton: {
|
||||
backgroundColor: "rgba(0, 122, 255, 0.3)",
|
||||
},
|
||||
selectedText: {
|
||||
color: colors.link,
|
||||
},
|
||||
}),
|
||||
ghost: StyleSheet.create({
|
||||
button: {
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
text: {
|
||||
color: colors.text,
|
||||
},
|
||||
focusedButton: {
|
||||
backgroundColor: "rgba(119, 119, 119, 0.9)",
|
||||
},
|
||||
selectedButton: {},
|
||||
selectedText: {},
|
||||
}),
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
backgroundColor: colors.border,
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 10,
|
||||
borderRadius: 8,
|
||||
borderWidth: 2,
|
||||
borderColor: "transparent",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
text: {
|
||||
color: colors.text,
|
||||
focusedButton: {
|
||||
backgroundColor: colors.link,
|
||||
borderColor: colors.background,
|
||||
elevation: 5,
|
||||
shadowColor: colors.link,
|
||||
shadowOffset: { width: 0, height: 0 },
|
||||
shadowOpacity: 1,
|
||||
shadowRadius: 15,
|
||||
},
|
||||
selectedButton: {
|
||||
backgroundColor: colors.tint,
|
||||
},
|
||||
focusedButton: {
|
||||
backgroundColor: colors.link,
|
||||
borderColor: colors.background,
|
||||
text: {
|
||||
fontSize: 16,
|
||||
fontWeight: "500",
|
||||
color: colors.text,
|
||||
},
|
||||
selectedText: {
|
||||
color: Colors.dark.text,
|
||||
},
|
||||
}),
|
||||
primary: StyleSheet.create({
|
||||
button: {
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
text: {
|
||||
color: colors.text,
|
||||
},
|
||||
focusedButton: {
|
||||
backgroundColor: colors.link,
|
||||
borderColor: colors.background,
|
||||
},
|
||||
selectedButton: {
|
||||
backgroundColor: "rgba(0, 122, 255, 0.3)",
|
||||
},
|
||||
selectedText: {
|
||||
color: colors.link,
|
||||
},
|
||||
}),
|
||||
ghost: StyleSheet.create({
|
||||
button: {
|
||||
backgroundColor: "transparent",
|
||||
},
|
||||
text: {
|
||||
color: colors.text,
|
||||
},
|
||||
focusedButton: {
|
||||
backgroundColor: "rgba(119, 119, 119, 0.9)",
|
||||
},
|
||||
selectedButton: {},
|
||||
selectedText: {},
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 10,
|
||||
borderRadius: 8,
|
||||
borderWidth: 2,
|
||||
borderColor: "transparent",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
focusedButton: {
|
||||
backgroundColor: colors.link,
|
||||
borderColor: colors.background,
|
||||
elevation: 5,
|
||||
shadowColor: colors.link,
|
||||
shadowOffset: { width: 0, height: 0 },
|
||||
shadowOpacity: 1,
|
||||
shadowRadius: 15,
|
||||
},
|
||||
selectedButton: {
|
||||
backgroundColor: colors.tint,
|
||||
},
|
||||
text: {
|
||||
fontSize: 16,
|
||||
fontWeight: "500",
|
||||
color: colors.text,
|
||||
},
|
||||
selectedText: {
|
||||
color: Colors.dark.text,
|
||||
},
|
||||
});
|
||||
return (
|
||||
<Animated.View style={[animationStyle, style]}>
|
||||
<Pressable
|
||||
ref={ref}
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onBlur={() => setIsFocused(false)}
|
||||
style={({ focused }) => [
|
||||
styles.button,
|
||||
variantStyles[variant].button,
|
||||
isSelected && (variantStyles[variant].selectedButton ?? styles.selectedButton),
|
||||
focused && (variantStyles[variant].focusedButton ?? styles.focusedButton),
|
||||
]}
|
||||
{...rest}
|
||||
>
|
||||
{text ? (
|
||||
<ThemedText
|
||||
style={[
|
||||
styles.text,
|
||||
variantStyles[variant].text,
|
||||
isSelected && (variantStyles[variant].selectedText ?? styles.selectedText),
|
||||
textStyle,
|
||||
]}
|
||||
>
|
||||
{text}
|
||||
</ThemedText>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</Pressable>
|
||||
</Animated.View>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<Animated.View style={[animationStyle, style]}>
|
||||
<Pressable
|
||||
onFocus={() => setIsFocused(true)}
|
||||
onBlur={() => setIsFocused(false)}
|
||||
style={({ focused }) => [
|
||||
styles.button,
|
||||
variantStyles[variant].button,
|
||||
isSelected && (variantStyles[variant].selectedButton ?? styles.selectedButton),
|
||||
focused && (variantStyles[variant].focusedButton ?? styles.focusedButton),
|
||||
]}
|
||||
{...rest}
|
||||
>
|
||||
{text ? (
|
||||
<ThemedText
|
||||
style={[
|
||||
styles.text,
|
||||
variantStyles[variant].text,
|
||||
isSelected && (variantStyles[variant].selectedText ?? styles.selectedText),
|
||||
textStyle,
|
||||
]}
|
||||
>
|
||||
{text}
|
||||
</ThemedText>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</Pressable>
|
||||
</Animated.View>
|
||||
);
|
||||
};
|
||||
StyledButton.displayName = "StyledButton";
|
||||
|
||||
@@ -42,10 +42,13 @@ export interface SearchResult {
|
||||
}
|
||||
|
||||
export interface Favorite {
|
||||
cover: string;
|
||||
title: string;
|
||||
poster: string;
|
||||
source_name: string;
|
||||
save_time: number;
|
||||
total_episodes: number;
|
||||
search_title: string;
|
||||
year: string;
|
||||
}
|
||||
|
||||
export interface PlayRecord {
|
||||
|
||||
@@ -82,7 +82,7 @@ export class FavoriteManager {
|
||||
return (await api.getFavorites()) as Record<string, Favorite>;
|
||||
}
|
||||
|
||||
static async save(source: string, id: string, item: Omit<Favorite, "save_time">): Promise<void> {
|
||||
static async save(source: string, id: string, item: Favorite): Promise<void> {
|
||||
const key = generateKey(source, id);
|
||||
await api.addFavorite(key, item);
|
||||
}
|
||||
@@ -98,7 +98,7 @@ export class FavoriteManager {
|
||||
return favorite !== null;
|
||||
}
|
||||
|
||||
static async toggle(source: string, id: string, item: Omit<Favorite, "save_time">): Promise<boolean> {
|
||||
static async toggle(source: string, id: string, item: Favorite): Promise<boolean> {
|
||||
const isFav = await this.isFavorited(source, id);
|
||||
if (isFav) {
|
||||
await this.remove(source, id);
|
||||
|
||||
Reference in New Issue
Block a user