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

قائمة المهام: المهام المتبقية

جزء من قسم المشاريع في رحلة Flutter على Coddy. الدرس 4 من 36.

يجب أن تخبرك نظرة سريعة إلى الشاشة بالمقدار المتبقي من العمل. الإجابة هي عدد المهام غير المنجزة، ويمكنك حسابه من القائمة في كل مرة تُبنى فيها الشاشة.

المُستلِم هو المكان المناسب لذلك. يبدو كأنه حقل، لكنه يشغّل شفرته في كل مرة تستخدمه فيها، لذا يظل محدّثًا دائمًا:

int get _left => _tasks.where((task) => !task.done).length;

لا يوجد متغير إضافي لمزامنته، ولا حاجة إلى setState خاص به: فعند تحديد مهمة، يُستدعى setState بالفعل، وتُعاد بناء الشاشة، ثم يُحصي المُستلِم المهام من جديد.

هناك تفصيل واحد يجعل العبارة تبدو كأن شخصًا كتبها: «مهمة واحدة متبقية»، وليس «مهمة واحدة متبقيات». يختار التعبير الشرطي الكلمات المناسبة.

challenge icon

التحدي

متوسط

اعرض ما تبقّى:

  • أضف مُوجِّهًا _left يحسب عدد المهام غير المنجزة
  • اعرضه بين الحقل والقائمة في عنصر Text مثل 3 tasks left، داخل Row مع مساحة داخلية مقدارها 16 بكسل على الجانبين و8 بكسلات من الأعلى والأسفل
  • عندما تكون هناك مهمة واحدة بالضبط، اعرض 1 task left

جرّب بنفسك

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
      ),
      home: const TodoScreen(),
    );
  }
}

class Task {
  Task(this.title);

  final String title;
  bool done = false;
}

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

  @override
  State<TodoScreen> createState() => _TodoScreenState();
}

class _TodoScreenState extends State<TodoScreen> {
  final List<Task> _tasks = [Task('Buy milk'), Task('Walk the dog'), Task('Read a book')];
  final _controller = TextEditingController();

  void _addTask() {
    setState(() {
      _tasks.add(Task(_controller.text));
    });
    _controller.clear();
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('My Tasks')),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _controller,
                    decoration: const InputDecoration(
                      labelText: 'New task',
                      border: OutlineInputBorder(),
                    ),
                  ),
                ),
                const SizedBox(width: 8),
                IconButton.filled(
                  onPressed: _addTask,
                  icon: const Icon(Icons.add),
                ),
              ],
            ),
          ),
          Expanded(
            child: ListView.builder(
              itemCount: _tasks.length,
              itemBuilder: (context, index) {
                final task = _tasks[index];
                return ListTile(
                  leading: Checkbox(
                    value: task.done,
                    onChanged: (value) {
                      setState(() {
                        task.done = value!;
                      });
                    },
                  ),
                  title: Text(
                    task.title,
                    style: task.done
                        ? const TextStyle(
                            decoration: TextDecoration.lineThrough,
                            color: Colors.grey,
                          )
                        : null,
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}
quiz iconاختبر نفسك

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

جميع دروس المشاريع

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