mapa con marcador añadido beta
This commit is contained in:
293
assets/referencia/nethive_tablas_actualizado.md
Normal file
293
assets/referencia/nethive_tablas_actualizado.md
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
|
||||||
|
# 📘 Estructura de Base de Datos — NETHIVE (Esquema: `nethive`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏢 `empresa`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato | Descripción |
|
||||||
|
|-----------------|----------------|-----------------------------------|
|
||||||
|
| id | UUID | PRIMARY KEY |
|
||||||
|
| nombre | TEXT | Nombre de la empresa |
|
||||||
|
| rfc | TEXT | Registro fiscal |
|
||||||
|
| direccion | TEXT | Dirección |
|
||||||
|
| telefono | TEXT | Teléfono de contacto |
|
||||||
|
| email | TEXT | Correo electrónico |
|
||||||
|
| fecha_creacion | TIMESTAMP | Fecha de creación (default: now) |
|
||||||
|
| logo_url | TEXT | URL del logo |
|
||||||
|
| imagen_url | TEXT | URL de imagen principal |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏪 `negocio`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato | Descripción |
|
||||||
|
|-----------------|----------------|-----------------------------------|
|
||||||
|
| id | UUID | PRIMARY KEY |
|
||||||
|
| empresa_id | UUID | FK → empresa.id |
|
||||||
|
| nombre | TEXT | Nombre del negocio |
|
||||||
|
| direccion | TEXT | Dirección |
|
||||||
|
| latitud | DECIMAL(9,6) | Latitud geográfica |
|
||||||
|
| longitud | DECIMAL(9,6) | Longitud geográfica |
|
||||||
|
| tipo_local | TEXT | Tipo de local (Sucursal, etc.) |
|
||||||
|
| fecha_creacion | TIMESTAMP | Default: now() |
|
||||||
|
| logo_url | TEXT | Logo del negocio |
|
||||||
|
| imagen_url | TEXT | Imagen del negocio |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧾 `categoria_componente`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato | Descripción |
|
||||||
|
|---------|--------------|--------------------------|
|
||||||
|
| id | SERIAL | PRIMARY KEY |
|
||||||
|
| nombre | TEXT | Nombre único de categoría|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 `componente`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato | Descripción |
|
||||||
|
|-----------------|----------------|------------------------------------|
|
||||||
|
| id | UUID | PRIMARY KEY |
|
||||||
|
| negocio_id | UUID | FK → negocio.id |
|
||||||
|
| categoria_id | INT | FK → categoria_componente.id |
|
||||||
|
| nombre | TEXT | Nombre del componente |
|
||||||
|
| descripcion | TEXT | Descripción general |
|
||||||
|
| en_uso | BOOLEAN | Si está en uso |
|
||||||
|
| activo | BOOLEAN | Si está activo |
|
||||||
|
| ubicacion | TEXT | Ubicación física (rack, bandeja) |
|
||||||
|
| imagen_url | TEXT | URL de imagen |
|
||||||
|
| fecha_registro | TIMESTAMP | Default: now() |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔌 `detalle_cable`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato |
|
||||||
|
|----------------|----------------|
|
||||||
|
| componente_id | UUID (PK, FK) |
|
||||||
|
| tipo_cable | TEXT |
|
||||||
|
| color | TEXT |
|
||||||
|
| tamaño | DECIMAL(5,2) |
|
||||||
|
| tipo_conector | TEXT |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📶 `detalle_switch`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato |
|
||||||
|
|----------------------|----------------|
|
||||||
|
| componente_id | UUID (PK, FK) |
|
||||||
|
| marca | TEXT |
|
||||||
|
| modelo | TEXT |
|
||||||
|
| numero_serie | TEXT |
|
||||||
|
| administrable | BOOLEAN |
|
||||||
|
| poe | BOOLEAN |
|
||||||
|
| cantidad_puertos | INT |
|
||||||
|
| velocidad_puertos | TEXT |
|
||||||
|
| tipo_puertos | TEXT |
|
||||||
|
| ubicacion_en_rack | TEXT |
|
||||||
|
| direccion_ip | TEXT |
|
||||||
|
| firmware | TEXT |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧱 `detalle_patch_panel`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato |
|
||||||
|
|---------------------|----------------|
|
||||||
|
| componente_id | UUID (PK, FK) |
|
||||||
|
| tipo_conector | TEXT |
|
||||||
|
| numero_puertos | INT |
|
||||||
|
| categoria | TEXT |
|
||||||
|
| tipo_montaje | TEXT |
|
||||||
|
| numeracion_frontal | BOOLEAN |
|
||||||
|
| panel_ciego | BOOLEAN |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🗄 `detalle_rack`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato |
|
||||||
|
|------------------------|----------------|
|
||||||
|
| componente_id | UUID (PK, FK) |
|
||||||
|
| tipo | TEXT |
|
||||||
|
| altura_u | INT |
|
||||||
|
| profundidad_cm | INT |
|
||||||
|
| ancho_cm | INT |
|
||||||
|
| ventilacion_integrada | BOOLEAN |
|
||||||
|
| puertas_con_llave | BOOLEAN |
|
||||||
|
| ruedas | BOOLEAN |
|
||||||
|
| color | TEXT |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧰 `detalle_organizador`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato |
|
||||||
|
|--------------|----------------|
|
||||||
|
| componente_id| UUID (PK, FK) |
|
||||||
|
| tipo | TEXT |
|
||||||
|
| material | TEXT |
|
||||||
|
| tamaño | TEXT |
|
||||||
|
| color | TEXT |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚡ `detalle_ups`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato |
|
||||||
|
|--------------------|----------------|
|
||||||
|
| componente_id | UUID (PK, FK) |
|
||||||
|
| tipo | TEXT |
|
||||||
|
| marca | TEXT |
|
||||||
|
| modelo | TEXT |
|
||||||
|
| voltaje_entrada | TEXT |
|
||||||
|
| voltaje_salida | TEXT |
|
||||||
|
| capacidad_va | INT |
|
||||||
|
| autonomia_minutos | INT |
|
||||||
|
| cantidad_tomas | INT |
|
||||||
|
| rackeable | BOOLEAN |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔐 `detalle_router_firewall`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato |
|
||||||
|
|--------------------------|----------------|
|
||||||
|
| componente_id | UUID (PK, FK) |
|
||||||
|
| tipo | TEXT |
|
||||||
|
| marca | TEXT |
|
||||||
|
| modelo | TEXT |
|
||||||
|
| numero_serie | TEXT |
|
||||||
|
| interfaces | TEXT |
|
||||||
|
| capacidad_routing_gbps | DECIMAL(5,2) |
|
||||||
|
| direccion_ip | TEXT |
|
||||||
|
| firmware | TEXT |
|
||||||
|
| licencias | TEXT |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧿 `detalle_equipo_activo`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato |
|
||||||
|
|-------------------|----------------|
|
||||||
|
| componente_id | UUID (PK, FK) |
|
||||||
|
| tipo | TEXT |
|
||||||
|
| marca | TEXT |
|
||||||
|
| modelo | TEXT |
|
||||||
|
| numero_serie | TEXT |
|
||||||
|
| especificaciones | TEXT |
|
||||||
|
| direccion_ip | TEXT |
|
||||||
|
| firmware | TEXT |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧭 `distribucion`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato | Descripción |
|
||||||
|
|--------------|----------------|--------------------------------------|
|
||||||
|
| id | UUID | PRIMARY KEY |
|
||||||
|
| negocio_id | UUID | FK → negocio.id |
|
||||||
|
| tipo | TEXT | 'MDF' o 'IDF' |
|
||||||
|
| nombre | TEXT | Nombre de la ubicación lógica |
|
||||||
|
| descripcion | TEXT | Detalles adicionales (opcional) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 `conexion_componente`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato | Descripción |
|
||||||
|
|-----------------------|----------------|------------------------------------------|
|
||||||
|
| id | UUID | PRIMARY KEY |
|
||||||
|
| componente_origen_id | UUID | FK → componente.id |
|
||||||
|
| componente_destino_id | UUID | FK → componente.id |
|
||||||
|
| descripcion | TEXT | Descripción de la conexión (opcional) |
|
||||||
|
| activo | BOOLEAN | Si la conexión está activa |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 👁️ `vista_negocios_con_coordenadas`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato | Descripción |
|
||||||
|
|--------------------|--------------|--------------------------------------------|
|
||||||
|
| negocio_id | UUID | ID del negocio |
|
||||||
|
| nombre_negocio | TEXT | Nombre del negocio |
|
||||||
|
| latitud | DECIMAL | Latitud del negocio |
|
||||||
|
| longitud | DECIMAL | Longitud del negocio |
|
||||||
|
| logo_negocio | TEXT | URL del logo del negocio |
|
||||||
|
| imagen_negocio | TEXT | URL de la imagen del negocio |
|
||||||
|
| empresa_id | UUID | ID de la empresa |
|
||||||
|
| nombre_empresa | TEXT | Nombre de la empresa |
|
||||||
|
| logo_empresa | TEXT | URL del logo de la empresa |
|
||||||
|
| imagen_empresa | TEXT | URL de la imagen de la empresa |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 `vista_inventario_por_negocio`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato | Descripción |
|
||||||
|
|--------------------|--------------|---------------------------------------------|
|
||||||
|
| componente_id | UUID | ID del componente |
|
||||||
|
| nombre_componente | TEXT | Nombre del componente |
|
||||||
|
| categoria | TEXT | Categoría del componente |
|
||||||
|
| en_uso | BOOLEAN | Si está en uso |
|
||||||
|
| activo | BOOLEAN | Si está activo |
|
||||||
|
| ubicacion | TEXT | Ubicación física del componente |
|
||||||
|
| imagen_componente | TEXT | Imagen asociada al componente |
|
||||||
|
| negocio_id | UUID | ID del negocio |
|
||||||
|
| nombre_negocio | TEXT | Nombre del negocio |
|
||||||
|
| logo_negocio | TEXT | Logo del negocio |
|
||||||
|
| imagen_negocio | TEXT | Imagen del negocio |
|
||||||
|
| empresa_id | UUID | ID de la empresa |
|
||||||
|
| nombre_empresa | TEXT | Nombre de la empresa |
|
||||||
|
| logo_empresa | TEXT | Logo de la empresa |
|
||||||
|
| imagen_empresa | TEXT | Imagen de la empresa |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧵 `vista_detalle_cables`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato | Descripción |
|
||||||
|
|--------------------|--------------|--------------------------------------------|
|
||||||
|
| componente_id | UUID | ID del componente |
|
||||||
|
| nombre | TEXT | Nombre del cable |
|
||||||
|
| tipo_cable | TEXT | Tipo de cable (UTP, fibra, etc.) |
|
||||||
|
| color | TEXT | Color del cable |
|
||||||
|
| tamaño | DECIMAL | Longitud del cable |
|
||||||
|
| tipo_conector | TEXT | Tipo de conector (RJ45, LC, etc.) |
|
||||||
|
| en_uso | BOOLEAN | Si está en uso |
|
||||||
|
| activo | BOOLEAN | Si está activo |
|
||||||
|
| ubicacion | TEXT | Ubicación física |
|
||||||
|
| imagen_componente | TEXT | Imagen del cable |
|
||||||
|
| nombre_negocio | TEXT | Nombre del negocio |
|
||||||
|
| logo_negocio | TEXT | Logo del negocio |
|
||||||
|
| nombre_empresa | TEXT | Nombre de la empresa |
|
||||||
|
| logo_empresa | TEXT | Logo de la empresa |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 `vista_resumen_componentes_activos`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato | Descripción |
|
||||||
|
|------------------|--------------|----------------------------------------------|
|
||||||
|
| nombre_empresa | TEXT | Nombre de la empresa |
|
||||||
|
| nombre_negocio | TEXT | Nombre del negocio |
|
||||||
|
| categoria | TEXT | Categoría del componente |
|
||||||
|
| cantidad_activos | INTEGER | Cantidad total de componentes activos |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔌 `vista_conexiones_por_negocio`
|
||||||
|
|
||||||
|
| Columna | Tipo de dato | Descripción |
|
||||||
|
|-----------------------|--------------|------------------------------------------|
|
||||||
|
| id | UUID | ID de la conexión |
|
||||||
|
| componente_origen_id | UUID | Componente origen |
|
||||||
|
| componente_destino_id | UUID | Componente destino |
|
||||||
|
| descripcion | TEXT | Descripción de la conexión |
|
||||||
|
| activo | BOOLEAN | Si la conexión está activa |
|
||||||
|
"""
|
||||||
@@ -5,8 +5,8 @@ import 'package:nethive_neo/pages/empresa_negocios/widgets/empresa_selector_side
|
|||||||
import 'package:nethive_neo/pages/empresa_negocios/widgets/negocios_table.dart';
|
import 'package:nethive_neo/pages/empresa_negocios/widgets/negocios_table.dart';
|
||||||
import 'package:nethive_neo/pages/empresa_negocios/widgets/negocios_cards_view.dart';
|
import 'package:nethive_neo/pages/empresa_negocios/widgets/negocios_cards_view.dart';
|
||||||
import 'package:nethive_neo/pages/empresa_negocios/widgets/mobile_empresa_selector.dart';
|
import 'package:nethive_neo/pages/empresa_negocios/widgets/mobile_empresa_selector.dart';
|
||||||
|
import 'package:nethive_neo/pages/empresa_negocios/widgets/negocios_map_view.dart';
|
||||||
import 'package:nethive_neo/theme/theme.dart';
|
import 'package:nethive_neo/theme/theme.dart';
|
||||||
import 'package:nethive_neo/helpers/globals.dart';
|
|
||||||
|
|
||||||
class EmpresaNegociosPage extends StatefulWidget {
|
class EmpresaNegociosPage extends StatefulWidget {
|
||||||
const EmpresaNegociosPage({Key? key}) : super(key: key);
|
const EmpresaNegociosPage({Key? key}) : super(key: key);
|
||||||
@@ -55,7 +55,6 @@ class _EmpresaNegociosPageState extends State<EmpresaNegociosPage>
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isLargeScreen = MediaQuery.of(context).size.width > 1200;
|
final isLargeScreen = MediaQuery.of(context).size.width > 1200;
|
||||||
final isMediumScreen = MediaQuery.of(context).size.width > 800;
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: AppTheme.of(context).primaryBackground,
|
backgroundColor: AppTheme.of(context).primaryBackground,
|
||||||
@@ -589,85 +588,10 @@ class _EmpresaNegociosPageState extends State<EmpresaNegociosPage>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildMapView() {
|
Widget _buildMapView() {
|
||||||
return Container(
|
return Consumer<EmpresasNegociosProvider>(
|
||||||
decoration: BoxDecoration(
|
builder: (context, provider, child) {
|
||||||
gradient: LinearGradient(
|
return NegociosMapView(provider: provider);
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
colors: [
|
|
||||||
Colors.blue.withOpacity(0.1),
|
|
||||||
Colors.blue.withOpacity(0.3),
|
|
||||||
AppTheme.of(context).primaryColor.withOpacity(0.2),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
border: Border.all(
|
|
||||||
color: AppTheme.of(context).primaryColor,
|
|
||||||
width: 2,
|
|
||||||
),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: AppTheme.of(context).primaryColor.withOpacity(0.2),
|
|
||||||
blurRadius: 20,
|
|
||||||
offset: const Offset(0, 10),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: Center(
|
|
||||||
child: TweenAnimationBuilder<double>(
|
|
||||||
duration: const Duration(milliseconds: 1500),
|
|
||||||
tween: Tween(begin: 0.0, end: 1.0),
|
|
||||||
builder: (context, value, child) {
|
|
||||||
return Transform.scale(
|
|
||||||
scale: 0.8 + (0.2 * value),
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.all(20),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
gradient: AppTheme.of(context).modernGradient,
|
|
||||||
borderRadius: BorderRadius.circular(20),
|
|
||||||
),
|
|
||||||
child: Icon(
|
|
||||||
Icons.map,
|
|
||||||
size: 80,
|
|
||||||
color: Colors.white,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 24),
|
|
||||||
Text(
|
|
||||||
'Vista de Mapa',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppTheme.of(context).primaryColor,
|
|
||||||
fontSize: 28,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
letterSpacing: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 12),
|
|
||||||
Container(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Colors.white.withOpacity(0.9),
|
|
||||||
borderRadius: BorderRadius.circular(15),
|
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
'Próximamente se implementará el mapa interactivo\ncon las ubicaciones de todas las sucursales',
|
|
||||||
style: TextStyle(
|
|
||||||
color: AppTheme.of(context).primaryColor,
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: FontWeight.w500,
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
685
lib/pages/empresa_negocios/widgets/negocios_map_view.dart
Normal file
685
lib/pages/empresa_negocios/widgets/negocios_map_view.dart
Normal file
@@ -0,0 +1,685 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
|
import 'package:latlong2/latlong.dart';
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:nethive_neo/providers/nethive/empresas_negocios_provider.dart';
|
||||||
|
import 'package:nethive_neo/theme/theme.dart';
|
||||||
|
|
||||||
|
class NegociosMapView extends StatefulWidget {
|
||||||
|
final EmpresasNegociosProvider provider;
|
||||||
|
|
||||||
|
const NegociosMapView({
|
||||||
|
Key? key,
|
||||||
|
required this.provider,
|
||||||
|
}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<NegociosMapView> createState() => _NegociosMapViewState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _NegociosMapViewState extends State<NegociosMapView>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
|
final MapController _mapController = MapController();
|
||||||
|
late AnimationController _markerAnimationController;
|
||||||
|
late AnimationController _tooltipAnimationController;
|
||||||
|
late Animation<double> _markerAnimation;
|
||||||
|
late Animation<double> _tooltipAnimation;
|
||||||
|
late Animation<Offset> _tooltipSlideAnimation;
|
||||||
|
|
||||||
|
String? _hoveredNegocioId;
|
||||||
|
Offset? _tooltipPosition;
|
||||||
|
bool _showTooltip = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_markerAnimationController = AnimationController(
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
vsync: this,
|
||||||
|
);
|
||||||
|
_tooltipAnimationController = AnimationController(
|
||||||
|
duration: const Duration(milliseconds: 200),
|
||||||
|
vsync: this,
|
||||||
|
);
|
||||||
|
|
||||||
|
_markerAnimation = Tween<double>(
|
||||||
|
begin: 1.0,
|
||||||
|
end: 1.4,
|
||||||
|
).animate(CurvedAnimation(
|
||||||
|
parent: _markerAnimationController,
|
||||||
|
curve: Curves.easeOutBack,
|
||||||
|
));
|
||||||
|
|
||||||
|
_tooltipAnimation = Tween<double>(
|
||||||
|
begin: 0.0,
|
||||||
|
end: 1.0,
|
||||||
|
).animate(CurvedAnimation(
|
||||||
|
parent: _tooltipAnimationController,
|
||||||
|
curve: Curves.easeOutCubic,
|
||||||
|
));
|
||||||
|
|
||||||
|
_tooltipSlideAnimation = Tween<Offset>(
|
||||||
|
begin: const Offset(0, 0.5),
|
||||||
|
end: Offset.zero,
|
||||||
|
).animate(CurvedAnimation(
|
||||||
|
parent: _tooltipAnimationController,
|
||||||
|
curve: Curves.easeOutCubic,
|
||||||
|
));
|
||||||
|
|
||||||
|
// Centrar el mapa después de que se construya
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_centerMapOnNegocios();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_markerAnimationController.dispose();
|
||||||
|
_tooltipAnimationController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _showTooltipForNegocio(String negocioId, Offset position) {
|
||||||
|
setState(() {
|
||||||
|
_hoveredNegocioId = negocioId;
|
||||||
|
_tooltipPosition = Offset(
|
||||||
|
position.dx + 20, // Offset del cursor para evitar interferencia
|
||||||
|
position.dy - 80, // Arriba del cursor
|
||||||
|
);
|
||||||
|
_showTooltip = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
_markerAnimationController.forward();
|
||||||
|
_tooltipAnimationController.forward();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _hideTooltip() {
|
||||||
|
_tooltipAnimationController.reverse().then((_) {
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {
|
||||||
|
_hoveredNegocioId = null;
|
||||||
|
_showTooltip = false;
|
||||||
|
_tooltipPosition = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_markerAnimationController.reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _centerMapOnNegocios() {
|
||||||
|
if (widget.provider.negocios.isNotEmpty) {
|
||||||
|
final bounds = _calculateBounds();
|
||||||
|
_mapController.fitCamera(
|
||||||
|
CameraFit.bounds(
|
||||||
|
bounds: bounds,
|
||||||
|
padding: const EdgeInsets.all(50),
|
||||||
|
maxZoom: 15,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LatLngBounds _calculateBounds() {
|
||||||
|
if (widget.provider.negocios.isEmpty) {
|
||||||
|
return LatLngBounds(
|
||||||
|
const LatLng(-90, -180),
|
||||||
|
const LatLng(90, 180),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
double minLat = widget.provider.negocios.first.latitud;
|
||||||
|
double maxLat = widget.provider.negocios.first.latitud;
|
||||||
|
double minLng = widget.provider.negocios.first.longitud;
|
||||||
|
double maxLng = widget.provider.negocios.first.longitud;
|
||||||
|
|
||||||
|
for (final negocio in widget.provider.negocios) {
|
||||||
|
minLat = minLat < negocio.latitud ? minLat : negocio.latitud;
|
||||||
|
maxLat = maxLat > negocio.latitud ? maxLat : negocio.latitud;
|
||||||
|
minLng = minLng < negocio.longitud ? minLng : negocio.longitud;
|
||||||
|
maxLng = maxLng > negocio.longitud ? maxLng : negocio.longitud;
|
||||||
|
}
|
||||||
|
|
||||||
|
return LatLngBounds(
|
||||||
|
LatLng(minLat, minLng),
|
||||||
|
LatLng(maxLat, maxLng),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (widget.provider.negocios.isEmpty) {
|
||||||
|
return _buildEmptyMapState();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.1),
|
||||||
|
blurRadius: 15,
|
||||||
|
offset: const Offset(0, 5),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
// Listener para detectar movimientos del mouse sobre el mapa
|
||||||
|
MouseRegion(
|
||||||
|
onExit: (_) => _hideTooltip(),
|
||||||
|
child: FlutterMap(
|
||||||
|
mapController: _mapController,
|
||||||
|
options: MapOptions(
|
||||||
|
initialCenter: const LatLng(19.4326, -99.1332),
|
||||||
|
initialZoom: 10,
|
||||||
|
minZoom: 3,
|
||||||
|
maxZoom: 18,
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
// Capa de tiles del mapa
|
||||||
|
TileLayer(
|
||||||
|
urlTemplate:
|
||||||
|
'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
|
||||||
|
userAgentPackageName: 'com.nethive.app',
|
||||||
|
),
|
||||||
|
|
||||||
|
// Capa de marcadores
|
||||||
|
MarkerLayer(
|
||||||
|
markers: _buildMarkers(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Header del mapa con información
|
||||||
|
Positioned(
|
||||||
|
top: 20,
|
||||||
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
child: _buildMapHeader(),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Controles del mapa
|
||||||
|
Positioned(
|
||||||
|
bottom: 20,
|
||||||
|
right: 20,
|
||||||
|
child: _buildMapControls(),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Tooltip flotante con información del negocio
|
||||||
|
if (_showTooltip && _tooltipPosition != null)
|
||||||
|
Positioned(
|
||||||
|
left: _tooltipPosition!.dx
|
||||||
|
.clamp(20.0, MediaQuery.of(context).size.width - 280),
|
||||||
|
top: _tooltipPosition!.dy
|
||||||
|
.clamp(20.0, MediaQuery.of(context).size.height - 150),
|
||||||
|
child: _buildAnimatedTooltip(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Marker> _buildMarkers() {
|
||||||
|
return widget.provider.negocios.map((negocio) {
|
||||||
|
final isHovered = _hoveredNegocioId == negocio.id;
|
||||||
|
|
||||||
|
return Marker(
|
||||||
|
point: LatLng(negocio.latitud, negocio.longitud),
|
||||||
|
width: 50,
|
||||||
|
height: 50,
|
||||||
|
child: MouseRegion(
|
||||||
|
onEnter: (event) {
|
||||||
|
_showTooltipForNegocio(negocio.id, event.position);
|
||||||
|
},
|
||||||
|
onHover: (event) {
|
||||||
|
// Actualizar posición del tooltip sin recalcular todo
|
||||||
|
if (_hoveredNegocioId == negocio.id) {
|
||||||
|
setState(() {
|
||||||
|
_tooltipPosition = Offset(
|
||||||
|
event.position.dx + 20,
|
||||||
|
event.position.dy - 80,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
// Navegar a la infraestructura del negocio
|
||||||
|
context.go('/infrastructure/${negocio.id}');
|
||||||
|
},
|
||||||
|
child: AnimatedBuilder(
|
||||||
|
animation: _markerAnimation,
|
||||||
|
builder: (context, child) {
|
||||||
|
return Transform.scale(
|
||||||
|
scale: isHovered ? _markerAnimation.value : 1.0,
|
||||||
|
child: Container(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
shape: BoxShape.circle,
|
||||||
|
gradient: isHovered
|
||||||
|
? AppTheme.of(context).primaryGradient
|
||||||
|
: AppTheme.of(context).modernGradient,
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: AppTheme.of(context)
|
||||||
|
.primaryColor
|
||||||
|
.withOpacity(0.4),
|
||||||
|
blurRadius: isHovered ? 15 : 8,
|
||||||
|
offset: const Offset(0, 4),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
border: Border.all(
|
||||||
|
color: Colors.white,
|
||||||
|
width: isHovered ? 3 : 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.store,
|
||||||
|
color: Colors.white,
|
||||||
|
size: isHovered ? 22 : 18,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildAnimatedTooltip() {
|
||||||
|
final negocio = widget.provider.negocios.firstWhere(
|
||||||
|
(n) => n.id == _hoveredNegocioId,
|
||||||
|
);
|
||||||
|
|
||||||
|
return SlideTransition(
|
||||||
|
position: _tooltipSlideAnimation,
|
||||||
|
child: FadeTransition(
|
||||||
|
opacity: _tooltipAnimation,
|
||||||
|
child: ScaleTransition(
|
||||||
|
scale: _tooltipAnimation,
|
||||||
|
child: Container(
|
||||||
|
width: 260,
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: AppTheme.of(context).modernGradient,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: AppTheme.of(context).primaryColor.withOpacity(0.3),
|
||||||
|
blurRadius: 20,
|
||||||
|
offset: const Offset(0, 8),
|
||||||
|
),
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.1),
|
||||||
|
blurRadius: 10,
|
||||||
|
offset: const Offset(0, 4),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white.withOpacity(0.2),
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.store,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
negocio.nombre,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.location_on,
|
||||||
|
color: Colors.white.withOpacity(0.8),
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
negocio.direccion,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white.withOpacity(0.9),
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
maxLines: 2,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.business,
|
||||||
|
color: Colors.white.withOpacity(0.8),
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
negocio.tipoLocal,
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white.withOpacity(0.9),
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Container(
|
||||||
|
padding:
|
||||||
|
const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white.withOpacity(0.2),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.touch_app,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 14,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
'Clic para ver infraestructura',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildMapHeader() {
|
||||||
|
return Container(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: AppTheme.of(context).primaryGradient,
|
||||||
|
borderRadius: BorderRadius.circular(15),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: AppTheme.of(context).primaryColor.withOpacity(0.3),
|
||||||
|
blurRadius: 15,
|
||||||
|
offset: const Offset(0, 5),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white.withOpacity(0.2),
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.map,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Mapa de Sucursales',
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'${widget.provider.negocios.length} ubicaciones de ${widget.provider.empresaSeleccionada?.nombre ?? ""}',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white.withOpacity(0.9),
|
||||||
|
fontSize: 14,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white.withOpacity(0.2),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.location_on,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 16,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
'OpenStreetMap',
|
||||||
|
style: TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildMapControls() {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
// Botón de centrar mapa
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: AppTheme.of(context).primaryGradient,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: AppTheme.of(context).primaryColor.withOpacity(0.3),
|
||||||
|
blurRadius: 10,
|
||||||
|
offset: const Offset(0, 3),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: _centerMapOnNegocios,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
child: Icon(
|
||||||
|
Icons.center_focus_strong,
|
||||||
|
color: Colors.white,
|
||||||
|
size: 24,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
|
||||||
|
// Botón de zoom in
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppTheme.of(context).secondaryBackground,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.1),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: const Offset(0, 2),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
_mapController.move(
|
||||||
|
_mapController.camera.center,
|
||||||
|
_mapController.camera.zoom + 1,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
child: Icon(
|
||||||
|
Icons.add,
|
||||||
|
color: AppTheme.of(context).primaryColor,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
|
||||||
|
// Botón de zoom out
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: AppTheme.of(context).secondaryBackground,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.1),
|
||||||
|
blurRadius: 8,
|
||||||
|
offset: const Offset(0, 2),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
onTap: () {
|
||||||
|
_mapController.move(
|
||||||
|
_mapController.camera.center,
|
||||||
|
_mapController.camera.zoom - 1,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
child: Icon(
|
||||||
|
Icons.remove,
|
||||||
|
color: AppTheme.of(context).primaryColor,
|
||||||
|
size: 20,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildEmptyMapState() {
|
||||||
|
return Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
colors: [
|
||||||
|
Colors.blue.withOpacity(0.1),
|
||||||
|
Colors.blue.withOpacity(0.3),
|
||||||
|
AppTheme.of(context).primaryColor.withOpacity(0.2),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
border: Border.all(
|
||||||
|
color: AppTheme.of(context).primaryColor,
|
||||||
|
width: 2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(20),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: AppTheme.of(context).modernGradient,
|
||||||
|
borderRadius: BorderRadius.circular(20),
|
||||||
|
),
|
||||||
|
child: Icon(
|
||||||
|
Icons.location_off,
|
||||||
|
size: 60,
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20),
|
||||||
|
Text(
|
||||||
|
'Sin ubicaciones para mostrar',
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppTheme.of(context).primaryColor,
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Text(
|
||||||
|
'Selecciona una empresa con sucursales\npara ver sus ubicaciones en el mapa',
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
style: TextStyle(
|
||||||
|
color: AppTheme.of(context).secondaryText,
|
||||||
|
fontSize: 16,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get isHovered => _hoveredNegocioId != null;
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
80
pubspec.lock
80
pubspec.lock
@@ -193,6 +193,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
|
dart_earcut:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: dart_earcut
|
||||||
|
sha256: e485001bfc05dcbc437d7bfb666316182e3522d4c3f9668048e004d0eb2ce43b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
dart_jsonwebtoken:
|
dart_jsonwebtoken:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -371,6 +379,14 @@ packages:
|
|||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
flutter_map:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_map
|
||||||
|
sha256: "2ecb34619a4be19df6f40c2f8dce1591675b4eff7a6857bd8f533706977385da"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.2"
|
||||||
flutter_plugin_android_lifecycle:
|
flutter_plugin_android_lifecycle:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -709,6 +725,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.3.1"
|
version: "0.3.1"
|
||||||
|
latlong2:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: latlong2
|
||||||
|
sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.9.1"
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -741,6 +765,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.0"
|
version: "3.0.0"
|
||||||
|
lists:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: lists
|
||||||
|
sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
|
logger:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: logger
|
||||||
|
sha256: "2621da01aabaf223f8f961e751f2c943dbb374dc3559b982f200ccedadaa6999"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.6.0"
|
||||||
logging:
|
logging:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -781,6 +821,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.12.0"
|
version: "1.12.0"
|
||||||
|
mgrs_dart:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mgrs_dart
|
||||||
|
sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -893,6 +941,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.8.0"
|
version: "3.8.0"
|
||||||
|
polylabel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: polylabel
|
||||||
|
sha256: "41b9099afb2aa6c1730bdd8a0fab1400d287694ec7615dd8516935fa3144214b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
postgrest:
|
postgrest:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -909,6 +965,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.4.0"
|
version: "3.4.0"
|
||||||
|
proj4dart:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: proj4dart
|
||||||
|
sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
provider:
|
provider:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -1202,6 +1266,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.2"
|
version: "1.3.2"
|
||||||
|
unicode:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: unicode
|
||||||
|
sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.1"
|
||||||
url_launcher:
|
url_launcher:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -1394,6 +1466,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "5.5.4"
|
version: "5.5.4"
|
||||||
|
wkt_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: wkt_parser
|
||||||
|
sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ dependencies:
|
|||||||
flutter_localizations:
|
flutter_localizations:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
|
# Mapa interactivo
|
||||||
|
flutter_map: ^7.0.2
|
||||||
|
latlong2: ^0.9.1
|
||||||
|
|
||||||
# Paquetes adicionales del pubspec.yaml que te proporcionaron
|
# Paquetes adicionales del pubspec.yaml que te proporcionaron
|
||||||
animated_toggle_switch: ^0.8.2
|
animated_toggle_switch: ^0.8.2
|
||||||
another_stepper: ^1.2.2
|
another_stepper: ^1.2.2
|
||||||
|
|||||||
Reference in New Issue
Block a user