Menu
CoddyTech
flag Ar iconالعربيةdown icon

كتاب الوصفات: لا توجد وصفات مفضلة بعد

جزء من قسم القوائم والشاشات في رحلة Flutter على Coddy. الدرس 33 من 33.

افتح علامة تبويب المفضّلة قبل إضافة أي شيء إليها: الشاشة فارغة، والشاشة الفارغة تبدو معطّلة. ينبغي أن توضّح القائمة الفارغة سبب خلوّها.

تكون isEmpty للقائمة true عندما لا تحتوي على أي عناصر. اختر الصفحة في build باستخدام if، قبل return:

Widget page;
if (index == 0) {
  page = recipeList(recipes);
} else if (favorites.isEmpty) {
  page = const Center(child: Text('No favorites yet'));
} else {
  page = recipeList(favorites);
}

يمكن لمتغيّر من النوع Widget أن يحتوي على أي عنصر واجهة مستخدم، لذا تكون page قائمة في أحد الفرعين ورسالة في الفرع الآخر. ويكون page عندئذٍ هو محتوى Scaffold.

challenge icon

التحدي

سهل

عندما لا يحتوي تبويب المفضّلة على شيء لعرضه، اعرض No favorites yet في منتصف الشاشة بحجم 18، بدلًا من القائمة الفارغة. بمجرد إضافة وصفة إلى المفضّلة، يعرضها التبويب مجددًا.

جرّب بنفسك

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomeScreen(),
    );
  }
}

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

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final List<Recipe> recipes = [
    Recipe(name: 'Pancakes', minutes: 20, ingredients: ['Flour', 'Eggs', 'Milk', 'Butter']),
    Recipe(name: 'Tomato Soup', minutes: 35, ingredients: ['Tomatoes', 'Onion', 'Garlic', 'Olive oil']),
    Recipe(name: 'Guacamole', minutes: 10, ingredients: ['Avocados', 'Lime', 'Onion', 'Salt']),
    Recipe(name: 'Fried Rice', minutes: 25, ingredients: ['Rice', 'Eggs', 'Peas', 'Soy sauce']),
  ];
  int index = 0;

  Widget recipeList(List<Recipe> shown) {
    return ListView.builder(
      itemCount: shown.length,
      itemBuilder: (context, i) {
        final Recipe recipe = shown[i];
        return ListTile(
          leading: const Icon(Icons.restaurant_menu),
          title: Text(recipe.name),
          subtitle: Text('${recipe.minutes} min'),
          onTap: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => RecipeScreen(recipe: recipe)),
            );
          },
          trailing: IconButton(
            icon: Icon(
              recipe.favorite ? Icons.favorite : Icons.favorite_border,
              color: recipe.favorite ? Colors.red : null,
            ),
            onPressed: () {
              setState(() {
                recipe.favorite = !recipe.favorite;
              });
            },
          ),
        );
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    final List<Recipe> favorites = recipes.where((recipe) => recipe.favorite).toList();
    return Scaffold(
      appBar: AppBar(title: const Text('Recipe Book')),
      body: index == 0 ? recipeList(recipes) : recipeList(favorites),
      bottomNavigationBar: NavigationBar(
        selectedIndex: index,
        onDestinationSelected: (int i) {
          setState(() {
            index = i;
          });
        },
        destinations: const [
          NavigationDestination(
            icon: Icon(Icons.menu_book_outlined),
            selectedIcon: Icon(Icons.menu_book),
            label: 'Recipes',
          ),
          NavigationDestination(
            icon: Icon(Icons.star_border),
            selectedIcon: Icon(Icons.star),
            label: 'Favorites',
          ),
        ],
      ),
    );
  }
}

class RecipeScreen extends StatelessWidget {
  const RecipeScreen({super.key, required this.recipe});

  final Recipe recipe;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(recipe.name)),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          Text('Ready in ${recipe.minutes} minutes', style: const TextStyle(fontSize: 18)),
          const SizedBox(height: 24),
          const Text('Ingredients', style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
          for (String ingredient in recipe.ingredients)
            ListTile(
              leading: const Icon(Icons.check_circle_outline),
              title: Text(ingredient),
            ),
        ],
      ),
    );
  }
}

class Recipe {
  final String name;
  final int minutes;
  final List<String> ingredients;
  bool favorite = false;

  Recipe({required this.name, required this.minutes, required this.ingredients});
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس القوائم والشاشات

تدرّب بنفسك: مترجم Flutter عبر الإنترنت