flutter_tooth_chart 0.1.0
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.
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,
),
],
);
}
}