import 'dart:developer'; import 'package:easy_debounce/easy_debounce.dart'; import 'package:flutter/material.dart'; import 'package:flutter_canvas_editor/history.dart'; import 'package:flutter_canvas_editor/providers/editor.dart'; import 'package:flutter_canvas_editor/style/canvas_style.dart'; import 'package:flutter_canvas_editor/utils/debouncer.dart'; import 'package:flutter_canvas_editor/widgets/elements.dart'; import 'package:provider/provider.dart'; class ToolbarWidget extends StatefulWidget { const ToolbarWidget({ super.key, }); @override State createState() => _ToolbarWidgetState(); } class _ToolbarWidgetState extends State { FocusNode? _focus = FocusNode(); // String? _lastSavedText; // void _addFocusNodeListener() { // if (Provider.of(context, listen: false).selectedElmKey != null && [ElementType.text, ElementType.textbox].contains(Provider.of(context, listen: false).selectedElm!.type)) { // _focus!.addListener(_onTextFieldFocusChange); // } // } // void _onTextFieldFocusChange() { // print('toolbar onfocus change'); // if (Provider.of(context, listen: false).selectedElm?.lastSavedText != Provider.of(context, listen: false).selectedElm?.valueController.text) { // // Provider.of(context, listen: false).setNewElementsState(CanvasHistoryModifyType.textEdit, Provider.of(context, listen: false).elementProperties); // Provider.of(context, listen: false).selectedElm?.lastSavedText = Provider.of(context, listen: false).selectedElm?.valueController.text; // } // } // void _removeFocusNodeListener() { // if ([ElementType.text, ElementType.textbox].contains(Provider.of(context).selectedElm!.type)) { // _focus!.removeListener(_onTextFieldFocusChange); // } // } @override void dispose() { // TODO: implement dispose // _removeFocusNodeListener(); super.dispose(); } @override Widget build(BuildContext context) { final editorProvider = Provider.of(context); return Container( padding: EdgeInsets.symmetric(horizontal: 16), color: Colors.white, width: MediaQuery.of(context).size.width, height: 150, child: Provider.of(context).insertElementMode ? insertElementSection() : ToolbarPropertiesWidget(editorProvider: editorProvider), // child: ListView( // children: Provider.of(context).insertElementMode ? insertElementSection() : elementPropertiesSection(editorProvider), // ), ); } Widget insertElementSection() { return ListView( children: [ Text('Insert Element'), SizedBox(height: 20), ElevatedButton( onPressed: Provider.of(context, listen: false).addTextElement, child: Text('Add Text Element') ), ElevatedButton( onPressed: Provider.of(context, listen: false).addTextboxElement, child: Text('Add Textbox Element') ), SizedBox(height: 24), // ? Variable Element Section Text('Insert Variable Element'), SizedBox(height: 24), ElevatedButton( onPressed: Provider.of(context, listen: false).addProductNameElement, child: Text('Add Product Name Element') ), ElevatedButton( onPressed: Provider.of(context, listen: false).addVariantNameElement, child: Text('Add Variant Name Element') ), ElevatedButton( onPressed: Provider.of(context, listen: false).addProductionCodeElement, child: Text('Add Production Code Element') ), ElevatedButton( onPressed: Provider.of(context, listen: false).addProductionDateElement, child: Text('Add Production Date Element') ), ElevatedButton( onPressed: Provider.of(context, listen: false).addSerialNumberElement, child: Text('Add Serial Number Element') ), ] ); } } class ToolbarPropertiesWidget extends StatefulWidget { final Editor editorProvider; const ToolbarPropertiesWidget({super.key, required this.editorProvider}); @override State createState() => _ToolbarPropertiesWidgetState(); } class _ToolbarPropertiesWidgetState extends State { List> fontSizeDropdownItems= []; List> qrSizeDropdownItems= []; // String? _valueOnStartEditing; @override void initState() { super.initState(); // _valueOnStartEditing = widget.editorProvider.selectedElm?.valueController.text; populateFontSizeDropdownItems(); populateQrSizeDropdownItems(); log('[TOOLBAR PROPERTIES EXECUTED]'); } //functions void populateFontSizeDropdownItems() { CanvasStyle.fontSizeMap.forEach((key, val) { final item = DropdownMenuItem( value: key, child: Text(key.toString()) ); fontSizeDropdownItems.add(item); }); } void populateQrSizeDropdownItems() { CanvasStyle.qrSizeMap.forEach((key, val) { final item = DropdownMenuItem( value: key, child: Text(key.toString()) ); qrSizeDropdownItems.add(item); }); } @override Widget build(BuildContext context) { return ListView( children: elementPropertiesSection(widget.editorProvider), ); } List elementPropertiesSection(Editor editorProvider) { final element = Provider.of(context).selectedElm; return [ Text('Properties'), SizedBox(height: 20), Text('Selected elements: ${Provider.of(context).selectedElmType}'), Text('Top: ${Provider.of(context, listen: true).selectedElm!.position.top}, Left: ${Provider.of(context, listen: true).selectedElm!.position.left}}'), SizedBox(height: 12), ...Provider.of(context).isVariableElement ? _variablePropertiesSection(editorProvider, element) : _commonPropertiesSection(editorProvider, element), ]; } List _variablePropertiesSection(Editor editorProvider, ElementState? element) { return [ Container( margin: EdgeInsets.only(bottom: 16), color: Colors.grey[200], width: double.infinity, child: Text( 'This is a variable element, the value shown in editor is a placeholder. The actual value will be generated when printing the label.', ) ), _buildElementRotatorButton(), // ? Font Resizer _buildFontResizerWidget(element), _buildElementPositionLockerButton(), _buildElementRemoverButton() ]; } List _commonPropertiesSection(Editor editorProvider, ElementState? element) { return [ // ? Value Editor if([ElementType.text, ElementType.textbox].contains(editorProvider.selectedElm!.type)) TextField( readOnly: element!.isLocked, controller: element!.valueController, onTap: editorProvider.enableEdit, // onEditingComplete: () { // FocusManager.instance.primaryFocus?.unfocus(); // editorProvider.disableEdit(); // print('kepenjet'); // }, onChanged: (newText) { Debouncer.run(() { log('[SAVING TO HISTORY]'); Provider.of(context, listen: false).editText(element.valueController); element.valueController.text = widget.editorProvider.valueOnStartEditing ?? ''; widget.editorProvider.setValueOnStartEditing(newText); }); setState(() {}); }, ), if (editorProvider.selectedElm!.type != ElementType.qr) _buildElementRotatorButton(), // ? Font Resizer (Only show when selected element is [ElementType.text, ElementType.textbox]) if (Provider.of(context).shouldShowFontResizer) _buildFontResizerWidget(element), // ? Qr Resizer (Only show when selected element is ElementType.qr) if (Provider.of(context).shouldShowQrResizer) _buildQrResizerWidget(element), // ? Lock Element _buildElementPositionLockerButton(), // ? Delete elm button (only show when type is not ElementType.qr) if (Provider.of(context).shouldShowDeleteElementButton) _buildElementRemoverButton() ]; } Widget _buildFontResizerWidget(ElementState? element) { return Row( children: [ DropdownButton( value: element?.fontScale, items: fontSizeDropdownItems, onChanged: (val) { print('dropdown value: $val'); Provider.of(context, listen: false).changeFontSize(val); } ), IconButton.filled( onPressed: Provider.of(context, listen: false).incrementFontSize, icon: Icon(Icons.add) ), IconButton.filled( onPressed: Provider.of(context, listen: false).decrementFontSize, icon: Icon(Icons.remove) ), ], ); } Widget _buildQrResizerWidget(ElementState? element) { return Row( children: [ DropdownButton( value: element?.qrScale, items: qrSizeDropdownItems, onChanged: (val) { print('dropdown value: $val'); Provider.of(context, listen: false).changeQrSize(val); } ), IconButton.filled( onPressed: Provider.of(context, listen: false).incrementQrSize, icon: Icon(Icons.add) ), IconButton.filled( onPressed: Provider.of(context, listen: false).decrementQrSize, icon: Icon(Icons.remove) ), ], ); } Widget _buildElementRotatorButton() { return ElevatedButton( onPressed: Provider.of(context).rotate, child: Text('Rotate') ); } Widget _buildElementRemoverButton() { return ElevatedButton( style: ButtonStyle( backgroundColor: WidgetStatePropertyAll(Theme.of(context).colorScheme.errorContainer) ), onPressed: () async => Provider.of(context, listen: false).deleteElement(context), child: Text( 'Delete Element', style: TextStyle(color: Theme.of(context).colorScheme.error), ) ); } Widget _buildElementPositionLockerButton() { return ElevatedButton( onPressed: () async { Provider.of(context, listen: false).toggleLockElement(); FocusScope.of(context).unfocus(); }, child: Text( Provider.of(context).selectedElm!.isLocked ? 'Unlock Element' : 'Lock Element', ) ); } }