file_caption_widget.dart 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import 'package:flutter/material.dart';
  2. import 'package:photos/models/file.dart';
  3. import 'package:photos/theme/ente_theme.dart';
  4. import 'package:photos/utils/magic_util.dart';
  5. class FileCaptionWidget extends StatefulWidget {
  6. final File file;
  7. const FileCaptionWidget({required this.file, super.key});
  8. @override
  9. State<FileCaptionWidget> createState() => _FileCaptionWidgetState();
  10. }
  11. class _FileCaptionWidgetState extends State<FileCaptionWidget> {
  12. int maxLength = 280;
  13. int currentLength = 0;
  14. final _textController = TextEditingController();
  15. final _focusNode = FocusNode();
  16. String? editedCaption;
  17. String? hintText = "Add a description...";
  18. @override
  19. void initState() {
  20. _focusNode.addListener(() {
  21. final caption = widget.file.caption;
  22. if (_focusNode.hasFocus && caption != null) {
  23. _textController.text = caption;
  24. editedCaption = caption;
  25. }
  26. });
  27. editedCaption = widget.file.caption;
  28. if (editedCaption != null && editedCaption!.isNotEmpty) {
  29. hintText = editedCaption;
  30. }
  31. super.initState();
  32. }
  33. @override
  34. void dispose() {
  35. if (editedCaption != null) {
  36. editFileCaption(null, widget.file, editedCaption);
  37. }
  38. _textController.dispose();
  39. _focusNode.removeListener(() {});
  40. super.dispose();
  41. }
  42. @override
  43. Widget build(BuildContext context) {
  44. final colorScheme = getEnteColorScheme(context);
  45. final textTheme = getEnteTextTheme(context);
  46. return TextField(
  47. onEditingComplete: () async {
  48. if (editedCaption != null) {
  49. await editFileCaption(context, widget.file, editedCaption);
  50. if (mounted) {
  51. setState(() {});
  52. }
  53. }
  54. _focusNode.unfocus();
  55. },
  56. controller: _textController,
  57. focusNode: _focusNode,
  58. decoration: InputDecoration(
  59. counterStyle: textTheme.mini.copyWith(color: colorScheme.textMuted),
  60. counterText: currentLength > 99
  61. ? currentLength.toString() + " / " + maxLength.toString()
  62. : "",
  63. contentPadding: const EdgeInsets.all(16),
  64. border: OutlineInputBorder(
  65. borderRadius: BorderRadius.circular(2),
  66. borderSide: const BorderSide(
  67. width: 0,
  68. style: BorderStyle.none,
  69. ),
  70. ),
  71. focusedBorder: OutlineInputBorder(
  72. borderRadius: BorderRadius.circular(2),
  73. borderSide: const BorderSide(
  74. width: 0,
  75. style: BorderStyle.none,
  76. ),
  77. ),
  78. filled: true,
  79. fillColor: colorScheme.fillFaint,
  80. hintText: hintText,
  81. hintStyle: getEnteTextTheme(context)
  82. .small
  83. .copyWith(color: colorScheme.textMuted),
  84. ),
  85. style: getEnteTextTheme(context).small,
  86. cursorWidth: 1.5,
  87. maxLength: maxLength,
  88. minLines: 1,
  89. maxLines: 6,
  90. textCapitalization: TextCapitalization.sentences,
  91. keyboardType: TextInputType.text,
  92. onChanged: (value) {
  93. setState(() {
  94. hintText = "Add a description...";
  95. currentLength = value.length;
  96. editedCaption = value;
  97. });
  98. },
  99. );
  100. }
  101. }