feat: add password visibility toggle to login forms

Improves user experience by allowing users to show/hide password text in both main login form and Jellyseerr settings.

Adds eye icon button that toggles between masked and visible password input, making it easier for users to verify their password entries.
This commit is contained in:
Uruk
2025-09-01 15:05:40 +02:00
parent 602a5fb7d9
commit 15d0de806b
2 changed files with 91 additions and 47 deletions

View File

@@ -52,6 +52,7 @@ const Login: React.FC = () => {
username: _username,
password: _password,
});
const [showPassword, setShowPassword] = useState<boolean>(false);
/**
* A way to auto login based on a link
@@ -275,21 +276,33 @@ const Login: React.FC = () => {
/>
{/* Password */}
<Input
placeholder={t("login.password_placeholder")}
onChangeText={(text: string) =>
setCredentials({ ...credentials, password: text })
}
value={credentials.password}
secureTextEntry
keyboardType='default'
returnKeyType='done'
autoCapitalize='none'
textContentType='password'
clearButtonMode='while-editing'
maxLength={500}
extraClassName='mb-4'
/>
<View className='relative mb-4'>
<Input
placeholder={t("login.password_placeholder")}
onChangeText={(text: string) =>
setCredentials({ ...credentials, password: text })
}
value={credentials.password}
secureTextEntry={!showPassword}
keyboardType='default'
returnKeyType='done'
autoCapitalize='none'
textContentType='password'
clearButtonMode='while-editing'
maxLength={500}
className='pr-12'
/>
<TouchableOpacity
onPress={() => setShowPassword(!showPassword)}
className='absolute right-3 top-3.5 p-1'
>
<Ionicons
name={showPassword ? "eye-off" : "eye"}
size={24}
color='white'
/>
</TouchableOpacity>
</View>
<View className='mt-4'>
<Button onPress={handleLogin}>{t("login.login_button")}</Button>
@@ -404,20 +417,33 @@ const Login: React.FC = () => {
maxLength={500}
/>
<Input
placeholder={t("login.password_placeholder")}
onChangeText={(text) =>
setCredentials({ ...credentials, password: text })
}
value={credentials.password}
secureTextEntry
keyboardType='default'
returnKeyType='done'
autoCapitalize='none'
textContentType='password'
clearButtonMode='while-editing'
maxLength={500}
/>
<View className='relative'>
<Input
placeholder={t("login.password_placeholder")}
onChangeText={(text) =>
setCredentials({ ...credentials, password: text })
}
value={credentials.password}
secureTextEntry={!showPassword}
keyboardType='default'
returnKeyType='done'
autoCapitalize='none'
textContentType='password'
clearButtonMode='while-editing'
maxLength={500}
className='pr-12'
/>
<TouchableOpacity
onPress={() => setShowPassword(!showPassword)}
className='absolute right-3 top-3.5 p-1'
>
<Ionicons
name={showPassword ? "eye-off" : "eye"}
size={24}
color='white'
/>
</TouchableOpacity>
</View>
<View className='flex flex-row items-center justify-between'>
<Button
onPress={handleLogin}

View File

@@ -1,8 +1,9 @@
import { Ionicons } from "@expo/vector-icons";
import { useMutation } from "@tanstack/react-query";
import { useAtom } from "jotai";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { View } from "react-native";
import { TouchableOpacity, View } from "react-native";
import { toast } from "sonner-native";
import { JellyseerrApi, useJellyseerr } from "@/hooks/useJellyseerr";
import { userAtom } from "@/providers/JellyfinProvider";
@@ -30,6 +31,9 @@ export const JellyseerrSettings = () => {
string | undefined
>(settings?.jellyseerrServerUrl || undefined);
const [showJellyseerrPassword, setShowJellyseerrPassword] =
useState<boolean>(false);
const loginToJellyseerrMutation = useMutation({
mutationFn: async () => {
if (!jellyseerrServerUrl && !settings?.jellyseerrServerUrl)
@@ -146,23 +150,37 @@ export const JellyseerrSettings = () => {
<Text className='font-bold mb-2'>
{t("home.settings.plugins.jellyseerr.password")}
</Text>
<Input
className='border border-neutral-800'
autoFocus={true}
focusable={true}
placeholder={t(
"home.settings.plugins.jellyseerr.password_placeholder",
{ username: user?.Name },
)}
value={jellyseerrPassword}
keyboardType='default'
secureTextEntry={true}
returnKeyType='done'
autoCapitalize='none'
textContentType='password'
onChangeText={setJellyseerrPassword}
editable={!loginToJellyseerrMutation.isPending}
/>
<View className='relative'>
<Input
className='border border-neutral-800 pr-12'
autoFocus={true}
focusable={true}
placeholder={t(
"home.settings.plugins.jellyseerr.password_placeholder",
{ username: user?.Name },
)}
value={jellyseerrPassword}
keyboardType='default'
secureTextEntry={!showJellyseerrPassword}
returnKeyType='done'
autoCapitalize='none'
textContentType='password'
onChangeText={setJellyseerrPassword}
editable={!loginToJellyseerrMutation.isPending}
/>
<TouchableOpacity
onPress={() =>
setShowJellyseerrPassword(!showJellyseerrPassword)
}
className='absolute right-3 top-3.5 p-1'
>
<Ionicons
name={showJellyseerrPassword ? "eye-off" : "eye"}
size={24}
color='white'
/>
</TouchableOpacity>
</View>
<Button
loading={loginToJellyseerrMutation.isPending}
disabled={loginToJellyseerrMutation.isPending}