Vou te dar um código. Depois vou te mando as instruções: import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:async';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Gerenciador de Tarefas',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: LoginPage(),
    );
  }
}

class LoginPage extends StatefulWidget {
  @override
  _LoginPageState createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {
  final emailController = TextEditingController();
  final passwordController = TextEditingController();

  Future<void> fazerLogin(String email, String senha) async {
    final url = Uri.https('barra.cos.ufrj.br:443', '/rest/rpc/fazer_login');
    final Map<String, String> headers = {
      'accept': 'application/json',
      'Content-Type': 'application/json',
    };
    final Map<String, String> body = {
      'email': email,
      'senha': senha,
    };
    final String jsonBody = json.encode(body);

    try {
      final response = await http.post(url, headers: headers, body: jsonBody);
      if (response.statusCode == 200) {
        final data = json.decode(response.body);
        final token = data['token'];
        Navigator.pushReplacement(
          context,
          MaterialPageRoute(
            builder: (context) => TaskListPage(token: token, email: email),
          ),
        );
      } else {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
              content: Text('Erro: ${response.statusCode} - ${response.body}')),
        );
      }
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Ocorreu um erro: ${e.toString()}')),
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Login')),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
                controller: emailController,
                decoration: InputDecoration(labelText: 'Email')),
            TextField(
                controller: passwordController,
                decoration: InputDecoration(labelText: 'Senha'),
                obscureText: true),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () =>
                  fazerLogin(emailController.text, passwordController.text),
              child: Text('Login'),
            ),
            TextButton(
              onPressed: () {
                Navigator.push(context,
                    MaterialPageRoute(builder: (context) => SignUpPage()));
              },
              child: Text('Criar conta'),
            ),
          ],
        ),
      ),
    );
  }
}

class SignUpPage extends StatefulWidget {
  @override
  _SignUpPageState createState() => _SignUpPageState();
}

class _SignUpPageState extends State<SignUpPage> {
  final emailController = TextEditingController();
  final passwordController = TextEditingController();
  final confirmPasswordController = TextEditingController();
  final phoneController = TextEditingController();
  final nomeController = TextEditingController();

  Future<void> signUp() async {
    if (passwordController.text != confirmPasswordController.text) {
      ScaffoldMessenger.of(context)
          .showSnackBar(SnackBar(content: Text('As senhas não coincidem.')));
      return;
    }

    final Map<String, dynamic> body = {
      'celular': '21900000000',
      'email': emailController.text,
      'nome': nomeController.text,
      'senha': passwordController.text,
    };

    if (phoneController.text.isNotEmpty) {
      body['celular'] = phoneController.text;
    }

    final response = await http.post(
      Uri.parse('https://barra.cos.ufrj.br:443/rest/rpc/registra_usuario'),
      headers: {'Content-Type': 'application/json'},
      body: json.encode(body),
    );

    if (response.statusCode == 200) {
      ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Usuário cadastrado com sucesso!')));
      final loginResponse = await http.post(
        Uri.parse('https://barra.cos.ufrj.br:443/rest/rpc/fazer_login'),
        headers: {
          'accept': 'application/json',
          'Content-Type': 'application/json',
        },
        body: json.encode({
          'email': emailController.text,
          'senha': passwordController.text,
        }),
      );

      if (loginResponse.statusCode == 200) {
        final loginData = json.decode(loginResponse.body);
        final String token = loginData['token'];
        await criarTarefas(token, emailController.text);
        Navigator.pop(context);
      } else {
        ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('Erro ao obter token de login.')));
      }
    } else {
      ScaffoldMessenger.of(context)
          .showSnackBar(SnackBar(content: Text('Erro ao cadastrar.')));
    }
  }

  Future<void> criarTarefas(String token, String email) async {
    final url = Uri.https('barra.cos.ufrj.br:443', '/rest/tarefas');
    final headers = {
      'Authorization': 'Bearer $token',
      'Content-Type': 'application/json',
    };
    final body = json.encode({
      'email': email,
      'valor': [],
    });

    try {
      final response = await http.post(url, headers: headers, body: body);

      if (response.statusCode != 201) {
        print(
            'Erro ao criar tarefas: ${response.statusCode} - ${response.body}');
      }
    } catch (e) {
      print('Erro: ${e.toString()}');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Cadastro')),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Column(
          children: [
            TextField(
                controller: emailController,
                decoration: InputDecoration(labelText: 'Email')),
            TextField(
                controller: nomeController,
                decoration: InputDecoration(labelText: 'Nome')),
            TextField(
                controller: passwordController,
                decoration: InputDecoration(labelText: 'Senha'),
                obscureText: true),
            TextField(
                controller: confirmPasswordController,
                decoration: InputDecoration(labelText: 'Confirmar Senha'),
                obscureText: true),
            TextField(
                controller: phoneController,
                decoration: InputDecoration(labelText: 'Celular')),
            SizedBox(height: 20),
            ElevatedButton(onPressed: signUp, child: Text('Cadastrar')),
          ],
        ),
      ),
    );
  }
}

class TaskListPage extends StatefulWidget {
  final String token;
  final String email;

  const TaskListPage({required this.token, required this.email});

  @override
  _TaskListPageState createState() => _TaskListPageState();
}

class _TaskListPageState extends State<TaskListPage> {
  List<Map<String, dynamic>> tasks = [];
  final textController = TextEditingController();

  bool _tasksLoaded = false;
  Map<String, Timer> _deleteTimers = {};

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

  Future<void> fetchTasks() async {
    final response = await http.get(
      Uri.parse(
          'https://barra.cos.ufrj.br:443/rest/tarefas?email=eq.${widget.email}'),
      headers: {
        'Authorization': 'Bearer ${widget.token}',
        'Content-Type': 'application/json'
      },
    );

    if (response.statusCode == 200) {
      final data = json.decode(response.body);
      setState(() {
        tasks.clear();
        if (data.isNotEmpty) {
          tasks.addAll(List<Map<String, dynamic>>.from(data[0]['valor']));
        }
        for (var task in tasks) {
          task['isBeingDeleted'] = false;
          task['isAnimating'] = false;
        }
        _tasksLoaded = true;
      });
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
            content: Text('Erro ao carregar tarefas: ${response.statusCode}')),
      );
    }
  }

  Future<void> addTask(String title) async {
    if (title.trim().isEmpty) return;

    setState(() {
      tasks.insert(0, {
        'titulo': title.trim(),
        'concluida': false,
        'isBeingDeleted': false,
        'isAnimating': false,
      });
    });

    await updateTasksOnServer();
    textController.clear();
  }

  Future<void> updateTasksOnServer() async {
    final response = await http.patch(
      Uri.parse(
          'https://barra.cos.ufrj.br:443/rest/tarefas?email=eq.${widget.email}'),
      headers: {
        'Authorization': 'Bearer ${widget.token}',
        'Content-Type': 'application/json'
      },
      body: json.encode({'email': widget.email, 'valor': tasks}),
    );

    if (response.statusCode != 204) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
            content: Text(
                'Erro ao atualizar tarefas: ${response.statusCode} ${response.body}')),
      );
    }
  }

  void _toggleCompletion(int index) {
    setState(() {
      var task = tasks[index];
      task['concluida'] = !task['concluida'];
      task['isAnimating'] = true;

      tasks.removeAt(index);

      if (task['concluida'] == true) {
        int newIndex = tasks.indexWhere((t) => t['concluida'] == true);
        if (newIndex == -1) {
          tasks.add(task);
        } else {
          tasks.insert(newIndex, task);
        }
      } else {
        int newIndex = tasks.lastIndexWhere((t) => t['concluida'] == false);
        tasks.insert(newIndex + 1, task);
      }

      Future.delayed(Duration(milliseconds: 500), () {
        setState(() {
          task['isAnimating'] = false;
        });
      });
    });

    updateTasksOnServer();
  }

  void _deleteTaskWithUndo(int index) {
    final task = tasks[index];
    setState(() {
      tasks[index]['isBeingDeleted'] = true;
    });

    _deleteTimers[task['titulo']] = Timer(Duration(seconds: 3), () {
      if (mounted && tasks.contains(task) && task['isBeingDeleted'] == true) {
        _deleteTask(index);
      }
    });
  }

  void _undoDeleteTask(int index) {
    final task = tasks[index];
    setState(() {
      tasks[index]['isBeingDeleted'] = false;
    });

    _deleteTimers[task['titulo']]?.cancel();
    _deleteTimers.remove(task['titulo']);

    updateTasksOnServer();
  }

  void _deleteTask(int index) {
    final task = tasks[index];
    _deleteTimers[task['titulo']]?.cancel();
    _deleteTimers.remove(task['titulo']);

    setState(() {
      tasks.removeAt(index);
    });
    updateTasksOnServer();
  }

  double _calculateTopPosition(int index) {
    double itemHeight = 86.0;
    return index * itemHeight;
  }

  @override
  Widget build(BuildContext context) {
    if (!_tasksLoaded) {
      return Scaffold(
        appBar: AppBar(
          title: const Text('Task List'),
          backgroundColor: const Color.fromARGB(255, 128, 0, 0),
        ),
        body: Center(child: CircularProgressIndicator()),
      );
    }

    List<Widget> taskWidgets = [];
    for (var i = 0; i < tasks.length; i++) {
      final task = tasks[i];
      final isBeingDeleted = task['isBeingDeleted'] == true;
      final isCompleted = task['concluida'] == true;
      final topPosition = _calculateTopPosition(i);

      final backgroundColor = isBeingDeleted
          ? Colors.red
          : (i % 3 == 0
              ? const Color.fromARGB(255, 99, 12, 0)
              : i % 3 == 1
                  ? const Color.fromARGB(255, 245, 245, 245)
                  : const Color.fromARGB(255, 0, 63, 5));
      final textColor =
          backgroundColor == const Color.fromARGB(255, 0, 63, 5) ||
                  backgroundColor == const Color.fromARGB(255, 99, 12, 0)
              ? Colors.white
              : Colors.black;

      Widget taskWidget = AnimatedPositioned(
        key: ValueKey(task['titulo']),
        duration: Duration(milliseconds: 500),
        curve: Curves.easeInOut,
        top: topPosition,
        left: 0,
        right: 0,
        child: TweenAnimationBuilder<double>(
          key: ValueKey(task['titulo'] + task['isAnimating'].toString()),
          tween: Tween(begin: task['isAnimating'] ? 0.1 : 0.0, end: 0.0),
          duration: Duration(milliseconds: 500),
          builder: (context, tilt, child) {
            return Transform(
              transform: Matrix4.rotationZ(tilt),
              alignment: Alignment.center,
              child: child,
            );
          },
          child: Dismissible(
            key: ValueKey(task['titulo'] + "dismissible"),
            background: Container(
              color: Colors.green,
              alignment: Alignment.centerLeft,
              padding: const EdgeInsets.only(left: 20.0),
              child: const Icon(Icons.check, color: Colors.white),
            ),
            secondaryBackground: Container(
              color: Colors.red,
              alignment: Alignment.centerRight,
              padding: const EdgeInsets.only(right: 20.0),
              child: const Icon(Icons.delete, color: Colors.white),
            ),
            confirmDismiss: (direction) async {
              int index = tasks.indexOf(task);
              if (direction == DismissDirection.endToStart) {
                _deleteTaskWithUndo(index);
                return false;
              } else if (direction == DismissDirection.startToEnd) {
                _toggleCompletion(index);
                return false;
              }
              return false;
            },
            child: Container(
              margin: const EdgeInsets.symmetric(
                  horizontal: 16.0, vertical: 8.0),
              decoration: BoxDecoration(
                color: backgroundColor,
                borderRadius: BorderRadius.circular(8.0),
                border: Border.all(
                  color: const Color.fromARGB(255, 0, 42, 116),
                  width: 2.0,
                ),
              ),
              child: ListTile(
                title: Text(
                  task['titulo'],
                  style: TextStyle(
                    color: textColor,
                    decoration: isCompleted
                        ? TextDecoration.lineThrough
                        : TextDecoration.none,
                  ),
                ),
                trailing: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Checkbox(
                      value: isCompleted,
                      onChanged: (_) {
                        int index = tasks.indexOf(task);
                        _toggleCompletion(index);
                      },
                    ),
                    isBeingDeleted
                        ? IconButton(
                            icon: const Icon(Icons.undo),
                            onPressed: () {
                              int index = tasks.indexOf(task);
                              _undoDeleteTask(index);
                            },
                          )
                        : IconButton(
                            icon: const Icon(Icons.delete),
                            onPressed: () {
                              int index = tasks.indexOf(task);
                              _deleteTaskWithUndo(index);
                            },
                          ),
                  ],
                ),
              ),
            ),
          ),
        ),
      );

      taskWidgets.add(taskWidget);
    }

    double totalHeight = tasks.length * 86.0;

    return Scaffold(
      appBar: AppBar(
        title: const Text('Task List'),
        backgroundColor: const Color.fromARGB(255, 128, 0, 0),
      ),
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: TextField(
              controller: textController,
              onSubmitted: (value) {
                addTask(value);
              },
              decoration: const InputDecoration(
                labelText: 'Add Task',
              ),
            ),
          ),
          Expanded(
            child: SingleChildScrollView(
              child: SizedBox(
                height: totalHeight,
                child: Stack(
                  children: taskWidgets,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}