text_input_widget.dart 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter/services.dart';
  3. import 'package:photos/theme/ente_theme.dart';
  4. import 'package:photos/ui/components/dialog_widget.dart';
  5. import 'package:photos/utils/separators_util.dart';
  6. class TextInputWidget extends StatefulWidget {
  7. final String? label;
  8. final String? message;
  9. final String? hintText;
  10. final IconData? prefixIcon;
  11. final String? initialValue;
  12. final Alignment? alignMessage;
  13. final bool? autoFocus;
  14. final int? maxLength;
  15. final ValueNotifier? submitNotifier;
  16. final bool alwaysShowSuccessState;
  17. final bool showOnlyLoadingState;
  18. final FutureVoidCallbackParamStr onSubmit;
  19. const TextInputWidget({
  20. required this.onSubmit,
  21. this.label,
  22. this.message,
  23. this.hintText,
  24. this.prefixIcon,
  25. this.initialValue,
  26. this.alignMessage,
  27. this.autoFocus,
  28. this.maxLength,
  29. this.submitNotifier,
  30. this.alwaysShowSuccessState = false,
  31. this.showOnlyLoadingState = false,
  32. super.key,
  33. });
  34. @override
  35. State<TextInputWidget> createState() => _TextInputWidgetState();
  36. }
  37. class _TextInputWidgetState extends State<TextInputWidget> {
  38. final _textController = TextEditingController();
  39. @override
  40. void initState() {
  41. widget.submitNotifier?.addListener(() {
  42. widget.onSubmit.call(_textController.text);
  43. });
  44. super.initState();
  45. }
  46. @override
  47. void dispose() {
  48. widget.submitNotifier?.dispose();
  49. super.dispose();
  50. }
  51. @override
  52. Widget build(BuildContext context) {
  53. if (widget.initialValue != null) {
  54. _textController.value = TextEditingValue(
  55. text: widget.initialValue!,
  56. selection: TextSelection.collapsed(offset: widget.initialValue!.length),
  57. );
  58. }
  59. final colorScheme = getEnteColorScheme(context);
  60. final textTheme = getEnteTextTheme(context);
  61. var textInputChildren = <Widget>[];
  62. if (widget.label != null) textInputChildren.add(Text(widget.label!));
  63. textInputChildren.add(
  64. ClipRRect(
  65. borderRadius: const BorderRadius.all(Radius.circular(8)),
  66. child: Material(
  67. child: TextFormField(
  68. autofocus: widget.autoFocus ?? false,
  69. controller: _textController,
  70. inputFormatters: widget.maxLength != null
  71. ? [LengthLimitingTextInputFormatter(50)]
  72. : null,
  73. decoration: InputDecoration(
  74. hintText: widget.hintText,
  75. hintStyle: textTheme.body.copyWith(color: colorScheme.textMuted),
  76. filled: true,
  77. contentPadding: const EdgeInsets.symmetric(
  78. vertical: 12,
  79. horizontal: 12,
  80. ),
  81. border: const UnderlineInputBorder(
  82. borderSide: BorderSide.none,
  83. ),
  84. focusedBorder: OutlineInputBorder(
  85. borderSide: BorderSide(color: colorScheme.strokeMuted),
  86. borderRadius: BorderRadius.circular(8),
  87. ),
  88. prefixIconConstraints: const BoxConstraints(
  89. maxHeight: 44,
  90. maxWidth: 44,
  91. minHeight: 44,
  92. minWidth: 44,
  93. ),
  94. suffixIconConstraints: const BoxConstraints(
  95. maxHeight: 44,
  96. maxWidth: 44,
  97. minHeight: 44,
  98. minWidth: 44,
  99. ),
  100. prefixIcon: widget.prefixIcon != null
  101. ? Icon(
  102. widget.prefixIcon,
  103. color: colorScheme.strokeMuted,
  104. )
  105. : null,
  106. ),
  107. onEditingComplete: () {},
  108. ),
  109. ),
  110. ),
  111. );
  112. if (widget.message != null) {
  113. textInputChildren.add(
  114. Padding(
  115. padding: const EdgeInsets.symmetric(horizontal: 8),
  116. child: Align(
  117. alignment: widget.alignMessage ?? Alignment.centerLeft,
  118. child: Text(
  119. widget.message!,
  120. style: textTheme.small.copyWith(color: colorScheme.textMuted),
  121. ),
  122. ),
  123. ),
  124. );
  125. }
  126. textInputChildren =
  127. addSeparators(textInputChildren, const SizedBox(height: 4));
  128. return Column(
  129. mainAxisSize: MainAxisSize.min,
  130. crossAxisAlignment: CrossAxisAlignment.start,
  131. children: textInputChildren,
  132. );
  133. }
  134. }