File size: 3,052 Bytes
5acd9c3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83f2577
5acd9c3
 
 
 
 
 
 
 
83f2577
 
 
 
5acd9c3
 
 
 
 
 
 
 
83f2577
 
 
 
5acd9c3
 
 
 
 
 
 
2e813e6
 
 
 
 
 
 
 
 
 
 
d7edecf
2e813e6
 
 
 
 
 
 
 
 
 
5acd9c3
2e813e6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5acd9c3
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// lib/widgets/search_box.dart
import 'package:flutter/material.dart';
import '../theme/colors.dart';

class SearchBox extends StatefulWidget {
  final TextEditingController controller;
  final bool isSearching;
  final bool enabled;
  final Function(String) onSearch;
  final VoidCallback onCancel;

  const SearchBox({
    super.key,
    required this.controller,
    required this.isSearching,
    required this.enabled,
    required this.onSearch,
    required this.onCancel,
  });

  @override
  State<SearchBox> createState() => _SearchBoxState();
}

class _SearchBoxState extends State<SearchBox> {
  final _focusNode = FocusNode();
  bool _isComposing = false;

  @override
  void initState() {
    super.initState();
    widget.controller.addListener(_onSearchTextChanged);
  }

  void _onSearchTextChanged() {
    if (_focusNode.hasFocus) {
      setState(() {
        _isComposing = widget.controller.text.isNotEmpty;
      });
    }
  }

  void _handleSubmitted(String value) {
    final trimmedValue = value.trim();
    if (trimmedValue.isNotEmpty) {
      FocusScope.of(context).unfocus();
      widget.onSearch(trimmedValue);
      // Reset _isComposing to ensure the field can be edited again
      setState(() {
        _isComposing = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      color: Colors.transparent,
      child: TextFormField(
        controller: widget.controller,
        focusNode: _focusNode,
        style: const TextStyle(color: AiTubeColors.onBackground),
        enabled: widget.enabled,
        textInputAction: TextInputAction.search,
        onFieldSubmitted: _handleSubmitted,
        onTapOutside: (_) {
          FocusScope.of(context).unfocus();
        },
        decoration: InputDecoration(
          hintText: 'Imagine anything eg "F1 race with farming trucks"',
          hintStyle: const TextStyle(color: AiTubeColors.onSurfaceVariant),
          filled: true,
          fillColor: AiTubeColors.surface,
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(24),
            borderSide: BorderSide.none,
          ),
          contentPadding: const EdgeInsets.symmetric(
            horizontal: 16,
            vertical: 12,
          ),
          suffixIcon: widget.isSearching
              ? IconButton(
                  icon: const SizedBox(
                    width: 20,
                    height: 20,
                    child: CircularProgressIndicator(strokeWidth: 2),
                  ),
                  onPressed: widget.onCancel,
                )
              : IconButton(
                  icon: const Icon(
                    Icons.search,
                    color: AiTubeColors.onSurfaceVariant,
                  ),
                  onPressed: () => _handleSubmitted(widget.controller.text),
                ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    _focusNode.dispose();
    widget.controller.removeListener(_onSearchTextChanged);
    super.dispose();
  }
}