creek

The AI Image Editor of 2030

lib/ui/pages/canvas_toolbar/text_tools_overlay.dart (6162B)


  1import 'package:flutter/material.dart';
  2import 'package:flutter_colorpicker/flutter_colorpicker.dart';
  3import '../../styles/variables.dart';
  4
  5class TextToolsOverlay extends StatelessWidget {
  6  final bool isActive;
  7  final bool isTextSelected;
  8  final Color currentColor;
  9  final double currentFontSize;
 10  final VoidCallback onClose;
 11  final VoidCallback onAddText;
 12  final Function(Color) onColorChanged;
 13  final Function(double) onFontSizeChanged;
 14
 15  const TextToolsOverlay({
 16    super.key,
 17    required this.isActive,
 18    required this.isTextSelected,
 19    required this.currentColor,
 20    required this.currentFontSize,
 21    required this.onClose,
 22    required this.onAddText,
 23    required this.onColorChanged,
 24    required this.onFontSizeChanged,
 25  });
 26
 27  @override
 28  Widget build(BuildContext context) {
 29    if (!isActive) return const SizedBox.shrink();
 30
 31    return Positioned(
 32      bottom: 100 + MediaQuery.of(context).padding.bottom,
 33      left: 0,
 34      right: 0,
 35      child: Center(
 36        child: Container(
 37          margin: const EdgeInsets.symmetric(horizontal: 20),
 38          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
 39          decoration: BoxDecoration(
 40            color: Colors.white,
 41            borderRadius: BorderRadius.circular(30),
 42            boxShadow: [
 43              BoxShadow(
 44                color: Colors.black.withOpacity(0.15),
 45                blurRadius: 12,
 46                offset: const Offset(0, 6),
 47              ),
 48            ],
 49          ),
 50          // Prevent overflow if screen is narrow
 51          child: SingleChildScrollView(
 52            scrollDirection: Axis.horizontal,
 53            child: Row(
 54              mainAxisSize: MainAxisSize.min,
 55              children: [
 56                IconButton(
 57                  icon: const Icon(
 58                    Icons.check_circle,
 59                    color: Variables.textPrimary,
 60                  ),
 61                  onPressed: onClose,
 62                  tooltip: "Done",
 63                ),
 64                Container(width: 1, height: 20, color: Variables.borderSubtle),
 65                const SizedBox(width: 8),
 66                IconButton(
 67                  icon: const Icon(
 68                    Icons.add_circle_outline,
 69                    color: Variables.textPrimary,
 70                  ),
 71                  onPressed: onAddText,
 72                  tooltip: "Add Text",
 73                ),
 74
 75                if (isTextSelected) ...[
 76                  const SizedBox(width: 8),
 77                  Container(
 78                    width: 1,
 79                    height: 20,
 80                    color: Variables.borderSubtle,
 81                  ),
 82                  const SizedBox(width: 12),
 83                  const Icon(
 84                    Icons.text_fields,
 85                    size: 18,
 86                    color: Variables.textSecondary,
 87                  ),
 88                  SizedBox(
 89                    width: 100,
 90                    child: SliderTheme(
 91                      data: SliderThemeData(
 92                        trackHeight: 2,
 93                        thumbShape: const RoundSliderThumbShape(
 94                          enabledThumbRadius: 6,
 95                        ),
 96                        activeTrackColor: Variables.textPrimary,
 97                        inactiveTrackColor: Variables.borderSubtle,
 98                        thumbColor: Colors.black,
 99                        overlayShape: SliderComponentShape.noOverlay,
100                      ),
101                      child: Slider(
102                        value: currentFontSize.clamp(10.0, 200.0),
103                        min: 10.0,
104                        max: 200.0,
105                        onChanged: onFontSizeChanged,
106                      ),
107                    ),
108                  ),
109                  const SizedBox(width: 12),
110                  GestureDetector(
111                    onTap: () => _showColorPicker(context),
112                    child: Container(
113                      width: 24,
114                      height: 24,
115                      decoration: BoxDecoration(
116                        color: currentColor,
117                        shape: BoxShape.circle,
118                        border: Border.all(
119                          color: Variables.borderSubtle,
120                          width: 1,
121                        ),
122                      ),
123                    ),
124                  ),
125                  const SizedBox(width: 8),
126                ],
127              ],
128            ),
129          ),
130        ),
131      ),
132    );
133  }
134
135  void _showColorPicker(BuildContext context) {
136    showModalBottomSheet(
137      context: context,
138      backgroundColor: Colors.transparent,
139      builder:
140          (ctx) => Container(
141            padding: const EdgeInsets.all(24),
142            decoration: const BoxDecoration(
143              color: Colors.white,
144              borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
145            ),
146            child: SafeArea(
147              child: Column(
148                mainAxisSize: MainAxisSize.min,
149                children: [
150                  Text(
151                    "Text Color",
152                    style: Variables.headerStyle.copyWith(fontSize: 16),
153                  ),
154                  const SizedBox(height: 20),
155                  BlockPicker(
156                    pickerColor: currentColor,
157                    onColorChanged: (c) {
158                      onColorChanged(c);
159                      Navigator.pop(ctx);
160                    },
161                    layoutBuilder:
162                        (context, colors, child) => SizedBox(
163                          width: 300,
164                          height: 160,
165                          child: GridView.count(
166                            crossAxisCount: 5,
167                            crossAxisSpacing: 10,
168                            mainAxisSpacing: 10,
169                            children: [
170                              for (Color color in colors) child(color),
171                            ],
172                          ),
173                        ),
174                  ),
175                ],
176              ),
177            ),
178          ),
179    );
180  }
181}