| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676 |
- import 'dart:convert';
- import 'dart:io';
- import 'dart:isolate';
- import 'dart:ui';
- import 'package:flutter/material.dart';
- import 'package:flutter_downloader/flutter_downloader.dart';
- import 'package:fluttertoast/fluttertoast.dart';
- import 'package:google_fonts/google_fonts.dart';
- import 'package:localstore/localstore.dart';
- import 'package:path_provider/path_provider.dart';
- import '../providers/proyectos_provider.dart';
- import '../widgets/encabezado_pais.dart';
- import 'package:http/http.dart' as http;
- import 'calculadora_estacionamiento.dart';
- import 'interfaz_cuadricula_page.dart';
- class VentilacionEstacionamientosPage extends StatefulWidget {
- const VentilacionEstacionamientosPage({Key? key}) : super(key: key);
- @override
- State<VentilacionEstacionamientosPage> createState() => _VentilacionEstacionamientosPageState();
- }
- class _VentilacionEstacionamientosPageState extends State<VentilacionEstacionamientosPage> {
- final db = Localstore.instance;
- final _proyectosProvider = ProyectosProvider();
- final List<Map<String, String?>> _projects = [];
- final Map<String, String> _estatusCodigos = {
- "C" : "Cálculo de caudal y equipos",
- "F" : "Finalizado"
- };
- String _idUsuario = "";
- String _token = "";
- String _pais = "";
- String _code = "";
- String _estado = "";
- String _ciudad = "";
- bool _isLoading = true;
- double _fontSize = 16.0;
- final ReceivePort _port = ReceivePort();
- List<TaskInfo>? _tasks;
- late String _localPath;
- @override
- void initState() {
- super.initState();
- _bindBackgroundIsolate();
- _prepareSaveDir();
- FlutterDownloader.registerCallback(downloadCallback);
- _fetchProjects().then((value) => {
- if(mounted){
- setState(() => _isLoading = false)
- }
- });
- }
- @override
- void dispose(){
- _unbindBackgroundIsolate();
- super.dispose();
- }
- Future<void> _fetchProjects() async{
- final items = await db.collection('login').get();
- final lastID = items?.keys.last;
- final data = items?[lastID];
- _pais = data['pais'];
- _idUsuario = data['idUsuario'];
- _token = data['token'];
- _estado = data['estado'];
- _ciudad = data['municipio'];
- final paisArr = data['pais'].split(" ");
- _code = paisArr.last.replaceAll("(", "").replaceAll(")", "");
- final proyectos = await _proyectosProvider.fetchProyectos(_idUsuario, "estacionamientos", _token);
- proyectos.result.forEach((element) {
- final timestamp = int.parse(element.fmodificacion);
- final date = DateTime.fromMillisecondsSinceEpoch(timestamp * 1000);
- final proyecto = {
- "idProyecto": element.id,
- "nombreProyecto": element.nombre,
- "estatus" : element.estatus,
- "ulModificacion" : date.toString(),
- "datos": element.datos,
- "archpdf": element.archpdf
- };
- _projects.add(proyecto);
- });
- }
- void _bindBackgroundIsolate(){
- bool isSuccess = IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port');
- if(!isSuccess){
- _unbindBackgroundIsolate();
- _bindBackgroundIsolate();
- return;
- }
- _port.listen((data) {
- print('UI Isolate Callback: $data');
- String? id = data[0];
- DownloadTaskStatus? status = data [1];
- int? progress = data[2];
- if(_tasks != null && _tasks!.isNotEmpty){
- final task = _tasks!.firstWhere((task) => task.taskId == id);
- setState(() {
- task.status = status;
- task.progress = progress;
- });
- }
- });
- }
- void _unbindBackgroundIsolate() {
- IsolateNameServer.removePortNameMapping('downloader_send_port');
- }
- void _requestDownload(TaskInfo task) async{
- task.taskId = await FlutterDownloader.enqueue(
- url: task.link!,
- savedDir: _localPath,
- showNotification: true,
- openFileFromNotification: true,
- saveInPublicStorage: true,
- );
- }
- Future<void> _prepareSaveDir() async {
- _localPath = (await _findLocalPath())!;
- final savedDir = Directory(_localPath);
- bool hasExisted = await savedDir.exists();
- if (!hasExisted) {
- savedDir.create();
- }
- }
- Future<String?> _findLocalPath() async{
- String externalStorageDirPath;
- if(Platform.isAndroid){
- final directory = await getExternalStorageDirectory();
- externalStorageDirPath = directory!.path;
- }else{
- final directory = await getApplicationDocumentsDirectory();
- externalStorageDirPath = directory.path;
- }
- return externalStorageDirPath;
- }
- static void downloadCallback(String id, DownloadTaskStatus status, int progress){
- print("Task $id: status: $status, progress: $progress");
- final SendPort send = IsolateNameServer.lookupPortByName('downloader_send_port')!;
- send.send([id, status, progress]);
- }
- @override
- Widget build(BuildContext context) {
- final _screenSize = MediaQuery.of(context).size;
- if(_screenSize.width <= 360){
- _fontSize = 14.0;
- }else if(_screenSize.width > 360 && _screenSize.width <= 400){
- _fontSize = 16.0;
- }else{
- _fontSize = 18.0;
- }
- return Scaffold(
- body: _isLoading ? const Center(
- child: CircularProgressIndicator(),
- ) : LayoutBuilder(
- builder: (context, constraints) {
- return SafeArea(
- child: SingleChildScrollView(
- child: Column(
- children: [
- const SizedBox(height: 8.0),
- Container(
- margin: const EdgeInsets.symmetric(horizontal: 32.0),
- child: Row(
- children: [
- TextButton(
- child: Text(
- "Portal de memorias de cálculo >",
- style: GoogleFonts.roboto(
- fontSize: 16.0,
- fontWeight: FontWeight.bold,
- fontStyle: FontStyle.italic,
- ),
- ),
- onPressed: () => Navigator.pop(context),
- style: TextButton.styleFrom(
- padding: const EdgeInsets.fromLTRB(0.0, 0.0, 8.0, 0.0),
- minimumSize: const Size(0.0, 0.0),
- tapTargetSize: MaterialTapTargetSize.shrinkWrap,
- ),
- ),
- const SizedBox(width: 8.0),
- Expanded(
- child: Container(
- padding: const EdgeInsets.fromLTRB(0.0, 0.0, 8.0, 0.0),
- child: Text(
- "Memoria de cálculo de ventilación de estacionamientos",
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- style: GoogleFonts.roboto(
- fontSize: 16.0,
- color: Colors.black54,
- fontWeight: FontWeight.bold,
- fontStyle: FontStyle.italic,
- ),
- ),
- ),
- )
- ],
- ),
- ),
- const SizedBox(height: 8.0),
- EncabezadoPais(paisCode: _code, paisName: _pais),
- const SizedBox(height: 32.0),
- Image.asset(
- "assets/estacionamientos.png",
- width: 88.0,
- ),
- const SizedBox(height: 16.0),
- Container(
- width: double.infinity,
- padding: const EdgeInsets.symmetric(horizontal: 32.0),
- child: const Text(
- "MEMORIA DE CÁLCULO VENTILACIÓN ESTACIONAMIENTOS",
- textAlign: TextAlign.center,
- style: TextStyle(
- fontFamily: "Helvetica Neue Black Cond",
- fontSize: 28.0,
- ),
- ),
- ),
- const SizedBox(height: 16.0),
- Container(
- margin: const EdgeInsets.symmetric(horizontal: 32.0),
- child: Text(
- "NUEVO PROYECTO",
- textAlign: TextAlign.center,
- style: GoogleFonts.robotoSlab(
- fontWeight: FontWeight.bold,
- fontSize: 18.0,
- ),
- ),
- ),
- const SizedBox(height: 16.0),
- Container(
- width: double.infinity,
- margin: const EdgeInsets.symmetric(
- horizontal: 32.0,
- ),
- padding: const EdgeInsets.all(32.0),
- color: const Color(0x0F000000),
- child: Row(
- children: [
- Expanded(
- child: ElevatedButton(
- style: ElevatedButton.styleFrom(
- primary: Colors.white,
- onPrimary: const Color.fromRGBO(180, 4, 4, 0.25),
- padding: const EdgeInsets.all(16.0),
- ),
- child: Column(
- children: [
- Image.asset(
- "assets/nuevo2.png",
- width: 64.0,
- ),
- const SizedBox(height: 8.0),
- Text(
- "Crear nuevo proyecto",
- style: GoogleFonts.roboto(
- fontWeight: FontWeight.bold,
- fontSize: 16.0,
- color: const Color(0xFFB40404),
- ),
- ),
- ],
- ),
- onPressed: () async{
- final controller = TextEditingController();
- final shouldCreate = await showDialog(
- context: context,
- barrierDismissible: false,
- builder: (context) => AlertDialog(
- title: Text(
- "Nombre del proyecto",
- textAlign: TextAlign.center,
- style: GoogleFonts.roboto(
- fontWeight: FontWeight.bold,
- ),
- ),
- content: TextField(
- controller: controller,
- decoration: InputDecoration(
- hintStyle: GoogleFonts.roboto(
- color: Colors.grey,
- fontStyle: FontStyle.italic,
- ),
- hintText: "Ingresa el nombre del proyecto",
- ),
- style: GoogleFonts.roboto(),
- maxLines: 1,
- maxLength: 100,
- onSubmitted: (val){
- if(val.isNotEmpty){
- Navigator.pop(context, true);
- }
- },
- ),
- actions: [
- TextButton(
- child: const Text("Cancelar"),
- onPressed: () => Navigator.pop(context, false),
- ),
- TextButton(
- child: const Text("Aceptar"),
- onPressed: (){
- if(controller.text.isNotEmpty){
- Navigator.pop(context, true);
- }else{
- Fluttertoast.showToast(
- msg: "EL nombre del proyecto no debe estar vacío",
- toastLength: Toast.LENGTH_SHORT,
- timeInSecForIosWeb: 3,
- gravity: ToastGravity.CENTER,
- webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
- );
- }
- },
- )
- ],
- ),
- );
- if(shouldCreate){
- final url = Uri.https("smart.solerpalau.mx", "PR/api/v1/quiosco/matrizMemoriasCalculo/nuevoProyectoVentilacion");
- final res = await http.post(url,
- headers: {
- "Authorization": "Bearer $_token"
- },
- body: {
- "NOMBREPROYECTO": controller.text,
- "MEMORIA": "estacionamientos",
- "FCREACION": DateTime.now().toIso8601String().substring(0, 19),
- "FMODIF": DateTime.now().toIso8601String().substring(0, 19),
- "IDUSUARIO": _idUsuario,
- "ESTATUS": "C",
- },
- );
- final decoded = jsonDecode(res.body);
- if(!decoded['response']){
- Fluttertoast.showToast(
- msg: decoded['message'],
- toastLength: Toast.LENGTH_SHORT,
- timeInSecForIosWeb: 3,
- gravity: ToastGravity.CENTER,
- webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
- );
- }else{
- String idProyecto = decoded['result']['idProyecto'];
- await Navigator.push(context, MaterialPageRoute(
- builder: (context) => CalculadoraEstacionamientoPage(
- ciudad: _ciudad,
- estado: _estado,
- pais: _pais,
- code: _code,
- idProyecto: idProyecto,
- idUsuario: _idUsuario,
- token: _token,
- datos: "",
- noProyecto: controller.text,
- archpdf: "",
- ),
- ));
- setState(() => _isLoading = true);
- _projects.clear();
- await _fetchProjects();
- setState(() => _isLoading = false);
- }
- }
- },
- ),
- flex: 1,
- ),
- ],
- ),
- ),
- const SizedBox(height: 16.0),
- Container(
- margin: const EdgeInsets.symmetric(horizontal: 32.0),
- child: Text(
- "HISTORIAL DE PROYECTOS",
- textAlign: TextAlign.center,
- style: GoogleFonts.robotoSlab(
- fontWeight: FontWeight.bold,
- fontSize: 18.0,
- ),
- ),
- ),
- const SizedBox(height: 16.0),
- if(_projects.isEmpty)
- Container(
- width: double.infinity,
- margin: const EdgeInsets.symmetric(horizontal: 32.0),
- child: Text(
- "Aún no has creado ningún proyecto.",
- style: GoogleFonts.roboto(
- fontWeight: FontWeight.bold,
- fontSize: 18.0,
- ),
- ),
- ),
- if(_projects.isNotEmpty)
- Container(
- height: 256.0,
- width: double.infinity,
- margin: const EdgeInsets.symmetric(horizontal: 32.0),
- child: Column(
- children: [
- Container(
- child: Row(
- children: [
- Expanded(
- child: Text(
- "Nombre",
- style: GoogleFonts.roboto(
- fontWeight: FontWeight.bold,
- fontSize: _fontSize + 2,
- ),
- ),
- flex: 5,
- ),
- Expanded(
- child: Text(
- "Estatus",
- style: GoogleFonts.roboto(
- fontWeight: FontWeight.bold,
- fontSize: _fontSize + 2,
- ),
- ),
- flex: 5,
- ),
- Expanded(
- child: Text(
- "Última Modificación",
- style: GoogleFonts.roboto(
- fontSize: _fontSize + 2,
- fontWeight: FontWeight.bold,
- ),
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- ),
- flex: 3,
- ),
- Expanded(
- child: Container(),
- flex: 1,
- ),
- ],
- ),
- padding: const EdgeInsets.only(right: 16.0),
- decoration: const BoxDecoration(
- border: Border(
- bottom: BorderSide(
- color: Colors.black54,
- width: 2.0,
- ),
- ),
- ),
- ),
- Expanded(
- child: ListView.separated(
- itemCount: _projects.length,
- itemBuilder: (context, index){
- return ListTile(
- title: Row(
- children: [
- Expanded(
- child: Text(
- _projects[index]["nombreProyecto"]!,
- style: GoogleFonts.roboto(
- fontSize: _fontSize,
- ),
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- ),
- flex: 5,
- ),
- Expanded(
- child: Text(
- _estatusCodigos[_projects[index]["estatus"]!]!,
- style: GoogleFonts.roboto(
- fontSize: _fontSize,
- ),
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- ),
- flex: 5,
- ),
- Expanded(
- child: Text(
- _buildDate(_projects[index]["ulModificacion"]!),
- style: GoogleFonts.roboto(
- fontSize: _fontSize,
- ),
- maxLines: 1,
- overflow: TextOverflow.ellipsis,
- ),
- flex: 3,
- ),
- Expanded(
- child: PopupMenuButton<String>(
- onSelected: (val) async{
- const auth = "smart.solerpalau.mx";
- if(val == "Eliminar"){
- final url = Uri.https(auth, "PR/api/v1/quiosco/matrizMemoriasCalculo/borrarProyectos");
- final res = await http.post(url,
- headers: {
- "Authorization": "Bearer $_token",
- },
- body: {
- "IDUSUARIO": _idUsuario,
- "IDPROYECTO": _projects[index]["idProyecto"],
- },
- );
- final decoded = jsonDecode(res.body);
- if(!decoded['response']){
- Fluttertoast.showToast(
- msg: decoded['message'],
- toastLength: Toast.LENGTH_SHORT,
- timeInSecForIosWeb: 4,
- gravity: ToastGravity.CENTER,
- webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
- );
- }else{
- Fluttertoast.showToast(
- msg: decoded['message'],
- toastLength: Toast.LENGTH_SHORT,
- timeInSecForIosWeb: 4,
- gravity: ToastGravity.CENTER,
- webBgColor: "linear-gradient(to right, #266B1F, #98F58F)",
- );
- setState(() => _isLoading = true);
- _projects.clear();
- await _fetchProjects();
- setState(() => _isLoading = false);
- }
- }else if(val == "Descargar PDF"){
- Fluttertoast.showToast(
- msg: "Descargando archivo...",
- toastLength: Toast.LENGTH_SHORT,
- );
- final task = TaskInfo(name: _projects[index]["nombreProyecto"]!, link: _projects[index]["archpdf"]!);
- _requestDownload(task);
- }
- },
- itemBuilder: (context) => ["Eliminar", if(_projects[index]["archpdf"]!.isNotEmpty)"Descargar PDF"].map((e) => PopupMenuItem(
- value: e,
- child: Row(
- children: [
- Text(
- e,
- style: GoogleFonts.roboto(
- fontSize: 16.0,
- color: Colors.black54,
- ),
- ),
- const SizedBox(width: 8.0),
- Icon(
- e == "Eliminar" ? Icons.delete : Icons.file_download,
- color: Colors.black54,
- )
- ],
- ),
- )).toList(),
- ),
- flex: 1,
- ),
- ],
- ),
- onTap: () async{
- await Navigator.push(context, MaterialPageRoute(
- builder: (context) => CalculadoraEstacionamientoPage(
- ciudad: _ciudad,
- estado: _estado,
- pais: _pais,
- code: _code,
- idProyecto: _projects[index]["idProyecto"]!,
- idUsuario: _idUsuario,
- token: _token,
- datos: _projects[index]["datos"]!,
- noProyecto: _projects[index]["nombreProyecto"]!,
- archpdf: "",
- ),
- ));
- setState(() => _isLoading = true);
- _projects.clear();
- await _fetchProjects();
- setState(() => _isLoading = false);
- },
- contentPadding: EdgeInsets.zero,
- );
- },
- separatorBuilder: (context, index){
- return const Divider();
- },
- ),
- )
- ],
- ),
- ),
- const SizedBox(height: 32.0),
- ],
- ),
- ),
- );
- },
- ),
- );
- }
- String _buildDate(String date){
- final parsed = DateTime.parse(date);
- final now = DateTime.now();
- final diff = now.difference(parsed).inDays;
- if(diff == 0){
- return "Hoy";
- }else if(diff == 1){
- return "Ayer";
- }else if(diff >= 2 && diff < 31){
- return "Hace $diff días";
- }else if(diff >= 31 && diff <= 359){
- final diffMes = diff~/30;
- return "Hace $diffMes mes(es)";
- }else if(diff > 359){
- final diffAnio = diff~/359;
- return "Hace $diffAnio año(s)";
- }else{
- return "Hace mucho tiempo";
- }
- }
- }
|