import 'dart:async'; import 'package:flutter/material.dart'; import 'package:my_app/appeditor/custom/AppEditorWidgetContext.dart'; Widget buildCustomWidget(BuildContext context, AppEditorWidgetContext app) { return CounterWidget(app: app); } class CounterWidget extends StatefulWidget { const CounterWidget({super.key, required this.app}); final AppEditorWidgetContext app; @override State createState() => _CounterWidgetState(); } class _CounterWidgetState extends State { late String _variable; late Stream _values; bool _busy = false; double _number(dynamic value, double fallback) { final result = value is num ? value.toDouble() : double.tryParse('$value'); return result != null && result.isFinite ? result : fallback; } void _bind() { _variable = widget.app.params['variable'] as String? ?? 'custom_counter'; _values = widget.app.watchVar(_variable); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) unawaited(_prepare()); }); } Future _prepare() async { try { await widget.app.addVar( name: _variable, value: _number(widget.app.params['initial'], 0), storeOnDevice: widget.app.params['storeOnDevice'] == true, ); } catch (error) { widget.app.showMessage('ایجاد شمارنده ممکن نشد: $error'); } } @override void initState() { super.initState(); _bind(); } @override void didUpdateWidget(covariant CounterWidget oldWidget) { super.didUpdateWidget(oldWidget); final name = widget.app.params['variable'] as String? ?? 'custom_counter'; if (name != _variable || !identical(widget.app, oldWidget.app)) _bind(); } Future _change(double direction) async { setState(() => _busy = true); final app = widget.app; final variable = _variable; try { await app.addVar( name: variable, value: _number(app.params['initial'], 0), storeOnDevice: app.params['storeOnDevice'] == true, ); if (!mounted) return; final current = _number(app.getVar(variable), 0); final step = _number(app.params['step'], 1); await app.setVar(variable, current + step * direction); if (mounted && app.hasAction('onChanged')) await app.runAction('onChanged'); } catch (error) { app.showMessage('تغییر شمارنده ممکن نشد: $error'); } finally { if (mounted) setState(() => _busy = false); } } @override Widget build(BuildContext context) { return StreamBuilder( stream: _values, builder: (context, snapshot) { final value = _number( snapshot.data, _number(widget.app.params['initial'], 0), ); final text = value == value.truncateToDouble() ? value.toStringAsFixed(0) : '$value'; return Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( widget.app.params['title'] as String? ?? 'شمارنده', style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 12), Text(text, style: Theme.of(context).textTheme.headlineLarge), const SizedBox(height: 12), Wrap( spacing: 16, children: [ OutlinedButton( onPressed: _busy ? null : () => _change(-1), child: const Text('−'), ), FilledButton( onPressed: _busy ? null : () => _change(1), child: const Text('+'), ), ], ), ], ), ), ); }, ); } }