flutter_timer_button 0.1.0 copy "flutter_timer_button: ^0.1.0" to clipboard
flutter_timer_button: ^0.1.0 copied to clipboard

A highly customizable timed & progress button for Flutter with an animated fill indicator. OTP resend, countdowns, sync/upload/download progress, rate-limited actions.

example/lib/main.dart

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

void main() => runApp(const ExampleApp());

class ExampleApp extends StatelessWidget {
  const ExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'FlutterTimerButton',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.indigo),
      home: const ShowcasePage(),
    );
  }
}

const _blue = Color(0xFF3D5AFE);
const _teal = Color(0xFF00BFA5);
const _orange = Color(0xFFFF8F00);

class ShowcasePage extends StatefulWidget {
  const ShowcasePage({super.key});

  @override
  State<ShowcasePage> createState() => _ShowcasePageState();
}

class _ShowcasePageState extends State<ShowcasePage> {
  final _syncController = TimerButtonController();
  final _downloadingController = TimerButtonController();
  final _continuingController = TimerButtonController()..setProgress(0.29);
  final _blue42Controller = TimerButtonController()..setProgress(0.42);
  final _outlined38Controller = TimerButtonController()..setProgress(0.38);
  final _teal34Controller = TimerButtonController()..setProgress(0.34);

  final _tealCountdownController = TimerButtonController(
    duration: const Duration(seconds: 4),
  );
  final _blueCountdownController = TimerButtonController(
    duration: const Duration(seconds: 3),
  );
  final _darkCountdownController = TimerButtonController(
    duration: const Duration(seconds: 2),
  );
  final _otpController = TimerButtonController(
    duration: const Duration(seconds: 5),
  );
  final _downloadController = TimerButtonController(
    duration: const Duration(seconds: 6),
  );

  Future<void> _fakeProgress(TimerButtonController controller) async {
    controller.setProgress(0);
    const steps = 24;
    const stepDuration = Duration(milliseconds: 100); // ~2.4s total
    for (var i = 1; i <= steps; i++) {
      await Future<void>.delayed(stepDuration);
      if (!mounted) return;
      controller.setProgress(i / steps);
    }
  }

  @override
  void dispose() {
    _syncController.dispose();
    _downloadingController.dispose();
    _continuingController.dispose();
    _blue42Controller.dispose();
    _outlined38Controller.dispose();
    _teal34Controller.dispose();
    _tealCountdownController.dispose();
    _blueCountdownController.dispose();
    _darkCountdownController.dispose();
    _otpController.dispose();
    _downloadController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFFF3F5FC),
      body: SafeArea(
        child: ListView(
          padding: const EdgeInsets.all(24),
          children: [
            const Text(
              'TimerButton',
              style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 4),
            Text(
              'A timed & progress button with an animated fill indicator.',
              style: TextStyle(fontSize: 14, color: Colors.grey.shade600),
            ),
            const SizedBox(height: 32),
            const _SectionTitle('Showcase'),
            const SizedBox(height: 16),

            // Blue progress button "Continuing 29%"
            TimerButton(
              mode: TimerButtonMode.progress,
              controller: _continuingController,
              style: TimerButtonStyle.filled(color: _blue),
              labelBuilder: (context, remaining, progress, isRunning) {
                return Text('Continuing ${(progress * 100).round()}%');
              },
            ),
            const SizedBox(height: 12),

            // Teal countdown button "4s left"
            TimerButton.countdown(
              duration: const Duration(seconds: 4),
              controller: _tealCountdownController,
              autoStart: true,
              style: TimerButtonStyle.filled(color: _teal),
            ),
            const SizedBox(height: 12),

            // Orange progress button "Sync 40%" - fake async progress on tap
            TimerButton(
              mode: TimerButtonMode.progress,
              controller: _syncController,
              disableWhileRunning: false,
              style: TimerButtonStyle.filled(color: _orange),
              onPressed: () => _fakeProgress(_syncController),
              labelBuilder: (context, remaining, progress, isRunning) {
                return Text('Sync ${(progress * 100).round()}%');
              },
            ),
            const SizedBox(height: 12),

            // Dark progress button "Downloading 26%" with CircleAvatar leading
            TimerButton(
              mode: TimerButtonMode.progress,
              controller: _downloadingController,
              disableWhileRunning: false,
              style: TimerButtonStyle.dark(),
              leading: const CircleAvatar(
                radius: 10,
                backgroundColor: Colors.white24,
                child: Text('D', style: TextStyle(fontSize: 11)),
              ),
              onPressed: () => _fakeProgress(_downloadingController),
              labelBuilder: (context, remaining, progress, isRunning) {
                return Text('Downloading ${(progress * 100).round()}%');
              },
            ),
            const SizedBox(height: 12),

            // Row: filled blue "42%" and outlined blue "38%"
            Row(
              children: [
                Expanded(
                  child: TimerButton(
                    mode: TimerButtonMode.progress,
                    controller: _blue42Controller,
                    style: TimerButtonStyle.filled(color: _blue),
                    labelBuilder: (context, remaining, progress, isRunning) {
                      return Text(defaultProgressLabel(progress));
                    },
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: TimerButton(
                    mode: TimerButtonMode.progress,
                    controller: _outlined38Controller,
                    style: TimerButtonStyle.outlined(color: _blue),
                    labelBuilder: (context, remaining, progress, isRunning) {
                      return Text(defaultProgressLabel(progress));
                    },
                  ),
                ),
              ],
            ),
            const SizedBox(height: 12),

            // Small teal progress button "34%"
            TimerButton(
              mode: TimerButtonMode.progress,
              controller: _teal34Controller,
              style: TimerButtonStyle.filled(
                color: _teal,
              ).copyWith(height: 44),
              labelBuilder: (context, remaining, progress, isRunning) {
                return Text(defaultProgressLabel(progress));
              },
            ),

            const SizedBox(height: 32),
            const _SectionTitle('Basic, Auto-start, OTP, Download'),
            const SizedBox(height: 16),

            // Row: blue countdown "3s left" + dark countdown "2s left"
            Row(
              children: [
                Expanded(
                  child: TimerButton.countdown(
                    duration: const Duration(seconds: 3),
                    controller: _blueCountdownController,
                    autoStart: true,
                    style: TimerButtonStyle.filled(color: _blue),
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: TimerButton.countdown(
                    duration: const Duration(seconds: 2),
                    controller: _darkCountdownController,
                    autoStart: true,
                    style: TimerButtonStyle.dark(),
                  ),
                ),
              ],
            ),
            const SizedBox(height: 12),

            // Dark countdown button, enabled: false
            TimerButton(
              mode: TimerButtonMode.countdown,
              duration: const Duration(seconds: 5),
              autoStart: false,
              enabled: false,
              style: TimerButtonStyle.dark(),
              child: const Text('Disabled'),
            ),
            const SizedBox(height: 12),

            // Teal countdown "Resend in 5s" with idleChild "Send code"
            TimerButton.countdown(
              duration: const Duration(seconds: 5),
              controller: _otpController,
              autoStart: false,
              style: TimerButtonStyle.filled(color: _teal),
              idleChild: const Text('Send code'),
              labelBuilder: (remaining) {
                final seconds = (remaining.inMilliseconds / 1000).ceil();
                return 'Resend in ${seconds}s';
              },
            ),
            const SizedBox(height: 12),

            // Dark progress button "Download 42%" with download icon, autoStart over 6s
            TimerButton.progress(
              duration: const Duration(seconds: 6),
              controller: _downloadController,
              autoStart: true,
              style: TimerButtonStyle.dark(),
              leading: const Icon(Icons.download, size: 18),
              labelBuilder: (progress) =>
                  'Download ${(progress * 100).round()}%',
            ),
          ],
        ),
      ),
    );
  }
}

class _SectionTitle extends StatelessWidget {
  const _SectionTitle(this.title);

  final String title;

  @override
  Widget build(BuildContext context) {
    return Text(
      title,
      style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
    );
  }
}
1
likes
160
points
75
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A highly customizable timed & progress button for Flutter with an animated fill indicator. OTP resend, countdowns, sync/upload/download progress, rate-limited actions.

Repository (GitHub)

Topics

#button #timer #progress #otp #countdown

License

MIT (license)

Dependencies

flutter

More

Packages that depend on flutter_timer_button