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

قائمة المهام: منع المهام الفارغة

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

اضغط على «إضافة» دون كتابة أي شيء، وستُضاف إلى قائمتك خانة فارغة. اكتب مسافات فقط، وستحصل أيضًا على خانة تبدو فارغة. ترفض التطبيقات الحقيقية الحالتين وتوضح السبب.

تعيد trim() النص من دون المسافات في بدايته ونهايته. إذا لم يتبقَّ شيء، فلا توجد مهمة: اعرض SnackBar ونفّذ return قبل إضافة أي شيء.

final title = _controller.text.trim();
if (title.isEmpty) {
  ScaffoldMessenger.of(context).showSnackBar(
    const SnackBar(content: Text('Type a task first')),
  );
  return;
}

استخدم title للمهمة الجديدة أيضًا، حتى يُحفَظ " Call mom " على هيئة "Call mom".

يُسمّى return المبكر مثل هذا حارسًا. فهو يُبقي الحالة غير الصالحة في البداية، ولا تتعامل بقية الدالة إلا مع المُدخلات الصالحة.

challenge icon

التحدي

متوسط

ارفض المهام الفارغة في _addTask:

  • اقرأ الحقل باستخدام trim()
  • عندما لا يتبقى شيء، اعرض SnackBar يقول Type a task first ولا تضف شيئًا
  • وإلا فأضف العنوان بعد إزالة المسافات الزائدة

جرّب بنفسك

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();

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

  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),
                ),
              ],
            ),
          ),
          Padding(
            padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
            child: Row(
              children: [
                Text(
                  _left == 1 ? '1 task left' : '$_left tasks left',
                  style: Theme.of(context).textTheme.titleSmall,
                ),
              ],
            ),
          ),
          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 عبر الإنترنت