Skip to main content

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

A beautiful customizable 3D tooth chart widget for Flutter apps. 32 permanent teeth + 20 primary teeth with occlusal view and animated highlight support.

example/lib/main.dart

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'flutter_tooth_chart demo',
      theme: ThemeData.dark(useMaterial3: true),
      home: const _DemoHome(),
    );
  }
}

class _DemoHome extends StatefulWidget {
  const _DemoHome();

  @override
  State<_DemoHome> createState() => _DemoHomeState();
}

class _DemoHomeState extends State<_DemoHome> {
  int _tabIndex = 0;

  // Adult FDI groups per sector (mirrors flutter_tooth_chart internals).
  static const _adultSectorFdis = <int, List<int>>{
    1: [18, 17, 16, 15, 14],
    2: [13, 12, 11, 21, 22, 23],
    3: [24, 25, 26, 27, 28],
    4: [48, 47, 46, 45, 44],
    5: [43, 42, 41, 31, 32, 33],
    6: [34, 35, 36, 37, 38],
  };
  static const _childSectorFdis = <int, List<int>>{
    1: [55, 54],
    2: [53, 52, 51, 61, 62, 63],
    3: [64, 65],
    4: [85, 84],
    5: [83, 82, 81, 71, 72, 73],
    6: [74, 75],
  };

  int _activeSector = 1;

  ({Set<int> completed, int? current, ToothChartMode mode, ToothChartPalette palette, String title})
      _stateForTab() {
    switch (_tabIndex) {
      case 0:
        return (
          completed: <int>{},
          current: null,
          mode: ToothChartMode.adult,
          palette: ToothChartPalette.dark,
          title: 'Empty · Adult',
        );
      case 1:
        {
          final completed = <int>{}
            ..addAll(_adultSectorFdis[1]!)
            ..addAll(_adultSectorFdis[2]!);
          final currentSectorFdis = _adultSectorFdis[_activeSector] ?? const [];
          return (
            completed: completed,
            current: currentSectorFdis.isNotEmpty ? currentSectorFdis[0] : null,
            mode: ToothChartMode.adult,
            palette: ToothChartPalette.dark,
            title: 'In progress · Adult',
          );
        }
      case 2:
        {
          final all = <int>{
            for (final list in _adultSectorFdis.values) ...list,
          };
          return (
            completed: all,
            current: null,
            mode: ToothChartMode.adult,
            palette: ToothChartPalette.dark,
            title: 'Perfect · Adult',
          );
        }
      case 3:
      default:
        {
          final completed = <int>{}
            ..addAll(_childSectorFdis[1] ?? const [])
            ..addAll(_childSectorFdis[4] ?? const []);
          final currentSectorFdis = _childSectorFdis[_activeSector] ?? const [];
          return (
            completed: completed,
            current: currentSectorFdis.isNotEmpty ? currentSectorFdis[0] : null,
            mode: ToothChartMode.child,
            palette: ToothChartPalette.kids,
            title: 'Kids mode',
          );
        }
    }
  }

  @override
  Widget build(BuildContext context) {
    final state = _stateForTab();
    return Scaffold(
      backgroundColor: const Color(0xFF1A2333),
      appBar: AppBar(
        title: const Text('flutter_tooth_chart demo'),
        backgroundColor: Colors.transparent,
      ),
      body: Column(
        children: [
          const SizedBox(height: 12),
          Center(
            child: Text(
              state.title,
              style: const TextStyle(color: Colors.white70, fontSize: 14),
            ),
          ),
          const SizedBox(height: 12),
          Expanded(
            child: Center(
              child: ToothArchWidget(
                mode: state.mode,
                completedFdis: state.completed,
                currentFdi: state.current,
                palette: state.palette,
                upperLabel: 'Upper',
                lowerLabel: 'Lower',
              ),
            ),
          ),
          if (_tabIndex == 1 || _tabIndex == 3) _sectorButtons(),
          const SizedBox(height: 8),
          _tabBar(),
        ],
      ),
    );
  }

  Widget _sectorButtons() {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          for (final s in [1, 2, 3, 4, 5, 6])
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 3),
              child: ChoiceChip(
                label: Text('S$s'),
                selected: _activeSector == s,
                onSelected: (_) => setState(() => _activeSector = s),
              ),
            ),
        ],
      ),
    );
  }

  Widget _tabBar() {
    const tabs = ['Empty', 'In progress', 'Perfect', 'Kids'];
    return BottomNavigationBar(
      currentIndex: _tabIndex,
      onTap: (i) => setState(() => _tabIndex = i),
      backgroundColor: const Color(0xFF25344A),
      selectedItemColor: Colors.lightBlueAccent,
      unselectedItemColor: Colors.white54,
      items: [
        for (final t in tabs)
          BottomNavigationBarItem(
            icon: const Icon(Icons.circle, size: 12),
            label: t,
          ),
      ],
    );
  }
}
0
likes
160
points
27
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A beautiful customizable 3D tooth chart widget for Flutter apps. 32 permanent teeth + 20 primary teeth with occlusal view and animated highlight support.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on flutter_tooth_chart