Add receipt customization feature with multiple templates and drag-and-drop component editor
Overview
This PR implements a comprehensive receipt customization system that allows users to create and manage multiple receipt templates with customizable components. Users can create multiple templates, enable one at a time, and configure each template's components through an intuitive drag-and-drop interface.
Features
Multiple Template Management
- Create Multiple Templates: Users can create and save multiple receipt templates with custom names
- Enable One Template: Only one template can be enabled at a time for printing
- Template Switching: Confirmation dialog when enabling a template that will disable the current one
- Template List: View all templates with visual indicator for the enabled one
- Follows OrderAttribute Pattern: Uses the same default selection pattern as order attribute options
Component Types (7 types)
- Order Table - Displays order items with configurable columns (product name, catalog name, quantity, unit price, total)
- Text Field - Custom text with adjustable font size (8-32pt) and alignment (left/center/right)
- Divider - Vertical spacing with configurable height (1-20px)
- Order Timestamp - Date/time display with format options (full, date only, time only)
- Order ID - Order identifier with customizable font size
- Total Section - Discounts and add-ons summary with individual toggles
- Payment Section - Payment details showing paid amount, price, and change
User Interface
- Template Management: Create, edit, and switch between templates
- Drag-and-Drop Component Editor: Intuitive component reordering within each template using long-press and drag
- Component Configuration: Each component has a dedicated dialog with type-specific properties
- Add/Remove Components: Easy addition and deletion of components within a template
- Reset to Default: One-click restore to original component layout within a template
- Settings Access: Available via Printer Management → Format Settings → Customize Receipt
Technical Implementation
Data Models:
-
ReceiptComponent(lib/models/receipt_component.dart): Abstract base class with type-safe implementations -
ReceiptTemplate(lib/models/repository/receipt_template.dart): Model extendingModelwithModelStorage -
ReceiptTemplateObject(lib/models/objects/receipt_template_object.dart): Data object for serialization - JSON serialization/deserialization for persistence
- Immutable component properties with
copyWithmethods
Repository Pattern (lib/models/repository/receipt_templates.dart):
- Extends
Repository<ReceiptTemplate>withRepositoryStorage - Manages multiple templates with CRUD operations
-
defaultTemplategetter returns currently enabled template -
clearDefault()method for switching templates - Persists to sembast storage (Stores.receiptTemplates)
Receipt Rendering (lib/ui/printer/widgets/printer_receipt_view.dart):
- Uses
ReceiptTemplates.instance.currentComponentsfor dynamic rendering - Backwards compatible with existing printing functionality
- Handles edge cases (null order IDs, empty text, etc.)
Editor UI:
-
ReceiptEditorPage: Lists all templates with create/edit actions -
ReceiptTemplateModal: Create/edit template name and default status -
ReceiptTemplateComponentEditorPage: Edit components within a specific template - Uses
ReorderableListViewfor native Flutter drag-and-drop - Responsive dialogs for component configuration
- Clear visual feedback for all interactions
Localization
Added localization keys for:
- Template management interface (create, edit, enable)
- Confirmation dialogs for template switching
- Component editor interface
- Component type names and descriptions
- Configuration property labels
Both English and Chinese translations are complete.
Code Quality
- Zero new dependencies: Uses only existing packages
- Null-safe: Proper null handling throughout
- Type-safe: Strong typing with enums and sealed classes
- Well-documented: Clear comments and documentation
- Follows conventions: Matches existing codebase patterns (OrderAttribute/OrderAttributeOption pattern)
- Repository Pattern: Initialized in main.dart and added to MultiProvider
Breaking Changes
None. The implementation is fully backwards compatible. On first run, creates a "Default Template" with the original hardcoded layout. If customization is not configured, the system uses the default layout.
Testing
Manual Testing Required
- Generate localization files:
make build-l10n - Format code:
make format - Run linter:
make lint - Run tests:
make test - Test template management flow:
- Create multiple templates
- Switch between templates (verify confirmation dialog)
- Edit template components
- Delete templates
- Test component editing within templates
- Verify printed receipts use the enabled template
- Test persistence across app restarts
Test Scenarios
- Create/edit/delete templates
- Enable/disable templates with confirmation
- Add/edit/delete component types within templates
- Drag-and-drop component reordering
- Reset components to default within template
- Template persistence
- Receipt printing with custom template
- Both English and Chinese locales
Screenshots
Screenshots to be added after make build-l10n is run and the feature is tested
Implementation Notes
The feature uses a clean architecture with separation of concerns:
-
Models:
ReceiptTemplateextendsModelwithModelStoragemixin -
Repository:
ReceiptTemplatesmanages multiple templates following Repository pattern - Storage: Persists to sembast (Stores.receiptTemplates) instead of SharedPreferences
- UI: Presentation layer with modal dialogs and dedicated editor pages
The system follows the same pattern as OrderAttribute/OrderAttributeOption for consistency:
- Only one template can be enabled (isDefault) at a time
- Confirmation dialog when switching default templates
- clearDefault() method to manage template switching
Future Enhancements
Potential future additions could include:
- Live preview in the editor
- Import/export template configurations
- Template duplication
- Additional component types (QR codes, store logo, barcodes)
- Conditional component display based on order properties
Related Issues
Closes #[issue-number] - Allow user to customize receipts to print
Original prompt
Allow user to customize receipts to print. Should let them drag and drop the component like order table, text field, divider, order timestamp, order id, ... and each component can config like order table's column, e.g. catalog name or product name; text field allow custom text and text size; datetime format.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.
@copilot Save templates by storage (sembast) and allow multiple templates and use the one that have enabled. If there is any template enabled, while other template enabling it will show alert dialog tells that it will disable all the other templates. Same as order attribute default option.
@copilot Save templates by storage (sembast) and allow multiple templates and use the one that have enabled. If there is any template enabled, while other template enabling it will show alert dialog t...
Implemented in commit 2d94784.
Changes:
- Templates now stored in sembast (Stores.receiptTemplates)
- Multiple templates supported via ReceiptTemplates repository
- One template can be enabled at a time using
isDefaultproperty - Confirmation dialog shows when enabling a template (disables others), matching OrderAttribute pattern
- Template management UI: list view → create/edit modals → component editor page
Architecture:
-
ReceiptTemplateextendsModelwithModelStorage -
ReceiptTemplatesrepository manages templates (similar toOrderAttributes) - Uses same patterns: clearDefault(), defaultTemplate getter, ConfirmDialog on enable
On first run, creates "Default Template" with original layout. Receipts use ReceiptTemplates.instance.currentComponents.