peiffer-innovations / json_dynamic_widget

MIT License
226 stars 68 forks source link

Registering a Custom Widget in json_dynamic_widget #301

Closed KenilDiyora closed 4 months ago

KenilDiyora commented 4 months ago

Description:

I am trying to register a custom widget in json_dynamic_widget. The widget is a countdown timer that displays the remaining time in days, hours, minutes, or seconds. However, I am facing issues with the registration process.

How to register custom widget in json_dynamic_widget.

Custom Widget Code

import 'package:flutter/material.dart';
import 'dart:async';

class CountdownTimer extends StatefulWidget {
  final String unit;

  const CountdownTimer({super.key, required this.unit});

  @override
  _CountdownTimerState createState() => _CountdownTimerState();
}

class _CountdownTimerState extends State<CountdownTimer> {
  late Timer _timer;
  late DateTime _endTime;
  late Duration _timeLeft;

  @override
  void initState() {
    super.initState();
    _endTime = DateTime.parse('2024-07-10 00:00:00');
    _timeLeft = _endTime.difference(DateTime.now());
    _startTimer();
  }

  void _startTimer() {
    _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      setState(() {
        _timeLeft = _endTime.difference(DateTime.now());
        if (_timeLeft.isNegative) {
          _timer.cancel();
        }
      });
    });
  }

  @override
  void dispose() {
    _timer.cancel();
    super.dispose();
  }

  String _formattedTime() {
    switch (widget.unit) {
      case 'days':
        return _timeLeft.inDays.toString().padLeft(2, '0');
      case 'hours':
        return (_timeLeft.inHours % 24).toString().padLeft(2, '0');
      case 'minutes':
        return (_timeLeft.inMinutes % 60).toString().padLeft(2, '0');
      case 'seconds':
        return (_timeLeft.inSeconds % 60).toString().padLeft(2, '0');
      default:
        return '00';
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Container(
          padding: const EdgeInsets.all(8.0),
          decoration: BoxDecoration(
            color: Colors.grey[200],
            borderRadius: BorderRadius.circular(4.0),
          ),
          child: Text(
            _formattedTime(),
            style: const TextStyle(
              fontSize: 24.0,
              fontWeight: FontWeight.bold,
            ),
          ),
        ),
        const SizedBox(height: 4.0),
        Text(widget.unit.capitalize())
      ],
    );
  }
}

extension StringExtension on String {
  String capitalize() {
    return "${this[0].toUpperCase()}${substring(1).toLowerCase()}";
  }
}
KenilDiyora commented 4 months ago

Solution:

I found the solution to register the custom widget in json_dynamic_widget. Here is the step-by-step process and the code:

  1. Create the Custom Widget:
    
    import 'package:flutter/material.dart';
    import 'dart:async';

class CountdownTimer extends StatefulWidget { final String unit; final String endTime;

const CountdownTimer({super.key, required this.unit, required this.endTime});

@override State createState() => _CountdownTimerState(); }

class _CountdownTimerState extends State { late Timer _timer; late DateTime _endTime; late Duration _timeLeft;

@override void initState() { super.initState(); _endTime = DateTime.parse(widget.endTime); _timeLeft = _endTime.difference(DateTime.now()); if (!_timeLeft.isNegative) { _startTimer(); } }

void _startTimer() { _timer = Timer.periodic(const Duration(seconds: 1), (timer) { setState(() { _timeLeft = _endTime.difference(DateTime.now()); if (_timeLeft.isNegative) { _timer.cancel(); } }); }); }

@override void dispose() { _timer.cancel(); super.dispose(); }

String _formattedTime() { switch (widget.unit) { case 'days': return _timeLeft.isNegative ? '00' : _timeLeft.inDays.toString().padLeft(2, '0'); case 'hours': return _timeLeft.isNegative ? '00' : (_timeLeft.inHours % 24).toString().padLeft(2, '0'); case 'minutes': return _timeLeft.isNegative ? '00' : (_timeLeft.inMinutes % 60).toString().padLeft(2, '0'); case 'seconds': return _timeLeft.isNegative ? '00' : (_timeLeft.inSeconds % 60).toString().padLeft(2, '0'); default: return '00'; } }

@override Widget build(BuildContext context) { return Column( children: [ Container( padding: const EdgeInsets.all(8.0), decoration: BoxDecoration( color: Colors.grey[200], borderRadius: BorderRadius.circular(4.0), ), child: Text( _formattedTime(), style: const TextStyle( fontSize: 24.0, fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 4.0), Text(widget.unit.capitalize()) ], ); } }

extension StringExtension on String { String capitalize() { return "${this[0].toUpperCase()}${substring(1).toLowerCase()}"; } }


2. Create Widget Builder (lib/builders/json_count_down_builder.dart):

Create a file named json_count_down_builder.dart with the following code:
```dart
import 'package:json_dynamic_widget/json_dynamic_widget.dart';

import '../widgets/count_down_widget.dart';

part 'json_count_down_builder.g.dart';

@jsonWidget
abstract class _CountdownTimerBuilder extends JsonWidgetBuilder {
  const _CountdownTimerBuilder({
    required super.args,
  });

  @override
  CountdownTimer buildCustom({
    ChildWidgetBuilder? childBuilder,
    required BuildContext context,
    required JsonWidgetData data,
    Key? key,
  });
}
  1. Add Dependencies to pubspec.yaml:
  json_dynamic_widget_codegen: 1.0.1
  build_runner: ^2.4.9
  1. Generate the Builder:

run command in terminal

dart run build_runner build --delete-conflicting-outputs
  1. Register the Custom Builder in the Registry:
  var registry = JsonWidgetRegistry.instance;

  registry.registerCustomBuilder(
    CountdownTimerBuilder.kType, // from generated file
    JsonWidgetBuilderContainer(
      builder: (map, {registry}) => CountdownTimerBuilder.fromDynamic(map), // from generated file
    ),
  );
  1. Use the Custom Widget in JSON:
{
  "type": "countdown_timer",
  "args": {
    "unit": "days",
    "endTime": "2024-07-11"
  }
}