mofilo_nutrient_verifier 1.0.1 copy "mofilo_nutrient_verifier: ^1.0.1" to clipboard
mofilo_nutrient_verifier: ^1.0.1 copied to clipboard

Nutrition data validator for user-submitted food data. Validates using physics-based limits, energy conservation, and toxicity thresholds. Binary pass/fail with trust scoring.

example/lib/main.dart

/// Example demonstrating the mofilo_nutrient_verifier package.
///
/// This example shows how to:
/// 1. Validate food items
/// 2. Handle validation results
/// 3. Calculate expected calories
/// 4. Display helpful error messages to users
///
/// Run this example with: flutter run

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

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Nutrient Verifier Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.green),
        useMaterial3: true,
      ),
      home: const ExamplePage(),
    );
  }
}

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

  @override
  State<ExamplePage> createState() => _ExamplePageState();
}

class _ExamplePageState extends State<ExamplePage> {
  ValidationResult? _lastResult;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text('Nutrient Verifier Examples'),
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          const Text(
            'Tap any food to validate it:',
            style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 16),

          // Example 1: Valid food
          _buildExampleCard(
            'Valid: Grilled Chicken Breast',
            FoodItem(
              id: 'ex1',
              name: 'Grilled Chicken Breast',
              servingSize: 100,
              servingUnit: 'g',
              protein: 31,
              carbs: 0,
              fat: 3.6,
              calories: 165,
            ),
            Colors.green,
          ),

          // Example 2: Invalid - Matter density violation
          _buildExampleCard(
            'Invalid: Too many macros',
            FoodItem(
              id: 'ex2',
              name: 'Impossible Protein Bar',
              servingSize: 100,
              servingUnit: 'g',
              protein: 60,
              carbs: 50,
              fat: 30, // Total: 140g in 100g serving!
              calories: 650,
            ),
            Colors.red,
          ),

          // Example 3: Invalid - Calorie mismatch
          _buildExampleCard(
            'Invalid: Wrong calories',
            FoodItem(
              id: 'ex3',
              name: 'Dream Food',
              servingSize: 100,
              servingUnit: 'g',
              protein: 50, // 200 kcal
              carbs: 2,    // 8 kcal
              fat: 0.5,    // 4.5 kcal
              calories: 100, // Should be ~213 kcal!
            ),
            Colors.orange,
          ),

          // Example 4: Invalid - Hierarchy violation
          _buildExampleCard(
            'Invalid: Fiber exceeds carbs',
            FoodItem(
              id: 'ex4',
              name: 'Fiber Powder',
              servingSize: 100,
              servingUnit: 'g',
              carbs: 10,
              dietaryFiber: 15, // Fiber can't exceed total carbs!
              calories: 40,
            ),
            Colors.purple,
          ),

          // Example 5: Invalid - Toxic sodium
          _buildExampleCard(
            'Invalid: Dangerous sodium level',
            FoodItem(
              id: 'ex5',
              name: 'Super Salty Snack',
              servingSize: 100,
              servingUnit: 'g',
              servingCount: 10, // 10 servings
              sodium: 1500, // 1500mg × 10 = 15,000mg (TOXIC!)
              carbs: 50,
              fat: 20,
              calories: 400,
            ),
            Colors.red,
          ),

          const SizedBox(height: 24),
          const Divider(),
          const SizedBox(height: 16),

          // Utility function example
          const Text(
            'Utility: Calculate Expected Calories',
            style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 8),
          _buildCalorieCalculator(),

          const SizedBox(height: 24),

          // Last validation result
          if (_lastResult != null) ...[
            const Divider(),
            const SizedBox(height: 16),
            const Text(
              'Last Validation Result:',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 8),
            _buildResultDisplay(_lastResult!),
          ],
        ],
      ),
    );
  }

  Widget _buildExampleCard(String title, FoodItem food, Color color) {
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: InkWell(
        onTap: () => _validateFood(food),
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Row(
            children: [
              Container(
                width: 8,
                height: 48,
                decoration: BoxDecoration(
                  color: color,
                  borderRadius: BorderRadius.circular(4),
                ),
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      title,
                      style: const TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      '${food.calories} kcal | P: ${food.protein ?? 0}g | '
                      'C: ${food.carbs ?? 0}g | F: ${food.fat ?? 0}g',
                      style: TextStyle(
                        fontSize: 14,
                        color: Colors.grey[600],
                      ),
                    ),
                  ],
                ),
              ),
              const Icon(Icons.chevron_right),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildCalorieCalculator() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text('Protein: 30g, Carbs: 50g, Fat: 10g'),
            const SizedBox(height: 8),
            Text(
              'Expected Calories: ${NutrientVerifier.calculateExpectedCalories(
                protein: 30,
                carbs: 50,
                fat: 10,
              )} kcal',
              style: const TextStyle(
                fontSize: 16,
                fontWeight: FontWeight.bold,
                color: Colors.blue,
              ),
            ),
            const SizedBox(height: 4),
            Text(
              'Formula: (30×4) + (50×4) + (10×9) = 410 kcal',
              style: TextStyle(
                fontSize: 14,
                color: Colors.grey[600],
              ),
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildResultDisplay(ValidationResult result) {
    return Card(
      color: result.pass ? Colors.green[50] : Colors.red[50],
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                Icon(
                  result.pass ? Icons.check_circle : Icons.error,
                  color: result.pass ? Colors.green : Colors.red,
                  size: 32,
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: Text(
                    result.pass ? 'PASS' : 'NO PASS',
                    style: TextStyle(
                      fontSize: 24,
                      fontWeight: FontWeight.bold,
                      color: result.pass ? Colors.green : Colors.red,
                    ),
                  ),
                ),
                Text(
                  'Score: ${result.trustScore}/100',
                  style: const TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ],
            ),
            if (!result.pass && result.reasons.isNotEmpty) ...[
              const SizedBox(height: 16),
              const Text(
                'Reasons:',
                style: TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 8),
              ...result.reasons.map((reason) => Padding(
                padding: const EdgeInsets.only(bottom: 4),
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    const Text('• ', style: TextStyle(fontSize: 16)),
                    Expanded(
                      child: Text(
                        reason,
                        style: const TextStyle(fontSize: 14),
                      ),
                    ),
                  ],
                ),
              )),
            ],
          ],
        ),
      ),
    );
  }

  void _validateFood(FoodItem food) {
    final result = NutrientVerifier.verify(food);
    setState(() {
      _lastResult = result;
    });

    // Show snackbar with quick result
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(
          result.pass
            ? '✓ ${food.name}: PASS'
            : '✗ ${food.name}: NO PASS',
        ),
        backgroundColor: result.pass ? Colors.green : Colors.red,
        duration: const Duration(seconds: 2),
      ),
    );
  }
}
0
likes
140
points
2
downloads

Publisher

verified publishermofilo.app

Weekly Downloads

Nutrition data validator for user-submitted food data. Validates using physics-based limits, energy conservation, and toxicity thresholds. Binary pass/fail with trust scoring.

Homepage
Repository (GitHub)

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on mofilo_nutrient_verifier