Good afternoon! I have a problem with the following code, as it throws out this error══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
The following assertion was thrown during performResize():
Vertical viewport was given unbounded height.
Viewports expand in the scrolling direction to fill their container. In this case, a vertical
viewport was given an unlimited amount of vertical space in which to expand. This situation
typically happens when a scrollable widget is nested inside another scrollable widget.
If this widget is always nested in a scrollable widget there is no need to use a viewport because
there will always be enough vertical space for the children. In this case, consider using a Column
or Wrap instead. Otherwise, consider using a CustomScrollView to concatenate arbitrary slivers into
a single scrollable. import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'dart:collection';

Future<Map<String,dynamic>> fazerLogin(String email, String senha) async {
  // URL do endpoint
  final url = Uri.https('barra.cos.ufrj.br:443', '/rest/rpc/fazer_login');

  // Headers da requisição
  final Map<String,String> headers = {
    'accept': 'application/json',
    'Content-Type': 'application/json',
  };

  // Corpo da requisição (JSON)
  final Map<String,String> body = {
    'email': email,
    'senha': senha,
  };

  // Converte o body para JSON
  final String jsonBody = json.encode(body);

  try {
    // Realiza a requisição POST
    final response = await http.post(url, headers: headers, body: jsonBody);
    final decodedResponse = json.decode(response.body);

    // Verifica o código de status da resposta
    if (response.statusCode == 200) {
      // Sucesso na requisição
      final jwt = decodedResponse['token'];
      return {
        'login':true,
        'token':jwt
      };
    } else {
      // Erro na requisição
      //print('Erro: ${response.statusCode} - ${response.body}');
      final erro = decodedResponse['message'];
      return {
        'login':false,
        'erro': erro
      };
    }
  } catch (e) {
    // Tratamento de exceções
    //print('Ocorreu um erro: ${e.toString()}');
    return {
      'login':false
    };
  }
}

Future<Map<String,dynamic>> fazerCadastro(String nome, String email, String celular, String senha) async {
  // URL do endpoint
  final url = Uri.https('barra.cos.ufrj.br:443', '/rest/rpc/registra_usuario');

  // Headers da requisição
  final Map<String,String> headers = {
    'accept': 'application/json',
    'Content-Type': 'application/json',
  };

  // Corpo da requisição (JSON)
  final Map<String,String> body = {
    'nome': nome,
    'email': email,
    'celular': celular,
    'senha': senha,
  };

  // Converte o body para JSON
  final String jsonBody = json.encode(body);

  try {
    // Realiza a requisição POST
    final response = await http.post(url, headers: headers, body: jsonBody);
    final decodedResponse = json.decode(response.body);

    // Verifica o código de status da resposta
    if (response.statusCode == 200) {
      // Sucesso na requisição
      return {
        'cadastro': true,
      };
    } else {
      // Erro na requisição
      //print('Erro: ${response.statusCode} - ${response.body}');
      return {
        'cadastro': false,
        'erro': decodedResponse['message']
      };
    }
  } catch (e) {
    // Tratamento de exceções
    //print('Ocorreu um erro: ${e.toString()}');
    return {'cadastro': false};
  }
}
void main() async => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Lista de Tarefas',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorSchemeSeed: Colors.blue,
      ),
      home: const LoginPage(title: 'Login'),
    );
  }
}

class Task {
  String title;
  bool isCompleted;

  Task({required this.title, this.isCompleted = false});
  
  Map<String, dynamic> toJson() {
    return {
      'title': title,
      'isCompleted': isCompleted,
    };
  }

  // Método para criar um objeto Task a partir de um mapa (vindo de JSON)
  factory Task.fromJson(Map<String, dynamic> json) {
    return Task(
      title: json['title'],
      isCompleted: json['isCompleted'],
    );
  }
}

class MyHomePage extends StatefulWidget {
  final String title;
  final String email;
  final String token;

  const MyHomePage({
    super.key,
    required this.title,
    required this.email,
    required this.token,
  });

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List<Task> taskList = [];
  int? taskIndexToRemove;
  bool deletar = false;
  Completer<void>? completerDeletar;

  late String email;
  late String token;

  @override
  void initState() {
    super.initState();
    email = widget.email;
    token = widget.token;
    getLista(token);
  }
  final textController = TextEditingController();


Future salvarLista(String email, String? jwt, List taskList) async {
  // URL do endpoint
  final url = Uri.https('barra.cos.ufrj.br:443', '/rest/tarefas');

  if (jwt == null){
    //print('Token inválido');
  }

  final List taskJsonList = taskList.map((task) => task.toJson()).toList();

  // Headers da requisição
  final Map<String,String> headers = {
    'accept': 'application/json',
    'Content-Type': 'application/json',
    'Authorization':'Bearer $jwt',
  };

  // Corpo da requisição (JSON)
  final Map<String,dynamic> body = {
    'email': email,
    'valor': taskJsonList
  };

  // Converte o body para JSON
  final String jsonBody = json.encode(body);

  try {
    // Realiza a requisição POST
    final deletion = await http.delete(url, headers: headers, body: jsonBody);
    if (deletion.statusCode == 401){
      final decodedDeletion = json.decode(deletion.body);
      if (decodedDeletion['code'] == "PGRST301"){
        Navigator.pushAndRemoveUntil(
                    context,
                    MaterialPageRoute(builder: (context) => LoginPage(title: 'Login', errorMessage: 'O token expirou. Por favor, faça login novamente.')),
                    (Route<dynamic> route) => false,
                  );
      }
    }
    final response = await http.post(url, headers: headers, body: jsonBody);

    // Verifica o código de status da resposta
    if (response.statusCode == 201) {
      // Sucesso na requisição
    } else {
      //print('Erro: ${response.statusCode} - ${response.body}');
    }
  } catch (e) {
    //print('Ocorreu um erro: ${e.toString()}');
  }
}

Future getLista(String? jwt) async {
  final url = Uri.https('barra.cos.ufrj.br:443', '/rest/tarefas');

  if (jwt == null){
    //print('Token inválido');
  }

  // Headers da requisição
  final Map<String,String> headers = {
    'accept': 'application/json',
    'Content-Type': 'application/json',
    'Authorization':'Bearer $jwt',
  };

  try {
    // Realiza a requisição GET
    final response = await http.get(url, headers: headers);

    // Verifica o código de status da resposta
    if (response.statusCode == 200) {
      // Sucesso na requisição
      final decodedResponse = json.decode(response.body);
      List taskListFetched = decodedResponse[0]['valor'];
      List<Task> taskListTasks = [];
      for (var i=0;i<taskListFetched.length;i++){
        taskListTasks.add(Task.fromJson(taskListFetched[i]));
      }
      setState(() {
        taskList = taskListTasks; 
        });

    } else {
      //print('Erro: ${response.statusCode} - ${response.body}');
    }
  } catch (e) {
    //print('Ocorreu um erro: ${e.toString()}');
  }
}

  void _addTask(String st) {
    setState(() {
      if (st.trim().isNotEmpty) {
        for (var x = 0; x < taskList.length; x++) {
          if (taskList[x].title == st.trim()) {
            return;
          }
        }
        final task = Task(title: st.trim());
        taskList.add(task);
        _sortTaskList();
        textController.clear();
      }
    });
    salvarLista(email, token, taskList);
  }

  void _sortTaskList() {
    taskList.sort((a, b) {
      if (a.isCompleted == b.isCompleted) {
        return 0;
      } else if (a.isCompleted) {
        return 1;
      } else {
        return -1;
      }
    });
  }

  Future<void> _deleteTask(int index) async {
    setState(() {
      taskIndexToRemove = index;
      deletar = true;
      completerDeletar = Completer<void>();
    });

    await Future.any([
      Future.delayed(const Duration(seconds: 3)),
      completerDeletar!.future
    ]);

    if (!completerDeletar!.isCompleted) {
      _removePermanently();
    }
  }

  void _undoDelete(String completion) {
    setState(() {
      if (completerDeletar != null && !completerDeletar!.isCompleted) {
        // Cancela a operação de deleção
        completerDeletar!.complete();
      }
      deletar = false;
    });
  }

  void _removePermanently() {
    setState(() {
      taskList.removeAt(taskIndexToRemove!);
      deletar = false;
    });
    salvarLista(email, token, taskList);
  }

  void _toggleCompletion(int index) {
    setState(() {
      taskList[index].isCompleted = !taskList[index].isCompleted;
      _sortTaskList();
    });
    salvarLista(email, token, taskList);
  }

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

  Widget _buildTaskList() {
    return Expanded(
      child: Stack(
        children: _buildStackChildren(),
      ),
    );
  }

  List<Widget> _buildStackChildren() {
    List<Widget> stackChildren = [];

    for (int index = 0; index < taskList.length; index++) {
      Task task = taskList[index];

      stackChildren.add(
        AnimatedPositioned(
          key: ValueKey(task.title),
          duration: const Duration(milliseconds: 500),
          top: 55.0 * index,
          left: 0,
          right: 0,
          child: TaskItemWidget(
            task: task,
            index: index,
            isBeingDeleted: deletar && taskIndexToRemove == index,
            onToggleCompletion: _toggleCompletion,
            onDeleteTask: _deleteTask,
            onUndoDelete: _undoDelete,
          ),
        ),
      );
    }

    return stackChildren;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        foregroundColor: Colors.white,
        backgroundColor: Colors.purple,
        title: Text(widget.title),
      ),
      drawer: Drawer (
        backgroundColor: const Color.fromARGB(255, 174, 122, 184),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            const DrawerHeader(
              decoration: BoxDecoration(
                color: Colors.purple,
              ),
              child: Center(
                child: Text(
                  'Menu',
                  style: TextStyle(
                    color: Colors.white,
                  ),
                ),
              ),
            ),
            ListTile(
              title: const Text('Minha Lista de Tarefas'),
              onTap: () {
                  Navigator.pushAndRemoveUntil(
                    context, 
                    MaterialPageRoute(builder: (context) => MyHomePage(title: 'Minha Lista de Tarefas', email: email, token: token)),
                    (Route<dynamic> route) => false,);
              },
            ),
            ListTile(
              title: Text("Meu Chat"),
              onTap: () {
                  Navigator.pushAndRemoveUntil(
                    context, 
                    MaterialPageRoute(builder: (context) => ChatPage(title: 'Chat', email: email, token: token, novaConversa: false)),
                    (Route<dynamic> route) => false,);
              },
            ),
            ListTile(
              title: Text("Iniciar nova conversa"),
              onTap: () {
                Navigator.pushAndRemoveUntil(
                    context, 
                    MaterialPageRoute(builder: (context) => ChatPage(title: 'Chat', email: email, token: token, novaConversa: true)),
                    (Route<dynamic> route) => false,);
              },
            ),
            Spacer(),
            Container(
              margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), 
              decoration: BoxDecoration(
                color: Colors.purple, 
                borderRadius: BorderRadius.circular(30),
              ),
              child: ListTile(
                title: const Text(
                  'Logout',
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    color: Colors.white,
                  ),
                ),
                onTap: () {
                  Navigator.pushAndRemoveUntil(
                    context,
                    MaterialPageRoute(builder: (context) => LoginPage(title: 'Login')),
                    (Route<dynamic> route) => false,
                  );
                },
              ),
            ),
          ],
        ),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: [
          Container(
            // Campo para inserir tarefas
            margin:
                const EdgeInsets.only(top: 10, left: 10, right: 10, bottom: 0),
            child: TextField(
              controller: textController,
              autofocus: true,
              onSubmitted: _addTask,
              decoration: InputDecoration(
                  hintText: 'Adicione uma nova tarefa',
                  suffixIcon: IconButton(
                    onPressed: () => _addTask(textController.text),
                    tooltip: 'Adicionar Tarefa',
                    icon: const Icon(Icons.add_box),
                  ),
                  border: const OutlineInputBorder(),
                  enabledBorder: OutlineInputBorder(
                    borderSide: const BorderSide(color: Colors.purple),
                    borderRadius: BorderRadius.circular(25.0),
                  ),
                  focusedBorder: OutlineInputBorder(
                    borderSide:
                        const BorderSide(color: Color.fromARGB(255, 81, 2, 95)),
                    borderRadius: BorderRadius.circular(25.0),
                  ),
                  filled: true,
                  fillColor: const Color.fromARGB(255, 224, 186, 231)),
            ),
          ),
          _buildTaskList(),
        ],
      ),
    );
  }
}

class TaskItemWidget extends StatelessWidget {
  final Task task;
  final int index;
  final bool isBeingDeleted;
  final Function(int) onToggleCompletion;
  final Function(int) onDeleteTask;
  final Function(String) onUndoDelete;

  const TaskItemWidget({
    Key? key,
    required this.task,
    required this.index,
    required this.isBeingDeleted,
    required this.onToggleCompletion,
    required this.onDeleteTask,
    required this.onUndoDelete,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return TweenAnimationBuilder<double>(
      key: ValueKey(task.isCompleted),
      tween: Tween(begin: task.isCompleted ? 0.1 : 0.0, end: 0.0),
      duration: const Duration(milliseconds: 500),
      curve: Curves.easeInOut,
      builder: (context, tilt, child) {
        return Transform(
          alignment: Alignment.center,
          transform: Matrix4.rotationZ(tilt),
          child: _buildTaskContainer(context),
        );
      },
    );
  }

  Widget _buildTaskContainer(BuildContext context) {
    Completer<bool?> apertouBotao = Completer();
    final List<Color> cores = [const Color.fromARGB(255, 199, 114, 214), const Color.fromARGB(255, 222, 187, 226)];

    return Container(
      margin: const EdgeInsets.only(top: 10, left: 10, right: 10, bottom: 0),
      color: isBeingDeleted ? Colors.red : cores[index%2],
      child: Dismissible(
        key: UniqueKey(), // Chave única para cada item
        onDismissed: (direction) {
          if (direction == DismissDirection.endToStart) {
            // Remove o item da lista
            onDeleteTask(index);
          }
          if (direction == DismissDirection.startToEnd) {
            onToggleCompletion(index);
          }
        },
        background: Container(
          color: Colors.green,
          alignment: Alignment.centerLeft,
          padding: const EdgeInsets.symmetric(horizontal: 20),
          child: task.isCompleted
              ? const Icon(Icons.check_box_outline_blank,
                  color: Colors.black)
              : const Icon(Icons.check_box, color: Colors.black),
        ),
        secondaryBackground: Container(
          color: Colors.red,
          alignment: Alignment.centerRight,
          padding: const EdgeInsets.symmetric(horizontal: 20),
          child: IconButton(
            onPressed: () {
              apertouBotao.complete(false);
            },
            icon: const Icon(Icons.undo, color: Colors.black),
          ),
        ),
        child: ListTile(
          title: Text(
            task.title,
            style: task.isCompleted
                ? const TextStyle(decoration: TextDecoration.lineThrough)
                : null,
          ),
          leading: Checkbox(
            value: task.isCompleted,
            onChanged: (value) {
              onToggleCompletion(index);
            },
          ),
          trailing: IconButton(
            icon: Icon(
              isBeingDeleted ? Icons.undo : Icons.delete,
            ),
            tooltip: 'Apagar Tarefa',
            onPressed: () {
              if (isBeingDeleted) {
                onUndoDelete('completed');
              } else {
                onDeleteTask(index);
              }
            },
          ),
        ),
      ),
    );
  }
}

class LoginPage extends StatefulWidget {
  final String title;
  final String? errorMessage;

  const LoginPage({
    super.key,
    required this.title,
    this.errorMessage,
  });

  @override
  State<LoginPage> createState() => _LoginPageState();
}

class _LoginPageState extends State<LoginPage> {

  final textControllerEmail = TextEditingController();
  final textControllerSenha = TextEditingController();
  String? message; // Para armazenar a mensagem

  @override
  void dispose() {
    textControllerEmail.dispose();
    textControllerSenha.dispose();
    super.dispose();
  }

  void showMessage(String msg) {
    setState(() {
      message = msg;
    });
  }

  void clearMessage(String msg) {
    setState(() {
      message = null;
    });
  }
  
  @override
  Widget build(BuildContext context) {
    if (widget.errorMessage != null){
      showMessage(widget.errorMessage!);
    }
    return Scaffold(
      appBar: AppBar(
        foregroundColor: Colors.white,
        backgroundColor: Colors.purple,
        title: const Text('Login'),
      ),
      body: Column(
        children: [

          Container( //Campo para inserir email
            margin: const EdgeInsets.only(top: 10,left: 10,right: 10,bottom: 0),
            child: TextField(
              controller: textControllerEmail,
              autofocus: true,
              decoration: InputDecoration(
                hintText: 'E-mail',
                border: const OutlineInputBorder(),
                enabledBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Colors.purple),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                focusedBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Color.fromARGB(255, 81, 2, 95)),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                filled: true,
                fillColor: const Color.fromARGB(255, 224, 186, 231)
              ),
            ),
          ),

          Container( //Campo para inserir senha
            margin: const EdgeInsets.only(top: 10,left: 10,right: 10,bottom: 0),
            child: TextField(
              controller: textControllerSenha,
              autofocus: true,
              obscureText: true,
              decoration: InputDecoration(
                hintText: 'Senha',
                border: const OutlineInputBorder(),
                enabledBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Colors.purple),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                focusedBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Color.fromARGB(255, 81, 2, 95)),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                filled: true,
                fillColor: const Color.fromARGB(255, 224, 186, 231)
              ),
            ),
          ),

          Container(
            margin: const EdgeInsets.only(top:15),
            child: ElevatedButton(
              onPressed: () async {
                String email = textControllerEmail.text;
                String senha = textControllerSenha.text;
                var loginResponse = await fazerLogin(email, senha);
                if (await loginResponse['login']==true){
                  final token = loginResponse['token'];
                  Navigator.pushAndRemoveUntil(
                    context,
                    MaterialPageRoute(builder: (context) => ChatPage(title: 'Chat', email: email, token: token, novaConversa: false)),
                    (Route<dynamic> route) => false,
                  );
              } else{
                showMessage(loginResponse['erro']);
              }
              },
              child: const Text(
                'Fazer Login',
                style: TextStyle(color:Colors.purple)
              ),
            ),
          ),

          Container(
            margin: const EdgeInsets.only(top:15),
            child: ElevatedButton(
              onPressed: () async {
                final resultadoCadastro = await Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => const SignUpPage (title: 'Cadastrar-se',)),
                );
                if (resultadoCadastro != null){
                  showMessage(resultadoCadastro);
                }
              },
              child: const Text(
                'Não possui conta? Cadastre-se.',
                style: TextStyle(color:Colors.purple)
              ),
            ),
          ),

          if (message != null) // Verifica se há mensagem para mostrar
            Padding(
              padding: const EdgeInsets.only(top: 10),
              child: Text(
                message!,
                style: const TextStyle(color: Colors.red),
              ),
            ),
        ]
      ),
    );
  }
}

class SignUpPage extends StatefulWidget {
  final String title;

  const SignUpPage({
    super.key,
    required this.title,
  });

  @override
  State<SignUpPage> createState() => _SignUpPageState();
}

class _SignUpPageState extends State<SignUpPage> {

  final textControllerNome = TextEditingController();
  final textControllerEmail = TextEditingController();
  final textControllerCelular = TextEditingController();
  final textControllerSenha = TextEditingController();
  final textControllerConfirmarSenha = TextEditingController();
  String? message;

  @override
  void dispose() {
    textControllerEmail.dispose();
    textControllerSenha.dispose();
    textControllerNome.dispose();
    textControllerCelular.dispose();
    textControllerConfirmarSenha.dispose();
    super.dispose();
  }

    void showMessage(String msg) {
    setState(() {
      message = msg;
    });
  }

  void clearMessage(String msg) {
    setState(() {
      message = null;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        foregroundColor: Colors.white,
        backgroundColor: Colors.purple,
        title: const Text('Cadastrar-se'),
      ),
      body: Column(
        children: [

          Container( //Campo para inserir nome
            margin: const EdgeInsets.only(top: 10,left: 10,right: 10,bottom: 0),
            child: TextField(
              controller: textControllerNome,
              autofocus: true,
              decoration: InputDecoration(
                hintText: 'Nome',
                border: const OutlineInputBorder(),
                enabledBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Colors.purple),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                focusedBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Color.fromARGB(255, 81, 2, 95)),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                filled: true,
                fillColor: const Color.fromARGB(255, 224, 186, 231)
              ),
            ),
          ),

          Container( //Campo para inserir email
            margin: const EdgeInsets.only(top: 10,left: 10,right: 10,bottom: 0),
            child: TextField(
              controller: textControllerEmail,
              autofocus: true,
              decoration: InputDecoration(
                hintText: 'E-mail',
                border: const OutlineInputBorder(),
                enabledBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Colors.purple),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                focusedBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Color.fromARGB(255, 81, 2, 95)),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                filled: true,
                fillColor: const Color.fromARGB(255, 224, 186, 231)
              ),
            ),
          ),

          Container( //Campo para inserir celular
            margin: const EdgeInsets.only(top: 10,left: 10,right: 10,bottom: 0),
            child: TextField(
              controller: textControllerCelular,
              autofocus: true,
              decoration: InputDecoration(
                hintText: 'Celular',
                border: const OutlineInputBorder(),
                enabledBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Colors.purple),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                focusedBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Color.fromARGB(255, 81, 2, 95)),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                filled: true,
                fillColor: const Color.fromARGB(255, 224, 186, 231)
              ),
            ),
          ),

          Container( //Campo para inserir senha
            margin: const EdgeInsets.only(top: 10,left: 10,right: 10,bottom: 0),
            child: TextField(
              controller: textControllerSenha,
              autofocus: true,
              obscureText: true,
              decoration: InputDecoration(
                hintText: 'Senha',
                border: const OutlineInputBorder(),
                enabledBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Colors.purple),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                focusedBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Color.fromARGB(255, 81, 2, 95)),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                filled: true,
                fillColor: const Color.fromARGB(255, 224, 186, 231)
              ),
            ),
          ),

          Container( //Campo para inserir senha novamente
            margin: const EdgeInsets.only(top: 10,left: 10,right: 10,bottom: 0),
            child: TextField(
              controller: textControllerConfirmarSenha,
              autofocus: true,
              obscureText: true,
              decoration: InputDecoration(
                hintText: 'Confirmar Senha',
                border: const OutlineInputBorder(),
                enabledBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Colors.purple),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                focusedBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Color.fromARGB(255, 81, 2, 95)),
                  borderRadius: BorderRadius.circular(25.0),
                ),
                filled: true,
                fillColor: const Color.fromARGB(255, 224, 186, 231)
              ),
            ),
          ),

          Container(
            margin: const EdgeInsets.only(top:15),
            child: ElevatedButton(
              onPressed: () async {
                String nome = textControllerNome.text;
                String email = textControllerEmail.text;
                String celular = textControllerCelular.text;
                String senha = textControllerSenha.text;
                String confirmarSenha = textControllerConfirmarSenha.text;
                if (senha != confirmarSenha){
                  showMessage('As senhas precisam ser iguais!');
                } else {
                  var signupResponse = await fazerCadastro(nome, email, celular, senha);
                  if (await signupResponse['cadastro']==true){
                    Navigator.pop(context, 'Cadastro realizado com sucesso!');
                  } else {
                    showMessage(signupResponse['erro']);
                  }
                }
              },
              child: const Text(
                'Cadastrar-se',
                style: TextStyle(color:Colors.purple)
              ),
            ),
          ),

          Container(
            margin: const EdgeInsets.only(top:15),
            child: ElevatedButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: const Text(
                'Já possui conta? Faça login.',
                style: TextStyle(color:Colors.purple)
              ),
            ),
          ),
          if (message != null) // Verifica se há mensagem para mostrar
            Padding(
              padding: const EdgeInsets.only(top: 10),
              child: Text(
                message!,
                style: const TextStyle(color: Colors.red),
              ),
            ),
        ]
      ),
    );
  }
}

class ChatPage extends StatefulWidget {
  final String title;
  final String email;
  final String token;
  final bool novaConversa;

  const ChatPage({
    super.key,
    required this.title,
    required this.email,
    required this.token,
    required this.novaConversa,
  });

  @override
  State<ChatPage> createState() => _ChatPageState();
}

class _ChatPageState extends State<ChatPage>{

  late String email;
  late String token;
  List<Map<String, dynamic>> mensagens = [];
  late String id;

  final textController = TextEditingController();

  @override
  void initState() {
    super.initState();
    email = widget.email;
    token = widget.token;
    if (widget.novaConversa) {
      _createConversa();
    } else {
      _getConversas();
    }
  }

  Future<void> _getConversas() async {

    final url = Uri.https('barra.cos.ufrj.br:443', '/rest/conversas');

    final Map<String,String> headers = {
      'accept': 'application/json',
      'Content-Type': 'application/json',
      'Authorization':'Bearer $token',
    };

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

      if (response.statusCode == 200) {
        final decodedResponse = json.decode(response.body);
        if (decodedResponse.isNotEmpty()){
          setState(() {
            mensagens = decodedResponse[0]['mensagens'];
            id = decodedResponse[0]['id'];
          });
        } else{
          await _createConversa();
        }
      } else {
          
      }
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Erro: ${e.toString()}')),
      );
    }

  }

  Future<void> _createConversa() async {
    final url = Uri.https('barra.cos.ufrj.br:443', '/rest/rpc/cria_conversa');

    final Map<String,String> headers = {
      'accept': 'application/json',
      'Content-Type': 'application/json',
      'Authorization':'Bearer $token',
    };
    try {
      final response = await http.post(url, headers: headers);
      if (response.statusCode == 200) {
        final decodedResponse = json.decode(response.body);
        await _getConversas();
      }
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Erro: ${e.toString()}')),
      );
    }
  }

  Future<void> _enviarResposta(String mensagem) async {

    mensagem = mensagem.trim();

    setState(() {
      mensagens.add({'papel': 'usuario', 'conteudo': mensagem});
    });

    final url = Uri.parse('https://barra.cos.ufrj.br/rest/rpc/envia_resposta');

    final Map<String,String> headers = {
      'accept': 'application/json',
      'Content-Type': 'application/json',
      'Authorization':'Bearer $token',
    };

    final body = json.encode({
      'conversa_id': id,
      'resposta': mensagem,
    });

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

      if (response.statusCode == 200){
        final decodedResponse = jsonDecode(response.body);
        if (decodedResponse.containsKey('pergunta')){
          setState(() {
            mensagens.add({'papel': 'assistente', 'conteudo': decodedResponse['pergunta']});
          });
        } else if (decodedResponse.containskey('tarefas')){
          _tarefasGeradas(List<String>.from(decodedResponse['tarefas']));
        }
      }
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Erro: ${e.toString()}')),
      );
    }
  }
  
  Future<void> _tarefasGeradas(List<String> tarefas) async{

  }
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        foregroundColor: Colors.white,
        backgroundColor: Colors.purple,
        title: const Text('Chat'),
      ),
      drawer: Drawer (
        backgroundColor: const Color.fromARGB(255, 174, 122, 184),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            const DrawerHeader(
              decoration: BoxDecoration(
                color: Colors.purple,
              ),
              child: Center(
                child: Text(
                  'Menu',
                  style: TextStyle(
                    color: Colors.white,
                  ),
                ),
              ),
            ),
            ListTile(
              title: const Text('Minha Lista de Tarefas'),
              onTap: () {
                  Navigator.pushAndRemoveUntil(
                    context, 
                    MaterialPageRoute(builder: (context) => MyHomePage(title: 'Minha Lista de Tarefas', email: email, token: token)),
                    (Route<dynamic> route) => false,);
              },
            ),
            ListTile(
              title: Text("Meu Chat"),
              onTap: () {
                  Navigator.pushAndRemoveUntil(
                    context, 
                    MaterialPageRoute(builder: (context) => ChatPage(title: 'Chat', email: email, token: token, novaConversa: false)),
                    (Route<dynamic> route) => false,);
              },
            ),
            ListTile(
              title: Text("Iniciar nova conversa"),
              onTap: () {
                Navigator.pushAndRemoveUntil(
                    context, 
                    MaterialPageRoute(builder: (context) => ChatPage(title: 'Chat', email: email, token: token, novaConversa: true)),
                    (Route<dynamic> route) => false,);
              },
            ),
            const Spacer(),
            Container(
              margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 10), 
              decoration: BoxDecoration(
                color: Colors.purple, 
                borderRadius: BorderRadius.circular(30),
              ),
              child: ListTile(
                title: const Text(
                  'Logout',
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    color: Colors.white,
                  ),
                ),
                onTap: () {
                  Navigator.pushAndRemoveUntil(
                    context,
                    MaterialPageRoute(builder: (context) => LoginPage(title: 'Login')),
                    (Route<dynamic> route) => false,
                  );
                },
              ),
            ),
          ],
        ),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          children: [
            ListView.builder(
              itemCount: mensagens.length,
              itemBuilder: (context,index){
                final mensagemAtual = mensagens[index];

                if (mensagemAtual['papel'] == 'assistente'){
                  Align(
                    alignment: Alignment.centerLeft,
                    child: Callout(
                      child: Text(
                        mensagemAtual['conteudo'],
                        style: TextStyle(color: Colors.black),
                      ),
                      triangleSize: 20,
                      triangleHeight: 10,
                      backgroundColor: Colors.grey[300]!,
                      isLeft: true,
                      position: "left", // Seta no lado esquerdo inferior inclinada
                    ),
                  );
                  SizedBox(height: 10);
                } else {
                   Align(
                    alignment: Alignment.centerRight,
                    child: Callout(
                      child: Text(
                        mensagemAtual['conteudo'],
                        style: TextStyle(color: Colors.white),
                      ),
                      triangleSize: 20,
                      triangleHeight: 10,
                      backgroundColor: Colors.purple,
                      isLeft: false,
                      position: "right", // Seta no lado direito inferior inclinada
                    ),
                  );
                  SizedBox(height: 10);
                }
              },
            ),
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: Row(
                children: [
                  Container(
                    margin:
                        const EdgeInsets.only(top: 10, left: 10, right: 10, bottom: 0),
                    child: TextField(
                      controller: textController,
                      autofocus: true,
                      onSubmitted: _enviarResposta,
                      decoration: InputDecoration(
                          hintText: 'O que deseja responder?',
                          suffixIcon: IconButton(
                            onPressed: () => _enviarResposta(textController.text),
                            tooltip: 'Enviar resposta',
                            icon: const Icon(Icons.send),
                          ),
                          border: const OutlineInputBorder(),
                          enabledBorder: OutlineInputBorder(
                            borderSide: const BorderSide(color: Colors.purple),
                            borderRadius: BorderRadius.circular(25.0),
                          ),
                          focusedBorder: OutlineInputBorder(
                            borderSide:
                                const BorderSide(color: Color.fromARGB(255, 81, 2, 95)),
                            borderRadius: BorderRadius.circular(25.0),
                          ),
                          filled: true,
                          fillColor: const Color.fromARGB(255, 224, 186, 231)),
                    ),
                  ),
                ]
              )
            )
          ]
        ),
      )
    );
  }
}

class CalloutPainter extends CustomPainter {
  final double triangleSize;
  final double triangleHeight;
  final String position;
  final Color backgroundColor;
  final bool isLeft; // Define se o balão é da esquerda ou direita

  CalloutPainter({
    required this.triangleSize,
    required this.triangleHeight,
    required this.position,
    required this.backgroundColor,
    this.isLeft = true,
  });

  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = Paint()
      ..color = backgroundColor
      ..style = PaintingStyle.fill;

    final Path balloonPath = Path();

    // Definir o corpo do balão (retângulo arredondado)
    final double margin = 10;
    final double radius = 8;
    final double bodyHeight = size.height - triangleHeight - margin;

    balloonPath.addRRect(RRect.fromRectAndRadius(
      Rect.fromLTWH(margin, margin, size.width - 2 * margin, bodyHeight),
      Radius.circular(radius),
    ));

    // Desenhar a seta na parte de baixo com inclinação para fora
    final Path trianglePath = Path();

    if (position == "left") {
      // Seta no lado esquerdo inferior, inclinada para a esquerda (obtusa)
      trianglePath.moveTo(
          margin + 10, bodyHeight + margin); // Base esquerda da seta
      trianglePath.lineTo(margin + 10 + triangleSize,
          bodyHeight + margin); // Base direita da seta
      trianglePath.lineTo(
          margin - 10, size.height); // Ponta da seta inclinada para fora
    } else if (position == "right") {
      // Seta no lado direito inferior, inclinada para a direita (obtusa)
      trianglePath.moveTo(size.width - margin - 10 - triangleSize,
          bodyHeight + margin); // Base esquerda da seta
      trianglePath.lineTo(size.width - margin - 10,
          bodyHeight + margin); // Base direita da seta
      trianglePath.lineTo(size.width + 10 - margin,
          size.height); // Ponta da seta inclinada para fora
    } else {
      // Seta no centro inferior (isósceles)
      double centerX = (size.width - triangleSize) / 2;
      trianglePath.moveTo(
          centerX, bodyHeight + margin); // Base esquerda da seta
      trianglePath.lineTo(
          centerX + triangleSize, bodyHeight + margin); // Base direita da seta
      trianglePath.lineTo(
          centerX + triangleSize / 2, size.height); // Ponta da seta (centro)
    }

    balloonPath.addPath(trianglePath, Offset.zero);

    // Desenhar o balão e a seta
    canvas.drawShadow(balloonPath, Colors.black, 6, false);
    canvas.drawPath(balloonPath, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}

class Callout extends StatelessWidget {
  final Widget child;
  final double triangleSize;
  final double triangleHeight;
  final String position;
  final Color backgroundColor;
  final bool isLeft;

  Callout({
    required this.child,
    this.triangleSize = 20,
    this.triangleHeight = 10,
    this.position = "left",
    this.backgroundColor = Colors.white,
    this.isLeft = true,
  });

  @override
  Widget build(BuildContext context) {
    return CustomPaint(
      painter: CalloutPainter(
        triangleSize: triangleSize,
        triangleHeight: triangleHeight,
        position: position,
        backgroundColor: backgroundColor,
        isLeft: isLeft,
      ),
      child: Padding(
        padding: EdgeInsets.all(16.0),
        child: child,
      ),
    );
  }
}