nusantara_data 1.0.0 copy "nusantara_data: ^1.0.0" to clipboard
nusantara_data: ^1.0.0 copied to clipboard

A comprehensive Flutter library for Indonesia location data (Province → City → District → Village → Postal Code) with BPS (Badan Pusat Statistik) codes. Complete data for all 38 provinces, 514 cities, [...]

example/lib/main.dart

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize the library
  await NusantaraData.initialize();

  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Nusantara Data Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  String? _selectedProvinceId;
  String? _selectedCityId;
  String? _selectedDistrictId;
  String? _selectedVillageId;

  List<ProvinceSummary> _provinces = [];
  List<CitySummary> _cities = [];
  List<DistrictSummary> _districts = [];
  List<VillageSummary> _villages = [];
  List<String> _postalCodes = [];

  DataStatistics? _statistics;

  @override
  void initState() {
    super.initState();
    _loadData();
  }

  void _loadData() {
    setState(() {
      _provinces = NusantaraData.getAllProvinces();
      _statistics = NusantaraData.getStatistics();
    });
  }

  void _onProvinceSelected(String? provinceId) {
    setState(() {
      _selectedProvinceId = provinceId;
      _selectedCityId = null;
      _selectedDistrictId = null;
      _selectedVillageId = null;
      _cities = provinceId != null
          ? NusantaraData.getCitiesByProvinceId(provinceId)
          : [];
      _districts = [];
      _villages = [];
      _postalCodes = [];
    });
  }

  void _onCitySelected(String? cityId) {
    setState(() {
      _selectedCityId = cityId;
      _selectedDistrictId = null;
      _selectedVillageId = null;
      _districts =
          cityId != null ? NusantaraData.getDistrictsByCityId(cityId) : [];
      _villages = [];
      _postalCodes = [];
    });
  }

  void _onDistrictSelected(String? districtId) {
    setState(() {
      _selectedDistrictId = districtId;
      _selectedVillageId = null;
      _villages = districtId != null
          ? NusantaraData.getVillagesByDistrictId(districtId)
          : [];
      _postalCodes = [];
    });
  }

  void _onVillageSelected(String? villageId) {
    setState(() {
      _selectedVillageId = villageId;
      _postalCodes = villageId != null
          ? NusantaraData.getPostalCodesByVillageId(villageId)
          : [];
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Nusantara Data Example'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            // Statistics Card
            if (_statistics != null) _buildStatisticsCard(),

            const SizedBox(height: 24),

            // Location Picker
            const Text(
              'Pilih Lokasi',
              style: TextStyle(
                fontSize: 20,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 16),

            // Province Dropdown
            _buildDropdown<ProvinceSummary>(
              label: 'Provinsi',
              hint: 'Pilih Provinsi',
              value: _selectedProvinceId,
              items: _provinces,
              getId: (p) => p.id,
              getLabel: (p) => p.name,
              onChanged: _onProvinceSelected,
            ),

            // City Dropdown
            _buildDropdown<CitySummary>(
              label: 'Kota/Kabupaten',
              hint: 'Pilih Kota/Kabupaten',
              value: _selectedCityId,
              items: _cities,
              getId: (c) => c.id,
              getLabel: (c) => '${c.type.displayName} ${c.name}',
              onChanged: _onCitySelected,
              enabled: _selectedProvinceId != null,
            ),

            // District Dropdown
            _buildDropdown<DistrictSummary>(
              label: 'Kecamatan',
              hint: 'Pilih Kecamatan',
              value: _selectedDistrictId,
              items: _districts,
              getId: (d) => d.id,
              getLabel: (d) => d.name,
              onChanged: _onDistrictSelected,
              enabled: _selectedCityId != null,
            ),

            // Village Dropdown
            _buildDropdown<VillageSummary>(
              label: 'Kelurahan/Desa',
              hint: 'Pilih Kelurahan/Desa',
              value: _selectedVillageId,
              items: _villages,
              getId: (v) => v.id,
              getLabel: (v) => v.name,
              onChanged: _onVillageSelected,
              enabled: _selectedDistrictId != null,
            ),

            // Postal Code Display
            if (_postalCodes.isNotEmpty) ...[
              const SizedBox(height: 16),
              Card(
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const Text(
                        'Kode Pos',
                        style: TextStyle(
                          fontSize: 16,
                          fontWeight: FontWeight.bold,
                        ),
                      ),
                      const SizedBox(height: 8),
                      Wrap(
                        spacing: 8,
                        children: _postalCodes
                            .map((code) => Chip(label: Text(code)))
                            .toList(),
                      ),
                    ],
                  ),
                ),
              ),
            ],

            const SizedBox(height: 24),

            // Search Demo
            const Text(
              'Demo Pencarian',
              style: TextStyle(
                fontSize: 20,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 16),
            _buildSearchDemo(),
          ],
        ),
      ),
    );
  }

  Widget _buildStatisticsCard() {
    final stats = _statistics!;
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              'Data Indonesia v${stats.version}',
              style: const TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
              ),
            ),
            Text(
              'Updated: ${stats.updatedAt}',
              style: TextStyle(color: Colors.grey[600]),
            ),
            const Divider(),
            _buildStatRow('Provinsi', stats.provinceCount),
            _buildStatRow('Kota/Kabupaten', stats.cityCount),
            _buildStatRow('Kecamatan', stats.districtCount),
            _buildStatRow('Kelurahan/Desa', stats.villageCount),
            _buildStatRow('Kode Pos', stats.postalCodeCount),
          ],
        ),
      ),
    );
  }

  Widget _buildStatRow(String label, int value) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(label),
          Text(
            _formatNumber(value),
            style: const TextStyle(fontWeight: FontWeight.bold),
          ),
        ],
      ),
    );
  }

  String _formatNumber(int number) {
    return number.toString().replaceAllMapped(
          RegExp(r'(\d{1,3})(?=(\d{3})+(?!\d))'),
          (Match m) => '${m[1]},',
        );
  }

  Widget _buildDropdown<T>({
    required String label,
    required String hint,
    required String? value,
    required List<T> items,
    required String Function(T) getId,
    required String Function(T) getLabel,
    required void Function(String?) onChanged,
    bool enabled = true,
  }) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            label,
            style: const TextStyle(fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 8),
          DropdownButtonFormField<String>(
            value: value,
            hint: Text(hint),
            isExpanded: true,
            decoration: const InputDecoration(
              border: OutlineInputBorder(),
              contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
            ),
            items: items.map((item) {
              return DropdownMenuItem<String>(
                value: getId(item),
                child: Text(getLabel(item)),
              );
            }).toList(),
            onChanged: enabled ? onChanged : null,
          ),
        ],
      ),
    );
  }

  Widget _buildSearchDemo() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              'Pencarian dengan typo tolerance:',
              style: TextStyle(fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 12),
            _buildSearchExample('Jakrta', 'DKI Jakarta'),
            _buildSearchExample('Bandug', 'Bandung'),
            _buildSearchExample('Surbaaya', 'Surabaya'),
            _buildSearchExample('Yogyakrta', 'Yogyakarta'),
          ],
        ),
      ),
    );
  }

  Widget _buildSearchExample(String query, String expected) {
    final results = NusantaraData.searchProvinces(query);
    final found = results.isNotEmpty ? results.first.name : 'Not found';

    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        children: [
          Expanded(
            flex: 2,
            child: Text('"$query"'),
          ),
          const Icon(Icons.arrow_forward, size: 16),
          const SizedBox(width: 8),
          Expanded(
            flex: 3,
            child: Text(
              found,
              style: TextStyle(
                fontWeight: FontWeight.bold,
                color: found.toLowerCase().contains(expected.toLowerCase())
                    ? Colors.green
                    : Colors.red,
              ),
            ),
          ),
        ],
      ),
    );
  }
}
0
likes
140
points
93
downloads

Publisher

unverified uploader

Weekly Downloads

A comprehensive Flutter library for Indonesia location data (Province → City → District → Village → Postal Code) with BPS (Badan Pusat Statistik) codes. Complete data for all 38 provinces, 514 cities, 7,265 districts, 83,202 villages, and 83,762 postal codes.

Repository (GitHub)
View/report issues
Contributing

Documentation

API reference

License

unknown (license)

Dependencies

flutter

More

Packages that depend on nusantara_data