main
dart 177 lines 4.57 KB
Raw
1 import 'package:flutter/material.dart';
2 import 'package:localmind/l10n/app_localizations.dart';
3
4 import 'app_sizes.dart';
5
6 class AppTextField extends StatelessWidget {
7 const AppTextField({
8 super.key,
9 this.controller,
10 this.hintText,
11 this.labelText,
12 this.obscureText = false,
13 this.maxLines = 1,
14 this.minLines,
15 this.maxLength,
16 this.onChanged,
17 this.onSubmitted,
18 this.validator,
19 this.prefixIcon,
20 this.suffixIcon,
21 this.enabled = true,
22 this.autofocus = false,
23 this.keyboardType,
24 this.textInputAction,
25 });
26
27 final TextEditingController? controller;
28 final String? hintText;
29 final String? labelText;
30 final bool obscureText;
31 final int? maxLines;
32 final int? minLines;
33 final int? maxLength;
34 final ValueChanged<String>? onChanged;
35 final ValueChanged<String>? onSubmitted;
36 final FormFieldValidator<String>? validator;
37 final Widget? prefixIcon;
38 final Widget? suffixIcon;
39 final bool enabled;
40 final bool autofocus;
41 final TextInputType? keyboardType;
42 final TextInputAction? textInputAction;
43
44 @override
45 Widget build(BuildContext context) {
46 return TextFormField(
47 controller: controller,
48 obscureText: obscureText,
49 maxLines: maxLines,
50 minLines: minLines,
51 maxLength: maxLength,
52 onChanged: onChanged,
53 onFieldSubmitted: onSubmitted,
54 validator: validator,
55 enabled: enabled,
56 autofocus: autofocus,
57 keyboardType: keyboardType,
58 textInputAction: textInputAction,
59 decoration: InputDecoration(
60 hintText: hintText,
61 labelText: labelText,
62 prefixIcon: prefixIcon,
63 suffixIcon: suffixIcon,
64 isDense: true,
65 contentPadding: const EdgeInsets.symmetric(
66 horizontal: AppSizes.md,
67 vertical: AppSizes.md,
68 ),
69 ),
70 );
71 }
72 }
73
74 class AppSheet {
75 AppSheet._();
76
77 static Future<T?> show<T>({
78 required BuildContext context,
79 required WidgetBuilder builder,
80 bool isScrollControlled = false,
81 }) {
82 return showModalBottomSheet<T>(
83 context: context,
84 isScrollControlled: isScrollControlled,
85 builder: (ctx) {
86 return Column(
87 mainAxisSize: MainAxisSize.min,
88 children: [
89 const SizedBox(height: AppSizes.sm),
90 Container(
91 width: 40,
92 height: 4,
93 decoration: BoxDecoration(
94 color: Theme.of(ctx).brightness == Brightness.dark
95 ? Colors.grey[600]
96 : Colors.grey[300],
97 borderRadius: BorderRadius.circular(2),
98 ),
99 ),
100 const SizedBox(height: AppSizes.sm),
101 Flexible(child: builder(ctx)),
102 ],
103 );
104 },
105 );
106 }
107 }
108
109 class AppDialog {
110 AppDialog._();
111
112 static Future<T?> confirm<T>({
113 required BuildContext context,
114 required String title,
115 String? message,
116 String? confirmLabel,
117 String? cancelLabel,
118 bool destructive = false,
119 }) {
120 final l10n = AppLocalizations.of(context)!;
121 return showDialog<T>(
122 context: context,
123 builder: (ctx) => AlertDialog(
124 title: Text(title),
125 content: message != null ? Text(message) : null,
126 actions: [
127 TextButton(
128 onPressed: () => Navigator.pop(ctx),
129 child: Text(cancelLabel ?? l10n.cancel),
130 ),
131 TextButton(
132 onPressed: () => Navigator.pop(ctx, true as T),
133 style: destructive
134 ? TextButton.styleFrom(foregroundColor: Colors.red)
135 : null,
136 child: Text(confirmLabel ?? l10n.confirm),
137 ),
138 ],
139 ),
140 );
141 }
142
143 static Future<String?> input({
144 required BuildContext context,
145 required String title,
146 String? initialValue,
147 String? hintText,
148 String? confirmLabel,
149 }) {
150 final l10n = AppLocalizations.of(context)!;
151 final controller = TextEditingController(text: initialValue);
152 return showDialog<String>(
153 context: context,
154 builder: (ctx) => AlertDialog(
155 title: Text(title),
156 content: TextField(
157 controller: controller,
158 autofocus: true,
159 decoration: InputDecoration(
160 hintText: hintText,
161 border: const OutlineInputBorder(),
162 ),
163 ),
164 actions: [
165 TextButton(
166 onPressed: () => Navigator.pop(ctx),
167 child: Text(l10n.cancel),
168 ),
169 TextButton(
170 onPressed: () => Navigator.pop(ctx, controller.text.trim()),
171 child: Text(confirmLabel ?? l10n.save),
172 ),
173 ],
174 ),
175 );
176 }
177 }