gamification_ui 0.0.1 copy "gamification_ui: ^0.0.1" to clipboard
gamification_ui: ^0.0.1 copied to clipboard

Headless gamification UI components for Flutter: achievements, streaks, points, and leaderboards. Bring your own state — no storage, no logic, just widgets.

example/lib/main.dart

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:gamification_ui/gamification_ui.dart';

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

/// Allows drag-scrolling with a mouse so the web demo feels like mobile.
class _AnyDeviceScrollBehavior extends MaterialScrollBehavior {
  const _AnyDeviceScrollBehavior();

  @override
  Set<PointerDeviceKind> get dragDevices => PointerDeviceKind.values.toSet();
}

/// Gallery of every gamification_ui component.
class GalleryApp extends StatelessWidget {
  /// Creates the gallery app.
  const GalleryApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'gamification_ui gallery',
      scrollBehavior: const _AnyDeviceScrollBehavior(),
      theme: ThemeData(
        colorSchemeSeed: Colors.deepPurple,
        useMaterial3: true,
      ),
      home: const GalleryPage(),
    );
  }
}

/// Scrollable gallery page.
class GalleryPage extends StatefulWidget {
  /// Creates the gallery page.
  const GalleryPage({super.key});

  @override
  State<GalleryPage> createState() => _GalleryPageState();
}

class _GalleryPageState extends State<GalleryPage> {
  final ConfettiController _confetti = ConfettiController();

  int _points = 2450;
  int _xp = 340;
  int _streak = 12;

  late List<Achievement> _achievements = [
    Achievement(
      id: 'first_steps',
      title: 'First steps',
      description: 'Complete your first lesson',
      icon: Icons.flag,
      unlocked: true,
      unlockedAt: DateTime(2026, 6, 21, 18, 30),
    ),
    const Achievement(
      id: 'bookworm',
      title: 'Bookworm',
      description: 'Finish 5 lessons',
      icon: Icons.menu_book,
      current: 3,
      target: 5,
    ),
    const Achievement(
      id: 'socialite',
      title: 'Socialite',
      description: 'Cheer 10 friends',
      icon: Icons.chat_bubble,
      current: 4,
      target: 10,
    ),
    const Achievement(
      id: 'week_streak',
      title: 'On fire',
      description: 'Keep a 7-day streak',
      icon: Icons.local_fire_department,
      current: 0,
      target: 7,
    ),
    const Achievement(
      id: 'night_owl',
      title: 'Night owl',
      description: 'Practice after midnight',
      icon: Icons.nightlight,
    ),
    const Achievement(
      id: 'century',
      title: 'Century',
      description: 'Complete 100 lessons',
      icon: Icons.emoji_events,
      current: 12,
      target: 100,
    ),
  ];

  final List<PointsTransaction> _history = [
    PointsTransaction(
      label: 'Weekly quest complete',
      amount: 120,
      timestamp: DateTime(2026, 7, 2, 9, 30),
    ),
    PointsTransaction(
      label: 'Theme unlock',
      amount: -50,
      timestamp: DateTime(2026, 7, 1, 18, 5),
      icon: Icons.palette,
    ),
    PointsTransaction(
      label: 'Daily login',
      amount: 10,
      timestamp: DateTime(2026, 7, 1, 8, 0),
    ),
  ];

  static const _leaders = [
    LeaderboardEntry(rank: 1, name: 'Aiko', score: 9800, rankDelta: 2),
    LeaderboardEntry(rank: 2, name: 'Ben', score: 9200, rankDelta: -1),
    LeaderboardEntry(rank: 3, name: 'Chika', score: 8700, rankDelta: 0),
    LeaderboardEntry(
      rank: 4,
      name: 'You',
      score: 8100,
      isCurrentUser: true,
      rankDelta: 3,
    ),
    LeaderboardEntry(rank: 5, name: 'Emi', score: 7600, rankDelta: -2),
  ];

  void _unlockNext() {
    final index = _achievements.indexWhere((a) => !a.unlocked);
    if (index == -1) return;
    final unlocked = _achievements[index].copyWith(
      unlocked: true,
      unlockedAt: DateTime.now(),
    );
    setState(() {
      _achievements = [..._achievements]..[index] = unlocked;
      _points += 50;
    });
    _confetti.burst();
    showAchievementUnlockToast(context, achievement: unlocked);
  }

  @override
  Widget build(BuildContext context) {
    return ConfettiOverlay(
      controller: _confetti,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('gamification_ui'),
          actions: [
            Padding(
              padding: const EdgeInsets.only(right: 12),
              child: Center(
                child: PointsBalanceChip(
                  points: _points,
                  onTap: () => setState(() => _points += 25),
                ),
              ),
            ),
          ],
        ),
        body: ListView(
          padding: const EdgeInsets.all(16),
          children: [
            _Section(
              title: 'Points',
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  LevelCard(
                    level: 12,
                    currentXp: _xp,
                    requiredXp: 500,
                    subtitle: 'Rising star',
                  ),
                  const SizedBox(height: 12),
                  Row(
                    children: [
                      FilledButton.tonal(
                        onPressed: () => setState(() => _xp =
                            _xp + 40 > 500 ? 500 : _xp + 40),
                        child: const Text('+40 XP'),
                      ),
                      const SizedBox(width: 8),
                      FilledButton.tonal(
                        onPressed: () => setState(() => _points += 100),
                        child: const Text('+100 pts'),
                      ),
                      const SizedBox(width: 16),
                      AnimatedPointsCounter(
                        value: _points,
                        style: Theme.of(context).textTheme.titleLarge,
                      ),
                    ],
                  ),
                  const SizedBox(height: 16),
                  const Row(
                    mainAxisAlignment: MainAxisAlignment.spaceAround,
                    children: [
                      TierBadge(tier: Tier.bronze, size: 56),
                      TierBadge(tier: Tier.silver, size: 56),
                      TierBadge(tier: Tier.gold, size: 56),
                      TierBadge(tier: Tier.platinum, size: 56),
                      TierBadge(tier: Tier.diamond, size: 56),
                    ],
                  ),
                ],
              ),
            ),
            _Section(
              title: 'Achievements',
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  AchievementBadgeGrid(
                    achievements: _achievements,
                    onTap: (a) => showAchievementDetailSheet(
                      context,
                      achievement: a,
                    ),
                  ),
                  const SizedBox(height: 8),
                  FilledButton.icon(
                    onPressed: _unlockNext,
                    icon: const Icon(Icons.celebration),
                    label: const Text('Unlock next'),
                  ),
                  const SizedBox(height: 12),
                  AchievementProgressCard(achievement: _achievements[1]),
                ],
              ),
            ),
            _Section(
              title: 'Streaks',
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Row(
                    children: [
                      StreakFlameCounter(count: _streak),
                      const Spacer(),
                      IconButton(
                        onPressed: () => setState(
                          () => _streak = _streak > 0 ? _streak - 1 : 0,
                        ),
                        icon: const Icon(Icons.remove),
                      ),
                      IconButton(
                        onPressed: () => setState(() => _streak++),
                        icon: const Icon(Icons.add),
                      ),
                    ],
                  ),
                  const SizedBox(height: 12),
                  const StreakWeeklyCalendar(
                    completed: [true, true, true, false, false, false, false],
                    todayIndex: 3,
                  ),
                  const SizedBox(height: 16),
                  StreakMilestoneBar(current: _streak),
                ],
              ),
            ),
            _Section(
              title: 'Leaderboard',
              child: Column(
                children: [
                  const LeaderboardPodium(entries: _leaders),
                  const SizedBox(height: 8),
                  LeaderboardList(entries: _leaders),
                ],
              ),
            ),
            _Section(
              title: 'History',
              child: PointsHistoryList(transactions: _history),
            ),
            const SizedBox(height: 48),
          ],
        ),
      ),
    );
  }
}

class _Section extends StatelessWidget {
  const _Section({required this.title, required this.child});

  final String title;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 24),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            title,
            style: Theme.of(context)
                .textTheme
                .titleLarge
                ?.copyWith(fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 12),
          child,
        ],
      ),
    );
  }
}
1
likes
160
points
32
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Headless gamification UI components for Flutter: achievements, streaks, points, and leaderboards. Bring your own state — no storage, no logic, just widgets.

Repository (GitHub)
View/report issues

Topics

#gamification #achievements #streaks #leaderboard #ui

License

MIT (license)

Dependencies

flutter

More

Packages that depend on gamification_ui