Skip to content

Commit 3dc60d6

Browse files
Tomasz KądziołkaTomasz Kądziołka
authored andcommitted
Created input card with fields
1 parent 7fa66b9 commit 3dc60d6

File tree

4 files changed

+118
-0
lines changed

4 files changed

+118
-0
lines changed

flutter_module/lib/presentation/screens/login_screen.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
22
import 'package:flutter_hooks/flutter_hooks.dart';
33
import 'package:flutter_module/presentation/navigation/login/login_navigator.dart';
44
import 'package:flutter_module/presentation/screens/named_screen.dart';
5+
import 'package:flutter_module/presentation/styles/padding_styles.dart';
6+
import 'package:flutter_module/presentation/widgets/login_input_card.dart';
57
import 'package:flutter_module/utils/hooks/use_navigator.dart';
68
import 'package:go_router/go_router.dart';
79
import 'package:go_router_plus/go_router_plus.dart';
@@ -27,13 +29,22 @@ class _MainPage extends HookWidget {
2729
Widget build(BuildContext context) {
2830
useNavigator([navigator]);
2931

32+
final login = useState("");
33+
final password = useState("");
34+
3035
return Scaffold(
3136
body: Center(
3237
child: Column(
3338
mainAxisAlignment: MainAxisAlignment.center,
3439
children: [
3540
// TODO Extract strings
3641
Text(LoginScreen.name),
42+
PaddingStyles.regular(
43+
LoginInputCard(
44+
onLoginChanged: (value) => login.value = value,
45+
onPasswordChanged: (value) => password.value = value,
46+
),
47+
),
3748
MaterialButton(
3849
child: const Text("Navigate to login"),
3950
onPressed: navigator.login,

flutter_module/lib/presentation/styles/dimens.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@ class Dimens {
44
static const l = 16.0;
55
static const xl = 24.0;
66
static const xxl = 32.0;
7+
8+
static const inputBorderWidth = 0.5;
79
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter/rendering.dart';
3+
import 'package:flutter/widgets.dart';
4+
import 'package:flutter_module/presentation/styles/dimens.dart';
5+
import 'package:flutter_module/presentation/styles/padding_styles.dart';
6+
import 'package:flutter_module/presentation/styles/surface_styles.dart';
7+
import 'package:flutter_module/presentation/widgets/text_input_field.dart';
8+
9+
class LoginInputCard extends StatelessWidget {
10+
const LoginInputCard({
11+
Key? key,
12+
required this.onLoginChanged,
13+
required this.onPasswordChanged,
14+
}) : super(key: key);
15+
16+
final TextInputCallback onLoginChanged;
17+
final TextInputCallback onPasswordChanged;
18+
19+
@override
20+
Widget build(BuildContext context) {
21+
return SurfaceStyles.snippetCard(
22+
child: PaddingStyles.regular(
23+
Column(
24+
children: [
25+
const SizedBox(height: Dimens.l),
26+
TextInputField(
27+
label: 'Login',
28+
onChanged: onLoginChanged,
29+
),
30+
const SizedBox(height: Dimens.xl),
31+
TextInputField(
32+
label: 'Password',
33+
onChanged: onPasswordChanged,
34+
isPassword: true,
35+
),
36+
const SizedBox(height: Dimens.l),
37+
],
38+
),
39+
),
40+
);
41+
}
42+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_hooks/flutter_hooks.dart';
3+
import 'package:flutter_module/presentation/styles/color_styles.dart';
4+
import 'package:flutter_module/presentation/styles/dimens.dart';
5+
6+
typedef TextInputCallback = Function(String value);
7+
8+
class TextInputField extends HookWidget {
9+
const TextInputField({
10+
Key? key,
11+
required this.label,
12+
this.isPassword = false,
13+
this.onChanged,
14+
}) : super(key: key);
15+
16+
final String label;
17+
final bool isPassword;
18+
final TextInputCallback? onChanged;
19+
20+
@override
21+
Widget build(BuildContext context) {
22+
final controller = useTextEditingController();
23+
final value = useValueListenable(controller);
24+
final shouldShow = useState(false);
25+
final passwordVisible = shouldShow.value;
26+
27+
useEffect(() {
28+
onChanged?.call(value.text);
29+
return null;
30+
}, [value.text]);
31+
32+
return TextField(
33+
obscureText: isPassword && !shouldShow.value,
34+
controller: controller,
35+
cursorColor: ColorStyles.accent(),
36+
decoration: InputDecoration(
37+
labelText: label,
38+
floatingLabelStyle: TextStyle(color: ColorStyles.accent()),
39+
border: OutlineInputBorder(
40+
borderSide: BorderSide(
41+
color: ColorStyles.pageBackground(),
42+
width: Dimens.inputBorderWidth,
43+
),
44+
),
45+
focusedBorder: OutlineInputBorder(
46+
borderSide: BorderSide(
47+
color: ColorStyles.accent(),
48+
width: Dimens.inputBorderWidth,
49+
),
50+
),
51+
suffixIcon: isPassword
52+
? InkWell(
53+
radius: Dimens.xl,
54+
onTap: () => shouldShow.value = !passwordVisible,
55+
child: passwordVisible
56+
? const Icon(Icons.visibility_off, color: Colors.black)
57+
: const Icon(Icons.visibility, color: Colors.black),
58+
)
59+
: null,
60+
),
61+
);
62+
}
63+
}

0 commit comments

Comments
 (0)