diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..af94e9d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+**/Objects
+**/AutoBackups
\ No newline at end of file
diff --git a/B4A/B4XMainPage.bas b/B4A/B4XMainPage.bas
new file mode 100644
index 0000000..8c2d8d0
--- /dev/null
+++ b/B4A/B4XMainPage.bas
@@ -0,0 +1,315 @@
+B4A=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=9.85
+@EndOfDesignText@
+#Region Shared Files
+#CustomBuildAction: folders ready, %WINDIR%\System32\Robocopy.exe,"..\..\Shared Files" "..\Files"
+'Ctrl + click to sync files: ide://run?file=%WINDIR%\System32\Robocopy.exe&args=..\..\Shared+Files&args=..\Files&FilesSync=True
+'###########################################################################################################
+'###################### PULL #############################################################
+'Ctrl + click ide://run?file=%WINDIR%\System32\cmd.exe&Args=/c&Args=git&Args=pull
+'###########################################################################################################
+'###################### PUSH #############################################################
+'Ctrl + click ide://run?file=%WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe&Args=github&Args=..\..\
+'###########################################################################################################
+#End Region
+
+'Ctrl + click to export as zip: ide://run?File=%B4X%\Zipper.jar&Args=Project.zip
+
+Sub Class_Globals
+ Dim rp As RuntimePermissions
+ Private Root As B4XView
+ Private xui As XUI
+ Private Root As B4XView
+ Public rp As RuntimePermissions
+ Public login As B4XMainPage
+ Public principal As C_Principal
+ Public clientes As C_Clientes
+ Public updateAvailable As C_UpdateAvailable
+ Dim reqManager As DBRequestManager
+' Dim ruta As String
+ Dim usuario As String
+ Dim logger As Boolean = True
+ Dim lat_gps, lon_gps As String
+' Dim skmt As SQL
+ Dim usuario As String
+ Dim server As String
+ Dim montoActual, clientesTotal, clientesVenta, clientesRechazo, clientesVisitados, almacen, rutaPreventa, CANTIDADPROD As String
+ Dim ultimaActualizacionGPS As String = 235959
+ Dim fechaRuta As String
+' Public wsServerLink As String = "ws://187.189.244.154:51042/push/b4a_ws2"
+' Public wsServerLink As String = "ws://10.0.0.214:51042/push/b4a_ws2"
+ Dim srvIp As String
+ Dim phn As Phone
+ Dim user As EditText
+ Dim pass As EditText
+ Dim c As Cursor
+ Dim existe As String
+ Dim paso1 As String
+ Private IMEN As Label
+ Dim IMEI As String
+ Private Label1 As Label
+ Dim server As String
+ Private p_principal As Panel
+ Private Entrar As Button
+ Dim batt As Int
+ Dim porVisitar, entregas, rechazos, montoEntregado, montoRechazado As String
+ Private p_appUpdate As Panel
+ Private i_engrane As ImageView
+ Private b_server As Button
+ Private b_apk As Button
+ Private b_envioBD As Button
+ Private b_regesar As Button
+ Private et_server As EditText
+ Private p_serverList As Panel
+ Private lv_server As ListView
+ Public rutaBDBackup As String = ""
+End Sub
+
+Public Sub Initialize
+' B4XPages.GetManager.LogEvents = True
+End Sub
+
+'This event will be called once, before the page becomes visible.
+Private Sub B4XPage_Created (Root1 As B4XView)
+ Root = Root1
+ B4XPages.GetManager.LogEvents = True
+ Root.LoadLayout("login")
+ B4XPages.SetTitle(Me, "Guna - Control de Kilometraje")
+ login.Initialize
+ B4XPages.AddPage("Login", login)
+ principal.Initialize
+ B4XPages.AddPage("Principal", principal)
+ clientes.Initialize
+ B4XPages.AddPage("Clientes", clientes)
+ updateAvailable.Initialize
+ B4XPages.AddPage("updateAvailable", updateAvailable)
+ reqManager.Initialize(Me, Starter.server)
+ LogColor($"ReqServer = ${Starter.server}"$, Colors.red)
+ Label1.Text = Application.VersionName
+ Starter.skmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS CONTROL_KMS(PLACAS TEXT, OPERADOR TEXT, RUTA TEXT, KMS_INICIAL TEXT, KMS_FINAL TEXT)")
+End Sub
+
+Sub B4XPage_Appear
+ If Starter.muestraProgreso = 1 Then
+ muestraProgreso("Descargando actualización")
+ Starter.muestraProgreso = 0
+ End If
+ Subs.centraPanel(p_principal, Root.Width)
+' Starter.rp.CheckAndRequest(Starter.rp.PERMISSION_ACCESS_FINE_LOCATION)
+'' LogColor("Start Tracker1", Colors.red)
+' Wait For B4XPage_PermissionResult (Permission As String, Result As Boolean)
+' If Result Then
+'' StartService(Tracker)
+'' LogColor("Start Tracker", Colors.red)
+' Else
+' ToastMessageShow("No permission", True)
+' Log("Sin permisos")
+' End If
+' LogColor("Start Tracker3", Colors.red)
+ c=Starter.skmt.ExecQuery("select USUARIO from usuarioa")
+ If c.RowCount > 0 Then
+' c.Position=0
+' c=skmt.ExecQuery("select USUARIO from usuarioa")
+ c.Position=0
+ usuario = c.GetString("USUARIO")
+ End If
+ c.Close
+' Starter.rp.CheckAndRequest(Starter.rp.PERMISSION_WRITE_EXTERNAL_STORAGE)
+' Wait For B4XPage_PermissionResult (Permission As String, Result As Boolean)
+' If Result Then
+' Log("Con permisos de escritura externa")
+' End If
+End Sub
+
+'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage.
+
+Sub Entrar_Click
+ If user.Text = "KMTS1" Then
+ Starter.skmt.ExecNonQuery("delete from usuarioa")
+' Starter.skmt.ExecNonQuery("delete from VERSION")
+ Starter.skmt.ExecNonQuery2("INSERT INTO USUARIOA VALUES (?,?)", Array As Object("ROOT", "ROOT"))
+' Starter.skmt.ExecNonQuery("delete from cat_almacen")
+' Starter.skmt.ExecNonQuery2("INSERT INTO CAT_ALMACEN(ID_ALMACEN) VALUES (?)", Array As Object (user.Text))
+' Starter.skmt.ExecNonQuery2("INSERT INTO VERSION(NOVERSION) VALUES (?)", Array As Object ("2.1"))
+' principal.B_REGRESA_Click
+' B4XPages.MainPage.principal.Subir.Visible = True
+ B4XPages.ShowPage("Principal")
+ Else
+ c=Starter.skmt.ExecQuery2("select count(*) as EXISTE1 from usuarioa where usuario = ?", Array As String(user.Text))
+ c.Position=0
+ existe = c.GetString("EXISTE1")
+ c.Close
+ 'existe = 1
+ If existe = 0 Then
+ 'skmt.ExecNonQuery("delete from usuarioa")
+ Dim cmd As DBCommand
+ cmd.Initialize
+ cmd.Name = "select_usuario_mards_REPG"
+ cmd.Parameters = Array As Object(user.Text, pass.Text)
+ reqManager.ExecuteQuery(cmd , 0, "usuario")
+
+ Dim cmd As DBCommand
+ cmd.Initialize
+ cmd.Name = "select_version_MARDS"
+ reqManager.ExecuteQuery(cmd , 0, "version")
+ Else
+' principal.B_REGRESA_Click
+ B4XPages.ShowPage("Principal")
+ End If
+ End If
+End Sub
+
+Sub JobDone(Job As HttpJob)
+ If Job.Success = False Then
+ ToastMessageShow("Error: " & Job.ErrorMessage, True)
+ Else
+ If Job.JobName = "DBRequest" Then
+ Dim result As DBResult = reqManager.HandleJob(Job)
+ If result.Tag = "version" Then 'query tag
+ For Each records() As Object In result.Rows
+ Starter.skmt.ExecNonQuery("delete from VERSION")
+ Dim CAT_VE_VERSION As String = records(result.Columns.Get("CAT_VE_VERSION"))
+' Starter.skmt.ExecNonQuery2("INSERT INTO VERSION(NOVERSION) VALUES (?)", Array As Object (CAT_VE_VERSION))
+ Next
+ End If
+ End If
+
+ If Job.JobName = "DBRequest" Then
+ Dim result As DBResult = reqManager.HandleJob(Job)
+ If result.Tag = "agencia" Then 'query tag
+ For Each records() As Object In result.Rows
+
+ Dim ID_ALMACEN As String = records(result.Columns.Get("ID_ALMACEN"))
+ Next
+ End If
+ End If
+
+ If Job.JobName = "DBRequest" Then
+ Dim result As DBResult = reqManager.HandleJob(Job)
+ If result.Tag = "usuario" Then 'query tag
+ For Each records() As Object In result.Rows
+ Dim name As String = records(result.Columns.Get("USUARIO"))
+ Dim ID_ALMACEN As String = records(result.Columns.Get("CAT_LO_AGENCIA"))
+ Dim IMEI_BASE As String = records(result.Columns.Get("CAT_LO_IDTELEFONO"))
+ Next
+ paso1 = 1
+ End If
+ End If
+ Job.Release
+ End If
+
+ If paso1 = 1 Then
+ If name = "OKActivo" Then
+ Starter.skmt.ExecNonQuery("delete from usuarioa")
+ Starter.skmt.ExecNonQuery2("INSERT INTO USUARIOA VALUES (?,?)", Array As Object(user.Text, pass.Text))
+ Starter.skmt.ExecNonQuery("delete from cat_almacen")
+' Starter.skmt.ExecNonQuery2("INSERT INTO CAT_ALMACEN(ID_ALMACEN) VALUES (?)", Array As Object (ID_ALMACEN))
+ B4XPages.ShowPage("Principal")
+ Else If name = "OKExpirado"& IMEI Then
+ Msgbox("Usuario Expirado llamar al administrador","") 'ignore
+ Else If name = "OKCancelado"& IMEI Then
+ Msgbox("Usuario Cancelado llamar al administrador","") 'ignore
+ Else
+ Msgbox("Usuario o password No validos","") 'ignore
+ End If
+ paso1 = 0
+ End If
+End Sub
+
+Private Sub i_engrane_Click
+ p_appUpdate.Width = Root.Width
+ p_appUpdate.Height = Root.Height
+ Subs.centraPanel(p_serverList, Root.Width)
+ Subs.centraBoton(b_server, Root.Width)
+ Subs.centraBoton(b_apk, Root.Width)
+ Subs.centraBoton(b_envioBD, Root.Width)
+ Subs.centraBoton(b_regesar, Root.Width)
+ Subs.centraBoton(b_server, p_serverList.Width)
+ lv_server.Clear
+ lv_server.AddSingleLine("http://keymon.lat:1787")
+ If user.Text = "KMTS1" Then lv_server.AddSingleLine("http://10.0.0.205:1787")
+' l_server.Text = Starter.server
+ et_server.Text = Starter.server
+ Subs.panelVisible(p_appUpdate, 0, 0)
+End Sub
+
+Private Sub B4XPage_CloseRequest As ResumableSub
+' Log("closreq")
+ If p_appUpdate.Visible Then
+ p_appUpdate.Visible = False
+ Else
+ Sleep(0)
+ ExitApplication
+ End If
+ Return False
+End Sub
+
+Private Sub b_regesar_Click
+ p_principal.Visible = True
+ p_appUpdate.Visible = False
+End Sub
+
+'Enviamos la base de datos por correo o Whatsapp
+Private Sub b_envioBD_Click
+ Public Provider As FileProvider
+ Log("provider")
+ Provider.Initialize
+ Dim FileName As String = "kmt.db"
+ Log("********* : "&Provider.SharedFolder)
+ Sleep(1000)
+ 'Copy the shared file to the shared folder
+ File.Copy(File.DirInternal, FileName, Provider.SharedFolder, FileName)
+ Dim email As Email
+ email.To.Add("soporte@keymonsoft.com")
+ email.Subject = "Base de datos para revisión"
+ email.Attachments.Add(Provider.GetFileUri(FileName))
+' email.Attachments.Add(Provider.GetFileUri(FileName)) 'second attachment
+ Dim in As Intent = email.GetIntent
+ in.Flags = 1 'FLAG_GRANT_READ_URI_PERMISSION
+ StartActivity(in)
+End Sub
+
+Private Sub b_apk_Click
+ StartService(appUpdater)
+End Sub
+
+Private Sub b_server_Click
+ Log("Guardar servidor")
+ Starter.skmt.ExecNonQuery2("delete from CAT_VARIABLES where CAT_VA_DESCRIPCION = ?", Array As Object ("SERVER"))
+ Starter.skmt.ExecNonQuery2("INSERT INTO CAT_VARIABLES(CAT_VA_DESCRIPCION, CAT_VA_VALOR) VALUES (?,?)", Array As Object ("SERVER",et_server.text))
+ Starter.server = et_server.text
+ If logger Then Log("Inicializamos reqManager con " & Starter.server)
+ reqManager.Initialize(Me, Starter.server)
+ LogColor($"ReqServer = ${Starter.server}"$, Colors.red)
+ reinicializaReqManager
+ p_appUpdate.Visible = False
+' Entrar.Visible = True
+End Sub
+
+Private Sub lv_server_ItemClick (Position As Int, Value As Object)
+' l_server.Text = Value
+ et_server.Text = Value
+ Starter.server = Value
+ reqManager.Initialize(Me, Value)
+ LogColor($"ReqServer = ${Value}"$, Colors.red)
+ ToastMessageShow("Servidor modificado", False)
+End Sub
+
+Sub reinicializaReqManager
+ reqManager.Initialize(Me, Starter.server)
+ If logger Then Log(Starter.server)
+ LogColor($"ReqServer = ${Starter.server}"$, Colors.red)
+End Sub
+
+'appUpdater - Mostramos el anuncio de que se esta descargando el nuevo apk
+Sub muestraProgreso(mensaje As String)
+ ProgressDialogShow(mensaje)
+End Sub
+
+'appUpdater - Ocultamos el anuncio de que se esta descargando el nuevo apk
+Sub ocultaProgreso
+ ProgressDialogHide
+End Sub
\ No newline at end of file
diff --git a/B4A/C_Clientes.bas b/B4A/C_Clientes.bas
new file mode 100644
index 0000000..596807b
--- /dev/null
+++ b/B4A/C_Clientes.bas
@@ -0,0 +1,563 @@
+B4A=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=12.2
+@EndOfDesignText@
+Sub Mods
+ 'Los clientes con rechazo se estan mostrando en la lista ... se DEBEN de mostrar???
+End Sub
+
+Sub Class_Globals
+ Private Root As B4XView 'ignore
+ Private xui As XUI 'ignore
+ Dim q_buscar As String
+' Dim skmt As SQL
+ Dim entro As String
+ Dim c As Cursor
+ Dim c2 As Cursor
+ Dim ListView1 As ListView
+' Dim gest As Button
+ Dim lfila As Label
+ Dim busca As EditText
+ Private p_colonia As Panel
+' Dim distList As List
+' Dim distMap As Map
+ Dim laRuta As String
+ Private b_GetDirs As Button
+ Private distOrderedMap, clientesMapaO As B4XOrderedMap
+ Private img_getDirs As ImageView
+ Private l_rutaInfo As Label
+ Private b_getRutaInfo As Button
+ Private conMapa As Boolean = False
+ Dim listaWayPoints As List
+ Dim lv1Top As String
+ Private b_limpiarRuta As Button
+End Sub
+
+'You can add more parameters here.
+Public Sub Initialize As Object
+ Return Me
+End Sub
+
+'This event will be called once, before the page becomes visible.
+Private Sub B4XPage_Created (Root1 As B4XView)
+ Root = Root1
+ 'load the layout to Root
+ Root.LoadLayout("clientes")
+ entro ="2"
+ lv1Top = ListView1.Top
+ clientesMapaO.Initialize
+ Starter.skmt.ExecNonQuery("delete from waypoints")
+' Log("Coordenadas del almacen: " & Starter.cedisLocation.Longitude & "," & Starter.cedisLocation.Latitude)
+End Sub
+
+'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage.
+
+Sub B4XPage_Appear
+ busca.Text = ""
+ b_GetDirs.Visible = False
+' skmt.Initialize(Starter.ruta,"kmt.db", True)
+ entro ="2"
+ ' esto es para rutas se quito por colonia
+ 'SE COMENTA EL SIGUIENTE CODIGO PARA QUE TODAS LAS TIENDAS APAREZCAN.
+ 'c=skmt.ExecQuery("select CAT_CL_COLONIA, count(*) as cuantos from kmt_info where gestion = 0 group by CAT_CL_COLONIA order by CAT_CL_COLONIA asc")
+ p_colonia.Width = Root.Width
+ p_colonia.Height = Root.Height
+ p_colonia.Top = 0
+ p_colonia.Left = 0
+ Subs.centraListView(ListView1, p_colonia.Width)
+ ListView1.Height = p_colonia.Height * 0.75
+ Subs.SetDivider(ListView1, Colors.LightGray, 2)
+ If Not(l_rutaInfo.Visible) Then
+ ListView1.Top = lv1Top
+ Else
+ ListView1.Top = lv1Top + 100
+ End If
+ c=Starter.skmt.ExecQuery("select codigo, indice, CAT_CL_NOMBRE, CAT_CL_CALLE, CAT_CL_NOEXT from waypoints inner join kmt_info on waypoints.codigo = kmt_info.CAT_CL_CODIGO where gestion = 0 order by indice")
+ If c.RowCount > 0 Then 'Ya hay waypoints en la base de datos
+ c.Position = 0
+' Log("Ya hay waypoints.")
+ conMapa = True
+' Private t1 As Map
+ ListView1.Clear
+ Dim cs, cs2 As CSBuilder
+ entro = 3
+' Log("Generamos ListView1 en Activity_Resume")
+ For i=0 To c.RowCount -1 'Generamos el listView con la lista ordenada.
+ c.Position=i
+ cs.Initialize
+ cs2.Initialize
+' t1 = Starter.waypointsOrdered.Get(k)
+' c.GetString("codigo")
+ ListView1.AddTwoLines(cs.Color(Colors.RGB(100,149,237)).Append(c.GetString("codigo")).PopAll, cs2.append(c.GetString("CAT_CL_NOMBRE")).Color(Colors.RGB(100,149,237)).Append(" Calle: ").Pop.Append(c.GetString("CAT_CL_CALLE").Trim & " " & c.GetString("CAT_CL_NOEXT")).PopAll )
+ Next
+ Else
+ generaListViewRutas
+ End If
+ c.Close
+ p_colonia.Width = Root.Width
+ p_colonia.Height = Root.Height
+ Subs.centraEtiqueta(l_rutaInfo, Root.Width)
+ Subs.centraListView(ListView1, p_colonia.Width)
+ ListView1.Height = p_colonia.Height * 0.70
+ Subs.centraEtiqueta(lfila, Root.Width)
+ b_getRutaInfo.Visible = True
+ b_getRutaInfo.BringToFront
+End Sub
+
+
+Sub ListView1_ItemClick (Position As Int, Value As Object)
+' Log($"Entro= ${entro}"$)
+ ListView1.Clear
+ Sleep(50)
+ Subs.SetDivider(ListView1, Colors.LightGray, 2)
+ If Not(l_rutaInfo.Visible) Then
+ ListView1.Top = lv1Top
+ Else
+ ListView1.Top = lv1Top + 100
+ End If
+ l_rutaInfo.Visible = False
+ b_GetDirs.Visible = False
+ If entro = "2" Then
+ b_GetDirs.Visible = True
+ img_getDirs.Visible = True
+ b_getRutaInfo.Visible = False
+ Private lrt As String
+ lrt = Value
+ laRuta = lrt.SubString(6) 'Quitamos el texto "Ruta: " para obtener el numero de la ruta.
+' Log($"Original: ${Value} - Mod: |${lrt.SubString(6)}| - laRuta: ${laRuta}"$)
+ c2=Starter.skmt.ExecQuery2("select CAT_CL_NOMBRE, CAT_CL_CALLE, CAT_CL_CODIGO, CAT_CL_LAT, CAT_CL_LONG from kmt_info where CAT_CL_RUTA = ? and gestion = 0 order by CAT_CL_NOMBRE ", Array As String(laRuta))
+' Private thisLoc As Location
+ Private label1 As Label
+ Private label2 As Label
+ label1 = ListView1.TwoLinesLayout.Label
+ label1.TextSize = 15
+ label1.TextColor = Colors.black
+ label2 = ListView1.TwoLinesLayout.SecondLabel
+ label2.TextSize = 15
+ label2.TextColor = Colors.black
+ label2.Height = 38dip
+' thisLoc.Initialize
+ If entro = 2 Then ListView1.TwoLinesLayout.ItemHeight = 75dip
+ lfila.text = "Nombre y Calle"
+ distOrderedMap.Initialize
+ If c2.RowCount>0 Then
+ For i=0 To c2.RowCount -1 'Generamos mapa de clientes
+ c2.Position=i
+' thisLoc.Latitude = c2.GetString("CAT_CL_LAT")
+' thisLoc.Longitude = c2.GetString("CAT_CL_LONG")
+' Log(Tracker.UUGCoords)
+' Private distancia As Int = Tracker.UUGCoords.DistanceTo(thisLoc) 'Calculamos la distancia de la posicion ACTUAL a la tienda.
+' Private esteCliente As Map = CreateMap("distancia": distancia, "ubicacion": thisLoc.Longitude&","&thisLoc.Latitude, "codigo": c2.GetString("CAT_CL_CODIGO"), "nomDirDist": $"${c2.GetString("CAT_CL_NOMBRE")} CALLE: ${c2.GetString("CAT_CL_CALLE")} ${CRLF}Distancia: $1.1{(distancia/1000)} kms"$)
+' distOrderedMap.Put(distancia, esteCliente)
+ Next
+ distOrderedMap.Keys.Sort(True) 'Ordenamos la mapa de clientes por distancia.
+ ListView1.Clear
+ Private m1 As Map
+ For Each k As Object In distOrderedMap.Keys 'Generamos el listView con el mapa ordenada.
+ m1 = distOrderedMap.Get(k)
+ m1.Get("codigo")
+ ListView1.AddTwoLines(m1.Get("codigo"), m1.Get("nomDirDist"))
+ Next
+ End If
+ c2.Close
+ entro = "3"
+ Else If entro = "3" Then
+ Starter.skmt.ExecNonQuery("delete from CUENTAA")
+ Starter.skmt.ExecNonQuery2("INSERT INTO CUENTAA VALUES (?)", Array As Object(Value))
+ B4XPages.ShowPage("Cliente")
+ End If
+End Sub
+
+'Genera el listview que muestra las rutas y clientes a visitar por ruta.
+Sub generaListViewRutas
+ ListView1.Clear
+ Sleep(110)
+ lfila.Text = "RUTA PREVENTA"
+ Dim label1 As Label
+ label1 = ListView1.TwoLinesLayout.Label
+ label1.TextSize = 15
+ label1.TextColor = Colors.Black
+ Dim label2 As Label
+ label2 = ListView1.TwoLinesLayout.SecondLabel
+ label2.TextSize = 15
+ label2.TextColor = Colors.Black
+ ListView1.TwoLinesLayout.ItemHeight = 60dip
+ c=Starter.skmt.ExecQuery("select CAT_CL_RUTA, count(*) as cuantos from kmt_info where gestion = 0 group by CAT_CL_RUTA order by CAT_CL_RUTA asc")
+ If c.RowCount>0 Then
+ ListView1.Clear
+ For i=0 To c.RowCount -1
+ c.Position=i
+ ListView1.AddTwoLines("Ruta: " & c.GetString("CAT_CL_RUTA"), "Por visitar: " & c.GetString("cuantos"))
+ Next
+ End If
+ c.Close
+End Sub
+
+Sub Activity_KeyPress (key As Int) As Boolean 'ignore
+ ' BACK key pressed
+ If key=KeyCodes.KEYCODE_BACK Then
+ If entro = 3 And Not(conMapa) Then
+ b_GetDirs.Visible = False
+' StartActivity(Activity_Create(False))
+ B4XPage_Created(Root)
+ Return True
+ End If
+ B4XPages.ShowPage("Principal")
+ Return False
+ 'End If
+ End If
+ ' Returning False signals the system to handle the key
+End Sub
+
+Sub BUSCA_TextChanged (Old As String, New As String)
+ q_buscar = "%" & busca.Text & "%"
+ c2=Starter.skmt.ExecQuery2("select CAT_CL_NOMBRE, CAT_CL_CALLE, CAT_CL_CODIGO from kmt_info where CAT_CL_NOMBRE like ? and gestion = 0 order by CAT_CL_CODIGO ", Array As String(q_buscar))
+ ListView1.Clear
+ lfila.text = "Nombre y Calle"
+ Subs.SetDivider(ListView1, Colors.LightGray, 2)
+ If c2.RowCount>0 Then
+ For i=0 To c2.RowCount -1
+ c2.Position=i
+ Dim label1 As Label
+ label1 = ListView1.TwoLinesLayout.Label
+ label1.TextSize = 15
+ label1.TextColor = Colors.Black
+ Dim label2 As Label
+ label2 = ListView1.TwoLinesLayout.SecondLabel
+ label2.TextSize = 15
+ label2.TextColor = Colors.Black
+ ListView1.AddTwoLines(c2.GetString("CAT_CL_CODIGO"), c2.GetString("CAT_CL_NOMBRE") &" CALLE: "& c2.GetString("CAT_CL_CALLE"))
+ Next
+ End If
+ entro = "3"
+ c2.Close
+End Sub
+
+'Regresa la distancia y tiempo de la ruta entre dos puntos, usa el API del projecto OSRM. (Parte de la funcionalidad OSRM)
+'Para mas información ir a esta liga:
+'http://project-osrm.org/docs/v5.24.0/api/?language=cURL#route-service
+Sub distanciaEntreCoords(id As String, coords1 As String, coords2 As String) As ResumableSub 'ignore
+' Sleep(1050)
+' Private distanciaTotal As String = "0"
+' Private tiempo As String = "0"
+' Dim j As HttpJob
+' j.Initialize("", Me)
+' j.Download("https://router.project-osrm.org/route/v1/driving/"&coords1&";"&coords2&"?overview=false")
+' Wait For (j) JobDone(j As HttpJob)
+' If j.Success Then
+' Dim jp As JSONParser
+' jp.Initialize(j.GetString)
+' Dim m As Map = jp.NextObject
+' Log($"Respuesta: ${m.Get("code")}"$)
+' If m.Get("code") = "Ok" Then
+'' Log(m)
+' Dim rutas As List = m.Get("routes")
+' Dim rutas2 As Map = rutas.Get(0)
+'' Log(rutas2)
+'' Dim legs As List = rutas2.Get("legs")
+'' Log(legs)
+' distanciaTotal = rutas2.Get("distance")
+' tiempo = rutas2.Get("duration")
+' Log($"Distancia total: ${distanciaTotal}, Tiempo: ${tiempo}"$ )
+' End If
+' Else
+' Log("Error!")
+' End If
+' j.Release
+' Private r As List
+' r.Initialize
+' r.Add(id)
+' r.Add(distanciaTotal)
+' r.Add(tiempo)
+' Return r
+End Sub
+
+'Regresa la distancia y tiempo estimado de la ruta del repartidor, utiliza el API del projecto OSRM
+'para calcular la distancia y tiempo de la ruta de un mapa de coordenadas a visitar dado. (Parte de la funcionalidad OSRM)
+Sub traeRutaDia(aVisitar As B4XOrderedMap)
+' Private coordsInicio As String = $"${Starter.cedisLocation.Longitude},${Starter.cedisLocation.Latitude}"$
+' Log($"Coordenadas de inicio: ${Starter.cedisLocation.Longitude},${Starter.cedisLocation.Latitude}"$)
+' Private rutaCompleta As String = coordsInicio
+' Private preRuta As String = coordsInicio
+' Private distanciaTotal, distanciaTotal0, tiempo0, tiempo As Double
+' Private masDe100 As Boolean
+' Private m4 As Map
+' Private visitaActual As Int = 0
+' Private cuantosAntes As Int = 0
+' listaWayPoints.Initialize
+' If aVisitar.Keys.Size > 98 Then 'Si los clientes a visitar son mas de 100 entonces hacemos 2 rutas, una inicial con pocas visitas (las que pasen de 100) y la final con el resto ...
+' cuantosAntes = aVisitar.Keys.Size - 98 'Definimos de cuantos clientes va a ser la ruta inicial.
+' preRuta = coordsInicio 'Ponemos las coordenadas de inicio (Las del CEDIS).
+' rutaCompleta = ""
+' masDe100 = True
+' End If
+' Log($"a visitar: ${aVisitar.Keys.Size}"$)
+' For Each k As Object In aVisitar.Keys
+' visitaActual = visitaActual + 1
+' m4 = aVisitar.Get(k)
+'' Log($"visitaActual: ${visitaActual} - cuantosAntes: ${cuantosAntes}"$)
+' If visitaActual < cuantosAntes + 2 Then 'Si estas coordenadas son de la ruta inicial las agregamos ...
+' preRuta = preRuta & ";" & m4.Get("coords")
+'' LogColor($"PreRuta - visitaActual: ${visitaActual} - coords: ${m4.Get("coords")}"$, Colors.Magenta)
+' End If
+' If visitaActual >= cuantosAntes + 2 Then 'Si estas coordenadas son de la ruta final las agregamos ...
+' rutaCompleta = rutaCompleta & ";" & m4.Get("coords")
+'' LogColor($"RutaCompleta - visitaActual: ${visitaActual} - coords: ${m4.Get("coords")} - testRuta Size: ${testRutaCompleta.size}"$, Colors.Green)
+' End If
+' Next
+' rutaCompleta = rutaCompleta & ";" & coordsInicio 'Agregamos las coordenadas del CEDIS al final para que sea viaje ida y vuelta.
+'' rutaCompleta = rutaCompleta & ";" & coordsInicio
+' If rutaCompleta.StartsWith(";") Then rutaCompleta = rutaCompleta.SubString(1) 'Si las cooredenadas tienen ";" al principio se lo quitamos.
+'' LogColor(preRuta, Colors.magenta)
+'' LogColor(rutaCompleta, Colors.Green)
+' ProgressDialogShow2("Calculando distancia y tiempo, un momento por favor.", False)
+' Private tiempoVisitas As Double 'TIMEPO DE 4 MINUTOS PROMEDIO POR TIENDA ESTO SE CAMBIA SEGUN EL CLIENTE
+' tiempoVisitas = aVisitar.Keys.Size * 4 * 60 'Aqui se calcula el tiempo que duran las visitas x 4 mins cada una en segundos.
+' tiempo0 = 0
+' distanciaTotal0 = 0
+' If masDe100 Then 'Si son mas de 100, entonces primero calculamos la ruta inicial.
+' Dim j0 As HttpJob
+' j0.Initialize("trip0", Me)
+' j0.Download("https://router.project-osrm.org/trip/v1/driving/"&preRuta&"?source=first&destination=last&roundtrip=false&geometries=geojson")
+'' LogColor("https://router.project-osrm.org/trip/v1/driving/"&preRuta&"?source=first&destination=last&roundtrip=false&geometries=geojson", Colors.Magenta)
+' Wait For (j0) JobDone(j0 As HttpJob)
+' If j0.Success Then
+' Dim jp0 As JSONParser
+' jp0.Initialize(j0.GetString)
+' Dim m0 As Map = jp0.NextObject
+' If m0.Get("code") = "Ok" Then
+' Dim puntos0 As List = m0.Get("waypoints")
+' Private esteWayPoint0 As Map
+' For p = 0 To puntos0.Size -1
+' esteWayPoint0 = puntos0.Get(p)
+'' LogColor("WP:" & esteWayPoint0, Colors.magenta)
+'' LogColor("WP: " & esteWayPoint0.Get("waypoint_index") & ", loc: " & esteWayPoint0.Get("location") & ", name: " & esteWayPoint0.Get("name"), Colors.Magenta)
+' esteWayPoint0.Remove("hint")
+' esteWayPoint0.Remove("distance")
+' esteWayPoint0.Remove("trips_index")
+' listaWayPoints.Add(esteWayPoint0)
+'' LogColor("estewaypoint: "&esteWayPoint0, Colors.Magenta)
+' Next
+' Dim rutas0 As List = m0.Get("trips")
+' Dim rutas20 As Map = rutas0.Get(0)
+'' Dim geometry0 As Map = rutas20.Get("geometry")
+'' Private coords0 As List = geometry0.Get("coordinates")
+' distanciaTotal0 = rutas20.Get("distance")
+' tiempo0 = rutas20.Get("duration")
+' tiempo0 = ((tiempo0 * 2) ) 'Tiempo X 2 (es muy corto porque no toma encuenta el trafico).
+' Log($"Distancia total ruta inicial: $1.1{distanciaTotal0/1000} kms, tiempo aprox: $1.1{tiempo0/60} mins. ($1.1{tiempo0/60/60} hrs)"$)
+'' l_rutaInfo.Text = $"Distancia total: $1.1{distanciaTotal0/1000} kms, tiempo aprox: $1.1{tiempo0/60/60} hrs"$
+' End If
+' Else
+' Log("Error!")
+' End If
+' j0.Release
+' End If
+'
+' Dim j As HttpJob
+' j.Initialize("trip", Me) 'Calculamos el resto de la ruta.
+' j.Download("https://router.project-osrm.org/trip/v1/driving/"&rutaCompleta&"?source=first&destination=last&roundtrip=false&geometries=geojson")
+'' LogColor("https://router.project-osrm.org/trip/v1/driving/"&rutaCompleta&"?source=first&destination=last&roundtrip=false&geometries=geojson", Colors.Green)
+' Wait For (j) JobDone(j As HttpJob)
+' If j.Success Then
+' Dim jp As JSONParser
+' jp.Initialize(j.GetString)
+' Dim m As Map = jp.NextObject
+' If m.Get("code") = "Ok" Then
+' Dim puntos As List = m.Get("waypoints")
+' Private esteWayPoint As Map
+' Dim twpi As Int
+' For p = 0 To puntos.Size -1
+' esteWayPoint = puntos.Get(p)
+'' LogColor("WP:" & esteWayPoint, Colors.green)
+'' LogColor("WP: " & esteWayPoint.Get("waypoint_index") & ", loc: " & esteWayPoint.Get("location") & ", name: " & esteWayPoint.Get("name"), Colors.Green)
+' esteWayPoint.Remove("hint")
+' esteWayPoint.Remove("distance")
+' esteWayPoint.Remove("trips_index")
+' twpi = esteWayPoint.Get("waypoint_index")
+' esteWayPoint.Remove("waypoint_index")
+' esteWayPoint.Put("waypoint_index", (twpi + cuantosAntes + 2))
+' listaWayPoints.Add(esteWayPoint)
+'' LogColor("estewaypoint: "&esteWayPoint, Colors.Green)
+' Next
+' Dim rutas As List = m.Get("trips")
+' Dim rutas2 As Map = rutas.Get(0)
+' distanciaTotal = rutas2.Get("distance")
+' Log("distancia ruta 2:" & (distanciaTotal) & "|" & rutas2.Get("distance"))
+' distanciaTotal = distanciaTotal + distanciaTotal0
+' tiempo = rutas2.Get("duration")
+' tiempo = (((tiempo + tiempo0) * 2) + tiempoVisitas) 'Tiempo X 2 (es muy corto porque no toma encuenta el trafico) + tiempoVisitas.
+' Log($"Distancia total: $1.1{distanciaTotal/1000} kms, tiempo aprox: $1.1{tiempo/60} mins. ($1.1{tiempo/60/60} hrs)"$)
+' l_rutaInfo.Text = $"Distancia: $1.1{distanciaTotal/1000} kms, tiempo aprox: $1.1{tiempo/60/60} hrs${CRLF}Visitas restantes: ${aVisitar.Keys.Size}"$
+' l_rutaInfo.Width = Root.Width * 0.9
+' Subs.centraEtiqueta(l_rutaInfo, Root.Width)
+' l_rutaInfo.Visible = True
+' l_rutaInfo.BringToFront
+' ListView1.Top = lv1Top + 100
+' End If
+' Else
+' LogColor("**************** Error! ******************", Colors.red)
+' End If
+' j.Release
+' ProgressDialogHide
+'' LogColor("clientesMapaO size: " & clientesMapaO.Size & "|" & listaWayPoints.Size, Colors.Blue)
+' Private r As Int = 1
+' Private r1, wps As Map
+' Starter.skmt.ExecNonQuery("delete from waypoints")
+' For Each k As Object In clientesMapaO.Keys 'Guardamos en la BD el orden de los waypoints para luego generar el listview.
+' r1 = clientesMapaO.Get(k)
+' r1.Get("codigo")
+'' Log(listaWayPoints.Get(r) & "|" & r1.Get("coords") & "|" & r1.Get("calle"))
+' wps = listaWayPoints.Get(r)
+' Starter.skmt.ExecNonQuery2("insert into waypoints values (?,?)", Array As Object(r1.Get("codigo"), wps.get("waypoint_index")))
+' r = r + 1
+' Next
+' ListView1.Clear
+' Sleep(100)
+' Dim label2 As Label
+' label2 = ListView1.TwoLinesLayout.SecondLabel
+' label2.TextSize = 15
+' label2.Height = 100dip
+' ListView1.TwoLinesLayout.ItemHeight = 70dip
+' Dim cs, cs2 As CSBuilder
+' entro = 3
+' Log("Generamos ListView1 en traeRutaDia")
+' 'Traemos las visitas restantes ordenadas por el indice de waypoints (este indice nos indica el orden en la ruta calculada).
+' c=Starter.skmt.ExecQuery("select codigo, indice, CAT_CL_NOMBRE, CAT_CL_CALLE, CAT_CL_NOEXT from waypoints inner join kmt_info on waypoints.codigo = kmt_info.CAT_CL_CODIGO where gestion = 0 order by indice")
+' If c.RowCount > 0 Then
+' For i=0 To c.RowCount -1 'Generamos el listView con la lista ordenada.
+' c.Position=i
+' cs.Initialize
+' cs2.Initialize
+' ListView1.AddTwoLines(cs.Color(Colors.RGB(100,149,237)).Append(c.GetString("codigo")).PopAll, cs2.append(c.GetString("CAT_CL_NOMBRE")).Color(Colors.RGB(100,149,237)).Append(" Calle: ").Pop.Append(c.GetString("CAT_CL_CALLE").Trim & " " & c.GetString("CAT_CL_NOEXT")).PopAll )
+' Next
+' End If
+' c.Close
+End Sub
+
+'Calcula distancia y tiempo de la ubicacion ACTUAL a las 8 primeras tiendas de la lista usando el API de OSRM. (Parte de la funcionalidad OSRM)
+Private Sub b_GetDirs_Click
+ ProgressDialogShow("Calculando distancias y tiempos ...")
+ Private m2 As Map
+ Private f As Int = 0
+ For Each k As Object In distOrderedMap.Keys 'Traemos la distancia y tiempo desde OSRM (2 puntos)
+ m2 = distOrderedMap.Get(k)
+ Private distancia2 As String = m2.Get("distancia")
+ Private thisLoc1 As String = m2.Get("ubicacion")
+' Private locActual As String = Tracker.UUGCoords.Longitude&","&Tracker.UUGCoords.Latitude
+' If locActual = "0,0" Then 'Si no tenemos ubicacion actual de GPS, buscamos la ultima guardada en la base de datos.
+' c = Starter.skmt.ExecQuery("select * from hist_gps")
+' If c.RowCount > 0 Then
+' c.Position = 0
+'' locActual = c.GetString("hglon") & "," & c.GetString("hglat")
+' End If
+' c.Close
+' End If
+ f = f+1
+ If f < 8 Then
+' If locActual = "0,0" Then 'Si todavia no tenemos ubicacion actual, entonces avisamos.
+' ToastMessageShow("No se pudo obtener la ubicacion actual!!", True)
+' f = 8
+' End If
+' Log($"locActual: ${locActual}, thisLoc1: ${thisLoc1}"$)
+ Wait For(distanciaEntreCoords(distancia2, locActual, thisLoc1)) Complete (r As List)
+ LogColor($"R: ${r.Get(0)} - ${r.Get(1)} - ${r.Get(2)}"$, Colors.Green)
+ Private tId As Int = r.Get(0)
+ Private tMap As Map = distOrderedMap.Get(tId)
+ LogColor("|" & tId & "| - " &distOrderedMap.Get(tId), Colors.Blue)
+ Private tempNDD As String = tMap.Get("nomDirDist")
+ Private indexD As Int = tempNDD.IndexOf("Distancia:")
+ If indexD > -1 Then tempNDD = tempNDD.SubString2(0, indexD)
+ Log(tempNDD)
+ tempNDD = tempNDD & $"Dist: $1.1{(r.Get(1)/1000)} kms, Tiempo aprox: $1.0{((r.Get(2)*2)/60)} min."$ 'Multiplicamos el tiempo X 2 porque el tiempo estimado siempre es muy corto, X2 es mucho mas real con trafico.
+ Private esteCliente As Map = CreateMap("distancia": distancia2, "ubicacion": tMap.Get("ubicacion"), "codigo": tMap.Get("codigo"), "nomDirDist": tempNDD)
+ distOrderedMap.Put(tId, esteCliente)
+ ListView1.Clear
+ Private m3 As Map
+ For Each k As Object In distOrderedMap.Keys 'Generamos el listView con la lista ordenada.
+ m3 = distOrderedMap.Get(k)
+ m3.Get("codigo")
+ ListView1.AddTwoLines(m3.Get("codigo"), m3.Get("nomDirDist"))
+ Next
+ End If
+ Next
+ ProgressDialogHide
+End Sub
+
+'Regresa un mapa (B4XOrderedMap) con todos los clientes que tiene que visitar el repartidor. (Parte de la funcionalidad OSRM)
+Sub traeTodosAVisitar As B4XOrderedMap 'ignore
+' Log("Iniciamos traeTodosAVisitar")
+'' If Starter.waypointsOrdered.isInitialized Then Log(Starter.waypointsOrdered.Size)
+'' Private rutaCompleta As String = ""
+' Private thisLoc, ubicacionInicial As Location
+' ubicacionInicial = Starter.cedisLocation
+' LogColor(ubicacionInicial, Colors.Gray)
+' c=Starter.skmt.ExecQuery("select sum(gestion) as hayVisitados from kmt_info")
+' If c.RowCount > 0 Then
+' c.Position = 0
+'' Log(c.GetString("hayVisitados"))
+'' If c.GetString("hayVisitados") > 0 Then ubicacionInicial = Tracker.UUGCoords 'Si ya hay clientes visitados, entonces ya no estamos en el CEDIS y la ubicacion inicial debe de ser la ACTUAL.
+' End If
+' c.Close
+' LogColor(ubicacionInicial, Colors.Red)
+' thisLoc.Initialize
+' clientesMapaO.Clear
+' 'Traemos las rutas asignadas al repartidor.
+' c=Starter.skmt.ExecQuery("select CAT_CL_RUTA, count(*) as cuantos from kmt_info where gestion = 0 group by CAT_CL_RUTA order by CAT_CL_RUTA asc")
+' If c.RowCount>0 Then
+' 'Traemos los clientes de cada ruta.
+' For i=0 To c.RowCount -1
+' c.Position=i
+'' Log($"Renglones ruta: ${c.RowCount} - i=${i} - Ruta: ${c.GetString("CAT_CL_RUTA")}"$)
+' c2=Starter.skmt.ExecQuery2("select CAT_CL_NOMBRE, CAT_CL_CALLE, CAT_CL_CODIGO, CAT_CL_LAT, CAT_CL_LONG from kmt_info where CAT_CL_RUTA = ? and gestion = 0 order by CAT_CL_NOMBRE ", Array As String(c.GetString("CAT_CL_RUTA")))
+' If c2.RowCount>0 Then
+' For j=0 To c2.RowCount -1 'Generamos lista de clientes
+' c2.Position=j
+'' Log($"Renglones clientes: ${c2.RowCount} - j=${j} - Ruta: ${c2.GetString("CAT_CL_CODIGO")}"$)
+' thisLoc.Latitude = c2.GetString("CAT_CL_LAT")
+' thisLoc.Longitude = c2.GetString("CAT_CL_LONG")
+' If Not(thisLoc.Latitude = 0.0) And Not(thisLoc.Latitude = 0) Then 'Este IF es para que si las coordenadas no son válidas, entonces no las agregue al mapeo, porque el API de OSRM nos manda error.
+' Private distancia As Int = ubicacionInicial.DistanceTo(thisLoc) 'Calculamos la distancia del cedis a la tienda.
+' If clientesMapaO.ContainsKey(distancia) Then distancia = distancia + 1 'Si por alguna extraña razon hay dos tiendas a la misma distancia del CEDIS, le sumamos 1 para que sea diferente.
+' Private esteCliente As Map = CreateMap("distancia": distancia, "ordenDist": j, "coords": c2.GetString("CAT_CL_LONG")&","&c2.GetString("CAT_CL_LAT"), "codigo": c2.GetString("CAT_CL_CODIGO"), "nombre": c2.GetString("CAT_CL_NOMBRE"), "calle": c2.GetString("CAT_CL_CALLE"))
+' clientesMapaO.Put(distancia, esteCliente)
+' Else
+' ToastMessageShow("Hay tiendas SIN coordenadas, fueron excluidas!!", False)
+' End If
+'' Log($"${thisLoc}"$)
+'' rutaCompleta = rutaCompleta & ";" & c2.GetString("CAT_CL_LONG")&","&c2.GetString("CAT_CL_LAT")
+' Next
+' End If
+' Next
+' End If
+' clientesMapaO.Keys.Sort(True) 'Ordenamos la lista de clientes por distancia.
+' c.Close
+' c2.Close
+' Log(c.RowCount & " rutas, " & clientesMapaO.Size & " clientes")
+'' LogColor(rutaCompleta, Colors.Magenta)
+'' Log(clientesMapaO)
+' Return clientesMapaO
+End Sub
+
+'Traemos la ruta de visitas via el API de OSRM usando el sub "traeRutaDia(traeTodosAVisitar)".
+Private Sub b_getRutaInfo_Click
+ traeRutaDia(traeTodosAVisitar)
+End Sub
+
+'Mostramos u ocultamos el boton para borrar los waypoints de la ruta.
+Private Sub b_getRutaInfo_LongClick
+ If b_limpiarRuta.Visible Then
+ b_limpiarRuta.Visible = False
+ Else
+ b_limpiarRuta.Visible = True
+ End If
+End Sub
+
+'Borramos los waypoints de la ruta.
+Private Sub b_limpiarRuta_Click
+ Starter.skmt.ExecNonQuery("delete from waypoints")
+ b_limpiarRuta.Visible = False
+ B4XPage_Appear
+End Sub
\ No newline at end of file
diff --git a/B4A/C_Principal.bas b/B4A/C_Principal.bas
new file mode 100644
index 0000000..1445ac2
--- /dev/null
+++ b/B4A/C_Principal.bas
@@ -0,0 +1,278 @@
+B4A=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=12.2
+@EndOfDesignText@
+Sub Class_Globals
+ Private Root As B4XView 'ignore
+ Private xui As XUI 'ignore
+ Dim reqManager As DBRequestManager
+ Dim b_mapa As Button
+ Dim l_ruta As Label
+ Private inv As Button
+ Private p_principal As Panel
+ Dim ime As IME
+ Private et_placas As EditText
+ Private et_operador As EditText
+ Private et_rutaReparto As EditText
+ Private b_guardar As Button
+ Private ImageView1 As ImageView
+ Private ImageView1 As ImageView
+ Private p_datos As Panel
+ Private p_camara As Panel
+ Private b_cerrar As Button
+ Private pnlPreview As Panel
+ Private camEx As CameraExClass
+
+ Private toast As BCToast
+ Private Capturing As Boolean
+ Private rp As RuntimePermissions
+ Private detector As JavaObject
+ Private camEx As CameraExClass
+ Private LastPreview As Long
+ Private IntervalBetweenPreviewsMs As Int = 100
+ Dim codigoencontrado, codigoBuscado As String
+ Private b_escanRuta As Button
+ Private b_escanOperador As Button
+ Private b_escanPlacas As Button
+ Private et_kmsInicial As EditText
+ Private et_kmsFinal As EditText
+End Sub
+
+'You can add more parameters here.
+Public Sub Initialize As Object
+ Return Me
+End Sub
+
+'This event will be called once, before the page becomes visible.
+Private Sub B4XPage_Created (Root1 As B4XView)
+ Root = Root1
+ 'load the layout to Root
+ Root.LoadLayout("principal")
+ reqManager.Initialize(Me, Starter.server)
+ B4XPages.MainPage.usuario=Subs.dameUsuarioDeDB
+ 'Inicia camara
+ p_camara.Width = Root.Width
+ p_camara.Height= Root.Height
+ p_camara.Visible = False
+ toast.Initialize(Root)
+ StopCamera
+ B4XPages.SetTitle(Me, "Barcode Example")
+ CreateDetector (Array("AZTEC", "CODE_128", "CODE_39", "CODE_93", "CODABAR", "DATA_MATRIX", "EAN_13", "EAN_8", "ITF", "PDF417", "QR_CODE", "UPC_A", "UPC_E"))
+ 'Termina camara
+End Sub
+
+Sub B4XPage_Appear
+ Subs.centraPanel(p_principal, Root.Width)
+
+End Sub
+
+Sub JobDone(Job As HttpJob)
+' Private r As DBResult = reqManager.HandleJob(Job)
+ If Job.Success = False Then
+ LogColor("** " & Job.Tag & " Error: " & Job.ErrorMessage, Colors.Red) ' Mod by CHV - 211023
+ 'ToastMessageShow("Error: " & Job.ErrorMessage, True)
+ Else
+ LogColor("JobDone: '" & reqManager.HandleJob(Job).tag & "' - Registros: " & reqManager.HandleJob(Job).Rows.Size, Colors.Green) 'Mod por CHV - 211023
+ If Job.JobName = "DBRequest" Then
+ Dim result As DBResult = reqManager.HandleJob(Job)
+ If result.Tag = "ins_rechazos" Then 'query tag
+ For Each records() As Object In result.Rows
+ For Each k As String In result.Columns.Keys
+ Log(k & ": " & records(result.Columns.Get(k)))
+ Next
+ Next
+ End If
+ End If
+ Job.Release
+ End If
+End Sub
+
+Private Sub B4XPage_CloseRequest As ResumableSub
+ ' BACK key pressed
+ B4XPages.ShowPage("Login")
+ ' Returning False signals the system to handle the key
+ Return False
+End Sub
+
+'Inicia camara
+
+Private Sub B4XPage_Disappear
+ If p_camara.Visible = True Then
+ p_camara.Visible = False
+ StopCamera
+ End If
+End Sub
+
+
+Sub btnStartStop_Click
+ If Capturing = False Then
+ p_camara.Visible = True
+ StartCamera
+ Else
+ p_camara.Visible = False
+ StopCamera
+ End If
+End Sub
+
+Private Sub B_cerrar_Click
+' If et_codigo.Text.Length = 0 Then
+' p_camara.Visible = False
+' Else
+' p_camara.Visible = False
+' et_codigo_EnterPressed
+' End If
+ StopCamera
+ p_camara.Visible = False
+End Sub
+
+Private Sub StopCamera
+' et_codigo.Text = ""
+ Capturing = False
+ pnlPreview.Visible = False
+ If camEx.IsInitialized Then
+ camEx.Release
+ End If
+End Sub
+
+Private Sub StartCameraShared
+ pnlPreview.Visible = True
+ Capturing = True
+End Sub
+
+Private Sub FoundBarcode (msg As String)
+' et_codigo.Text = msg
+ toast.Show($"Found [Color=Red][b][plain]${msg}[/plain][/b][/Color]"$)
+ Log(msg)
+ codigoencontrado = msg
+ Log($"${codigoencontrado}, ${codigoBuscado}"$)
+ If codigoBuscado = "placas" Then
+ et_placas.text = codigoencontrado
+ Else If codigoBuscado = "operador" Then
+ Log("ponemos operador en HOLA")
+ et_operador.text = codigoencontrado
+ Else If codigoBuscado = "ruta" Then
+ et_rutaReparto.text = codigoencontrado
+ End If
+' If et_codigo.Text.Length > 1 Then
+ B_cerrar_Click
+' End If
+End Sub
+
+Private Sub StartCamera
+ rp.CheckAndRequest(rp.PERMISSION_CAMERA)
+ Wait For B4XPage_PermissionResult (Permission As String, Result As Boolean)
+ If Result = False Then
+ toast.Show("No permission!")
+ Return
+ End If
+ StartCameraShared
+ camEx.Initialize(pnlPreview, False, Me, "Camera1")
+ Wait For Camera1_Ready (Success As Boolean)
+ If Success Then
+ camEx.SetContinuousAutoFocus
+ camEx.CommitParameters
+ camEx.StartPreview
+ Else
+ toast.Show("Error opening camera")
+ StopCamera
+ End If
+End Sub
+
+Private Sub CreateDetector (Codes As List)
+ Dim ctxt As JavaObject
+ ctxt.InitializeContext
+ Dim builder As JavaObject
+ builder.InitializeNewInstance("com/google/android/gms/vision/barcode/BarcodeDetector.Builder".Replace("/", "."), Array(ctxt))
+ Dim barcodeClass As String = "com/google/android/gms/vision/barcode/Barcode".Replace("/", ".")
+ Dim barcodeStatic As JavaObject
+ barcodeStatic.InitializeStatic(barcodeClass)
+ Dim format As Int
+ For Each formatName As String In Codes
+ format = Bit.Or(format, barcodeStatic.GetField(formatName))
+ Next
+ builder.RunMethod("setBarcodeFormats", Array(format))
+ detector = builder.RunMethod("build", Null)
+ Dim operational As Boolean = detector.RunMethod("isOperational", Null)
+ If operational = False Then
+ toast.Show("Failed to create detector")
+ End If
+ b_escanOperador.Enabled = operational
+ b_escanPlacas.Enabled = operational
+ b_escanRuta.Enabled = operational
+End Sub
+
+Private Sub Camera1_Preview (data() As Byte)
+ If DateTime.Now > LastPreview + IntervalBetweenPreviewsMs Then
+ 'Dim n As Long = DateTime.Now
+ Dim frameBuilder As JavaObject
+ Dim bb As JavaObject
+ bb = bb.InitializeStatic("java.nio.ByteBuffer").RunMethod("wrap", Array(data))
+ frameBuilder.InitializeNewInstance("com/google/android/gms/vision/Frame.Builder".Replace("/", "."), Null)
+ Dim cs As CameraSize = camEx.GetPreviewSize
+ frameBuilder.RunMethod("setImageData", Array(bb, cs.Width, cs.Height, 842094169))
+ Dim frame As JavaObject = frameBuilder.RunMethod("build", Null)
+ Dim SparseArray As JavaObject = detector.RunMethod("detect", Array(frame))
+ LastPreview = DateTime.Now
+ Dim Matches As Int = SparseArray.RunMethod("size", Null)
+ If Matches > 0 Then
+ Dim barcode As JavaObject = SparseArray.RunMethod("valueAt", Array(0))
+ Dim raw As String = barcode.GetField("rawValue")
+ FoundBarcode(raw)
+ End If
+ End If
+End Sub
+
+'fin camara
+
+Private Sub b_guardar_Click
+ Starter.skmt.ExecNonQuery($"insert into CONTROL_KMS (PLACAS, OPERADOR, RUTA, KMS_INICIAL, KMS_FINAL) values ('${et_placas.text}', '${et_operador.text}', '${et_rutaReparto.text}', '${et_kmsInicial.text}', '${et_kmsFinal.text}')"$)
+End Sub
+
+Private Sub pnlPreview_Click
+
+End Sub
+
+Private Sub p_camara_Click
+
+End Sub
+
+Private Sub b_escanPlacas_Click
+ ime.HideKeyboard
+ codigoBuscado = "placas"
+ Subs.panelVisible(p_camara, 0, 0)
+ If Capturing = False Then
+ p_camara.Visible = True
+ StartCamera
+ Else
+ p_camara.Visible = False
+ StopCamera
+ End If
+End Sub
+
+Private Sub b_escanOperador_Click
+ ime.HideKeyboard
+ codigoBuscado = "operador"
+ Subs.panelVisible(p_camara, 0, 0)
+ If Capturing = False Then
+ p_camara.Visible = True
+ StartCamera
+ Else
+ p_camara.Visible = False
+ StopCamera
+ End If
+End Sub
+
+Private Sub b_escanRuta_Click
+ ime.HideKeyboard
+ codigoBuscado = "ruta"
+ Subs.panelVisible(p_camara, 0, 0)
+ If Capturing = False Then
+ p_camara.Visible = True
+ StartCamera
+ Else
+ p_camara.Visible = False
+ StopCamera
+ End If
+End Sub
\ No newline at end of file
diff --git a/B4A/C_UpdateAvailable.bas b/B4A/C_UpdateAvailable.bas
new file mode 100644
index 0000000..62c83f8
--- /dev/null
+++ b/B4A/C_UpdateAvailable.bas
@@ -0,0 +1,74 @@
+B4A=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=11.5
+@EndOfDesignText@
+Sub Class_Globals
+ Private Root As B4XView 'ignore
+ Private xui As XUI 'ignore
+End Sub
+
+'You can add more parameters here.
+Public Sub Initialize As Object
+ Return Me
+End Sub
+
+'This event will be called once, before the page becomes visible.
+Private Sub B4XPage_Created (Root1 As B4XView)
+ Root = Root1
+ 'load the layout to Root
+ Root.Color = Colors.Transparent
+End Sub
+
+Sub B4XPage_Appear
+ Try
+ Do While Not(CanRequestPackageInstalls)
+ MsgboxAsync($"Por favor permita que ${Application.PackageName} instale actualizaciones"$, "Instalar actualización")
+ Wait For Msgbox_Result(Result As Int)
+ Dim in As Intent
+ in.Initialize("android.settings.MANAGE_UNKNOWN_APP_SOURCES", "package:" & Application.PackageName)
+ StartActivity(in)
+ Loop
+ Catch
+ Log("updateAvailable() Error - " & LastException.Message)
+ End Try
+ If appUpdater.newApp.update Then
+ ofreceActualizacion
+ Else
+ sinActualizacion
+ End If
+End Sub
+
+'////////////////////////////////////////////////////////////////////////////////////////////
+'//// Esta es una actividad usada por el servicio appUpdater para mostrar notificaciones
+'//// cuando hay alguna actualizacion de apk.
+'////////////////////////////////////////////////////////////////////////////////////////////
+
+
+public Sub CanRequestPackageInstalls As Boolean
+ ' // https://www.b4x.com/android/forum/threads/version-safe-apk-installation.87667/#content
+ Dim ctxt As JavaObject
+ ctxt.InitializeContext
+ Dim PackageManager As JavaObject = ctxt.RunMethod("getPackageManager", Null)
+ Return PackageManager.RunMethod("canRequestPackageInstalls", Null)
+End Sub
+
+Sub ofreceActualizacion
+ If Msgbox2(appUpdater.newApp.newMsg,"Actualización disponible","Si","","No",Null) = DialogResponse.Positive Then 'ignore
+' StartService(DownloadService)
+ CallSubDelayed(appUpdater, "download_newApk")
+' ToastMessageShow("Descargando actualización", True)
+ End If
+ B4XPages.MainPage.ocultaProgreso
+ StartActivity(Main)
+' Activity.Finish
+ B4XPages.ShowPage("Login")
+End Sub
+
+Sub sinActualizacion
+ Msgbox(appUpdater.newApp.okMsg, "Aplicación al corriente") 'ignore
+' StartActivity(Main)
+ B4XPages.MainPage.ocultaProgreso
+ B4XPages.ShowPage("Login")
+End Sub
\ No newline at end of file
diff --git a/B4A/CameraExClass.bas b/B4A/CameraExClass.bas
new file mode 100644
index 0000000..976371b
--- /dev/null
+++ b/B4A/CameraExClass.bas
@@ -0,0 +1,414 @@
+B4A=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=7.01
+@EndOfDesignText@
+'Class module
+'version 1.30
+'See this page for the list of constants:
+'http://developer.android.com/intl/fr/reference/android/hardware/Camera.Parameters.html
+'Note that you should use the constant values instead of the names.
+
+' Agregar a Main la siguientes lienas en Globals
+'
+' Type CameraInfoAndId (CameraInfo As Object, Id As Int)
+' Type CameraSize (Width As Int, Height As Int)
+'
+' Agregar en main
+' #AdditionalJar: com.google.android.gms:play-services-vision
+
+'Necesita las librerias XUI y XUI Views
+'
+
+Sub Class_Globals
+ Private nativeCam As Object
+ Private cam As Camera
+ Private r As Reflector
+ Private target As Object
+ Private event As String
+ Public Front As Boolean
+ Private parameters As Object
+
+ Public PreviewOrientation As Int
+End Sub
+
+Public Sub Initialize (Panel1 As Panel, FrontCamera As Boolean, TargetModule As Object, EventName As String)
+ target = TargetModule
+ event = EventName
+ Front = FrontCamera
+ Dim id As Int
+ id = FindCamera(Front).id
+ If id = -1 Then
+ Front = Not(Front) 'try different camera
+ id = FindCamera(Front).id
+ If id = -1 Then
+ ToastMessageShow("No camera found.", True)
+ Return
+ End If
+ End If
+ cam.Initialize2(Panel1, "camera", id)
+End Sub
+
+Private Sub FindCamera (frontCamera As Boolean) As CameraInfoAndId
+ Dim ci As CameraInfoAndId
+ Dim cameraInfo As Object
+ Dim cameraValue As Int
+ Log("findCamera")
+ If frontCamera Then cameraValue = 1 Else cameraValue = 0
+ cameraInfo = r.CreateObject("android.hardware.Camera$CameraInfo")
+ Dim numberOfCameras As Int = r.RunStaticMethod("android.hardware.Camera", "getNumberOfCameras", Null, Null)
+ Log(r.target)
+ Log(numberOfCameras)
+ For i = 0 To numberOfCameras - 1
+ r.RunStaticMethod("android.hardware.Camera", "getCameraInfo", Array As Object(i, cameraInfo), _
+ Array As String("java.lang.int", "android.hardware.Camera$CameraInfo"))
+ r.target = cameraInfo
+ Log("facing: " & r.GetField("facing") & ", " & cameraValue)
+ If r.GetField("facing") = cameraValue Then 'ignore
+ ci.cameraInfo = r.target
+ ci.Id = i
+ Return ci
+ End If
+ Next
+ ci.id = -1
+ Return ci
+End Sub
+
+Private Sub SetDisplayOrientation
+ r.target = r.GetActivity
+ r.target = r.RunMethod("getWindowManager")
+ r.target = r.RunMethod("getDefaultDisplay")
+ r.target = r.RunMethod("getRotation")
+ Dim result, degrees As Int = r.target * 90
+ Dim ci As CameraInfoAndId = FindCamera(Front)
+ r.target = ci.CameraInfo
+ Dim orientation As Int = r.GetField("orientation")
+ If Front Then
+ PreviewOrientation = (orientation + degrees) Mod 360
+ result = PreviewOrientation
+ PreviewOrientation = (360 - PreviewOrientation) Mod 360
+ Else
+ PreviewOrientation = (orientation - degrees + 360) Mod 360
+ result = PreviewOrientation
+ Log("Preview Orientation: " & PreviewOrientation)
+ End If
+ r.target = nativeCam
+ r.RunMethod2("setDisplayOrientation", PreviewOrientation, "java.lang.int")
+ r.target = parameters
+ r.RunMethod2("setRotation", result, "java.lang.int")
+ CommitParameters
+End Sub
+
+Private Sub Camera_Ready (Success As Boolean)
+ If Success Then
+ r.target = cam
+ nativeCam = r.GetField("camera")
+ r.target = nativeCam
+ parameters = r.RunMethod("getParameters")
+ SetDisplayOrientation
+ Else
+ Log("success = false, " & LastException)
+ End If
+ CallSub2(target, event & "_ready", Success)
+End Sub
+'Uncomment this sub if you need to handle the Preview event
+Sub Camera_Preview (Data() As Byte)
+ If SubExists(target, event & "_preview") Then
+ CallSub2(target, event & "_preview", Data)
+ End If
+End Sub
+
+Public Sub TakePicture
+ cam.TakePicture
+End Sub
+
+Private Sub Camera_PictureTaken (Data() As Byte)
+ CallSub2(target, event & "_PictureTaken", Data)
+End Sub
+
+Public Sub StartPreview
+ cam.StartPreview
+End Sub
+
+Public Sub StopPreview
+ cam.StopPreview
+End Sub
+
+Public Sub Release
+ cam.Release
+End Sub
+
+'Saves the data received from PictureTaken event
+Public Sub SavePictureToFile(Data() As Byte, Dir As String, FileName As String)
+ Dim out As OutputStream = File.OpenOutput(Dir, FileName, False)
+ out.WriteBytes(Data, 0, Data.Length)
+ out.Close
+End Sub
+
+Public Sub SetParameter(Key As String, Value As String)
+ r.target = parameters
+ r.RunMethod3("set", Key, "java.lang.String", Value, "java.lang.String")
+End Sub
+
+Public Sub GetParameter(Key As String) As String
+ r.target = parameters
+ Return r.RunMethod2("get", Key, "java.lang.String")
+End Sub
+
+Public Sub CommitParameters
+ 'Try
+ r.target = nativeCam
+ r.RunMethod4("setParameters", Array As Object(parameters), Array As String("android.hardware.Camera$Parameters"))
+ 'Catch
+ ' ToastMessageShow("Error setting parameters.", True)
+ ' Log(LastException)
+ ' End Try
+End Sub
+
+Public Sub GetColorEffect As String
+ Return GetParameter("effect")
+End Sub
+
+Public Sub SetColorEffect(Effect As String)
+ SetParameter("effect", Effect)
+End Sub
+
+Public Sub GetSupportedPreviewSizes As CameraSize()
+ r.target = parameters
+ Dim list1 As List = r.RunMethod("getSupportedPreviewSizes")
+ Dim cs(list1.Size) As CameraSize
+ For i = 0 To list1.Size - 1
+ r.target = list1.get(i)
+ cs(i).Width = r.GetField("width")
+ cs(i).Height = r.GetField("height")
+ Next
+ Return cs
+End Sub
+
+Public Sub SetPreviewSize(Width As Int, Height As Int)
+ r.target = parameters
+ r.RunMethod3("setPreviewSize", Width, "java.lang.int", Height, "java.lang.int")
+End Sub
+Public Sub GetSupportedPicturesSizes As CameraSize()
+ r.target = parameters
+ Dim list1 As List = r.RunMethod("getSupportedPictureSizes")
+ Dim cs(list1.Size) As CameraSize
+ For i = 0 To list1.Size - 1
+ r.target = list1.get(i)
+ cs(i).Width = r.GetField("width")
+ cs(i).Height = r.GetField("height")
+ Next
+ Return cs
+End Sub
+
+Public Sub SetPictureSize(Width As Int, Height As Int)
+ r.target = parameters
+ r.RunMethod3("setPictureSize", Width, "java.lang.int", Height, "java.lang.int")
+End Sub
+
+Public Sub SetJpegQuality(Quality As Int)
+ r.target = parameters
+ r.RunMethod2("setJpegQuality", Quality, "java.lang.int")
+End Sub
+
+Public Sub SetFlashMode(Mode As String)
+ r.target = parameters
+ r.RunMethod2("setFlashMode", Mode, "java.lang.String")
+End Sub
+
+Public Sub GetFlashMode As String
+ r.target = parameters
+ Return r.RunMethod("getFlashMode")
+End Sub
+
+Public Sub GetSupportedFlashModes As List
+ r.target = parameters
+ Return r.RunMethod("getSupportedFlashModes")
+End Sub
+
+Public Sub GetSupportedColorEffects As List
+ r.target = parameters
+ Return r.RunMethod("getSupportedColorEffects")
+End Sub
+
+'Returns a list with the supported preview fps. Each item in the list is an array of two ints (minimum value and maximum value).
+Public Sub GetSupportedPreviewFpsRange As List
+ r.target = parameters
+ Return r.RunMethod("getSupportedPreviewFpsRange")
+End Sub
+'Returns the current preview fps range.
+'Range is a two elements array. The minimum value and maximum value will be stored in this array.
+Public Sub GetPreviewFpsRange(Range() As Int)
+ r.target = parameters
+ r.RunMethod4("getPreviewFpsRange", Array As Object(Range), Array As String("[I"))
+End Sub
+
+Public Sub SetPreviewFpsRange(MinValue As Int, MaxValue As Int)
+ r.target = parameters
+ r.RunMethod4("setPreviewFpsRange", Array As Object(MinValue, MaxValue), _
+ Array As String("java.lang.int", "java.lang.int"))
+End Sub
+
+Public Sub GetPreviewSize As CameraSize
+ r.target = parameters
+ r.target = r.RunMethod("getPreviewSize")
+ Dim cs As CameraSize
+ cs.Width = r.GetField("width")
+ cs.Height = r.GetField("height")
+ Return cs
+End Sub
+
+Public Sub GetPictureSize As CameraSize
+ r.target = parameters
+ r.target = r.RunMethod("getPictureSize")
+ Dim cs As CameraSize
+ cs.Width = r.GetField("width")
+ cs.Height = r.GetField("height")
+ Return cs
+End Sub
+
+'Converts a preview image formatted in YUV format to JPEG.
+'Note that you should not save every preview image as it will slow down the whole process.
+Public Sub PreviewImageToJpeg(data() As Byte, quality As Int) As Byte()
+ Dim size, previewFormat As Object
+ r.target = parameters
+ size = r.RunMethod("getPreviewSize")
+ previewFormat = r.RunMethod("getPreviewFormat")
+ r.target = size
+ Dim width = r.GetField("width"), height = r.GetField("height") As Int
+ Dim yuvImage As Object = r.CreateObject2("android.graphics.YuvImage", _
+ Array As Object(data, previewFormat, width, height, Null), _
+ Array As String("[B", "java.lang.int", "java.lang.int", "java.lang.int", "[I"))
+ r.target = yuvImage
+ Dim rect1 As Rect
+ rect1.Initialize(0, 0, r.RunMethod("getWidth"), r.RunMethod("getHeight"))
+ Dim out As OutputStream
+ out.InitializeToBytesArray(100)
+ r.RunMethod4("compressToJpeg", Array As Object(rect1, quality, out), _
+ Array As String("android.graphics.Rect", "java.lang.int", "java.io.OutputStream"))
+
+ Return out.ToBytesArray
+End Sub
+
+Public Sub GetSupportedFocusModes As List
+ r.target = parameters
+ Return r.RunMethod("getSupportedFocusModes")
+End Sub
+
+Public Sub SetContinuousAutoFocus
+ Dim modes As List = GetSupportedFocusModes
+ If modes.IndexOf("continuous-picture") > -1 Then
+ SetFocusMode("continuous-picture")
+ Else If modes.IndexOf("continuous-video") > -1 Then
+ SetFocusMode("continuous-video")
+ Else
+ Log("Continuous focus mode is not available")
+ End If
+End Sub
+
+Public Sub SetFocusMode(Mode As String)
+ r.target = parameters
+ r.RunMethod2("setFocusMode", Mode, "java.lang.String")
+End Sub
+
+Public Sub GetFocusDistances As Float()
+ Dim F(3) As Float
+ r.target = parameters
+ r.RunMethod4("getFocusDistances", Array As Object(F), Array As String("[F"))
+ Return F
+End Sub
+
+Public Sub GetSupportedPictureFormats As List
+ r.target = parameters
+ Return r.RunMethod("getSupportedPictureFormats")
+End Sub
+'This method should only be called if you need to immediately release the camera.
+'For example if you need to start another application that depends on the camera.
+Public Sub CloseNow
+ cam.Release
+ r.target = cam
+ r.RunMethod2("releaseCameras", True, "java.lang.boolean")
+End Sub
+'Calls AutoFocus and then takes the picture if focus was successfull.
+Public Sub FocusAndTakePicture
+ cam.AutoFocus
+End Sub
+
+
+Private Sub Camera_FocusDone (Success As Boolean)
+ If Success Then
+ Sleep(100)
+ TakePicture
+ Else
+ Log("AutoFocus error.")
+ End If
+End Sub
+
+Public Sub IsZoomSupported As Boolean
+ r.target = parameters
+ Return r.RunMethod("isZoomSupported")
+End Sub
+
+Public Sub GetMaxZoom As Int
+ r.target = parameters
+ Return r.RunMethod("getMaxZoom")
+End Sub
+
+Public Sub getZoom() As Int
+ r.target = parameters
+ Return r.RunMethod("getZoom")
+End Sub
+
+Public Sub setZoom(ZoomValue As Int)
+ r.target = parameters
+ r.RunMethod2("setZoom", ZoomValue, "java.lang.int")
+End Sub
+
+Public Sub getExposureCompensation As Int
+ r.target = parameters
+ Return r.RunMethod("getExposureCompensation")
+End Sub
+
+Public Sub setExposureCompensation(v As Int)
+ r.target = parameters
+ r.RunMethod2("setExposureCompensation", v, "java.lang.int")
+End Sub
+
+Public Sub getMinExposureCompensation As Int
+ r.target = parameters
+ Return r.RunMethod("getMinExposureCompensation")
+End Sub
+
+Public Sub getMaxExposureCompensation As Int
+ r.target = parameters
+ Return r.RunMethod("getMaxExposureCompensation")
+End Sub
+
+Public Sub SetFaceDetectionListener
+ Dim jo As JavaObject = nativeCam
+ Dim e As Object = jo.CreateEvent("android.hardware.Camera.FaceDetectionListener", "FaceDetection", Null)
+ jo.RunMethod("setFaceDetectionListener", Array(e))
+End Sub
+
+Private Sub FaceDetection_Event (MethodName As String, Args() As Object) As Object
+ Dim faces() As Object = Args(0)
+ For Each f As Object In faces
+ Dim jo As JavaObject = f
+ Dim faceRect As Rect = jo.GetField("rect") 'ignore
+ Next
+ Return Null
+End Sub
+
+
+
+Public Sub StartFaceDetection
+ Dim jo As JavaObject = nativeCam
+ jo.RunMethod("startFaceDetection", Null)
+End Sub
+
+Public Sub StopFaceDetection
+ Dim jo As JavaObject = nativeCam
+ jo.RunMethod("stopFaceDetection", Null)
+End Sub
+
diff --git a/B4A/DBRequestManager.bas b/B4A/DBRequestManager.bas
new file mode 100644
index 0000000..b3d83a1
--- /dev/null
+++ b/B4A/DBRequestManager.bas
@@ -0,0 +1,272 @@
+B4A=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Class
+Version=7.01
+@EndOfDesignText@
+'Class module
+Sub Class_Globals
+ Private mTarget As Object
+ Type DBResult (Tag As Object, Columns As Map, Rows As List)
+ Type DBCommand (Name As String, Parameters() As Object)
+ Private link As String
+ Private bc As ByteConverter
+ Private T_NULL = 0, T_STRING = 1, T_SHORT = 2, T_INT = 3, T_LONG = 4, T_FLOAT = 5 _
+ ,T_DOUBLE = 6, T_BOOLEAN = 7, T_BLOB = 8 As Byte
+ Private VERSION As Float = 0.9
+ Private tempArray(1) As Object
+ Dim jobTagAnterior As String = "" 'Mod por CHV - 211023
+End Sub
+
+'Target - The module that handles JobDone (usually Me).
+'ConnectorLink - URL of the Java server.
+Public Sub Initialize (Target As Object, ConnectorLink As String)
+ mTarget = Target
+ link = ConnectorLink
+End Sub
+
+'Sends a query request.
+'Command - Query name and parameters.
+'Limit - Maximum rows to return or 0 for no limit.
+'Tag - An object that will be returned in the result.
+Public Sub ExecuteQuery(Command As DBCommand, Limit As Int, Tag As Object)
+ Dim j As HttpJob
+ Dim ms As OutputStream
+ Dim out2 As OutputStream = StartJob(j,ms, Tag)
+
+ WriteObject(Command.Name, out2)
+ WriteInt(Limit, out2)
+ WriteList(Command.Parameters, out2)
+ out2.Close
+ j.PostBytes(link & "?method=query", ms.ToBytesArray)
+End Sub
+
+'Executes a batch of (non-select) commands.
+'ListOfCommands - List of the commands that will be executes.
+'Tag - An object that will be returned in the result.
+Public Sub ExecuteBatch(ListOfCommands As List, Tag As Object)
+ Dim j As HttpJob
+ Dim ms As OutputStream
+ Dim out2 As OutputStream = StartJob(j,ms, Tag)
+ WriteInt(ListOfCommands.Size, out2)
+ For Each Command As DBCommand In ListOfCommands
+ WriteObject(Command.Name, out2)
+ WriteList(Command.Parameters, out2)
+ Next
+ out2.Close
+ j.PostBytes(link & "?method=batch", ms.ToBytesArray)
+End Sub
+
+'Similar to ExecuteBatch. Sends a single command.
+Public Sub ExecuteCommand(Command As DBCommand, Tag As Object)
+ ExecuteBatch(Array As DBCommand(Command), Tag)
+End Sub
+
+Private Sub StartJob(j As HttpJob, MemoryStream As OutputStream, Tag As Object) As OutputStream
+ j.Initialize("DBRequest", mTarget)
+ j.Tag = Tag
+ MemoryStream.InitializeToBytesArray(0)
+ Dim compress As CompressedStreams
+ Dim out As OutputStream = compress.WrapOutputStream(MemoryStream, "gzip")
+ WriteObject(VERSION, out)
+ Return out
+End Sub
+
+Private Sub WriteList(Parameters As List, out As OutputStream)
+ Dim data() As Byte
+ If Parameters = Null Or Parameters.IsInitialized = False Then
+ Dim Parameters As List
+ Parameters.Initialize
+ End If
+ data = bc.IntsToBytes(Array As Int(Parameters.Size))
+ out.WriteBytes(data, 0, data.Length)
+ For Each o As Object In Parameters
+ WriteObject(o, out)
+ Next
+End Sub
+
+Private Sub WriteObject(o As Object, out As OutputStream)
+ Dim data() As Byte
+ tempArray(0) = o
+ If tempArray(0) = Null Then
+ out.WriteBytes(Array As Byte(T_NULL), 0, 1)
+ Else If tempArray(0) Is Short Then
+ out.WriteBytes(Array As Byte(T_SHORT), 0, 1)
+ data = bc.ShortsToBytes(Array As Short(o))
+ Else If tempArray(0) Is Int Then
+ out.WriteBytes(Array As Byte(T_INT), 0, 1)
+ data = bc.IntsToBytes(Array As Int(o))
+ Else If tempArray(0) Is Float Then
+ out.WriteBytes(Array As Byte(T_FLOAT), 0, 1)
+ data = bc.FloatsToBytes(Array As Float(o))
+ Else If tempArray(0) Is Double Then
+ out.WriteBytes(Array As Byte(T_DOUBLE), 0, 1)
+ data = bc.DoublesToBytes(Array As Double(o))
+ Else If tempArray(0) Is Long Then
+ out.WriteBytes(Array As Byte(T_LONG), 0, 1)
+ data = bc.LongsToBytes(Array As Long(o))
+ Else If tempArray(0) Is Boolean Then
+ out.WriteBytes(Array As Byte(T_BOOLEAN), 0, 1)
+ Dim b As Boolean = 0
+ Dim data(1) As Byte
+ If b Then data(0) = 1 Else data(0) = 0
+ Else If GetType(tempArray(0)) = "[B" Then
+ data = o
+ out.WriteBytes(Array As Byte(T_BLOB), 0, 1)
+ WriteInt(data.Length, out)
+ Else 'If o Is String Then (treat all other values as string)
+ out.WriteBytes(Array As Byte(T_STRING), 0, 1)
+ data = bc.StringToBytes(o, "UTF8")
+ WriteInt(data.Length, out)
+ End If
+ If data.Length > 0 Then out.WriteBytes(data, 0, data.Length)
+End Sub
+
+Private Sub ReadObject(In As InputStream) As Object
+ Dim data(1) As Byte
+ In.ReadBytes(data, 0, 1)
+ Select data(0)
+ Case T_NULL
+ Return Null
+ Case T_SHORT
+ Dim data(2) As Byte
+ Return bc.ShortsFromBytes(ReadBytesFully(In, data, data.Length))(0)
+ Case T_INT
+ Dim data(4) As Byte
+ Return bc.IntsFromBytes(ReadBytesFully(In, data, data.Length))(0)
+ Case T_LONG
+ Dim data(8) As Byte
+ Return bc.LongsFromBytes(ReadBytesFully(In, data, data.Length))(0)
+ Case T_FLOAT
+ Dim data(4) As Byte
+ Return bc.FloatsFromBytes(ReadBytesFully(In, data, data.Length))(0)
+ Case T_DOUBLE
+ Dim data(8) As Byte
+ Return bc.DoublesFromBytes(ReadBytesFully(In, data, data.Length))(0)
+ Case T_BOOLEAN
+ Dim b As Byte = ReadByte(In)
+ Return b = 1
+ Case T_BLOB
+ Dim len As Int = ReadInt(In)
+ Dim data(len) As Byte
+ Return ReadBytesFully(In, data, data.Length)
+ Case Else
+ Dim len As Int = ReadInt(In)
+ Dim data(len) As Byte
+ ReadBytesFully(In, data, data.Length)
+ Return BytesToString(data, 0, data.Length, "UTF8")
+ End Select
+End Sub
+
+Private Sub ReadBytesFully(In As InputStream, Data() As Byte, Len As Int) As Byte()
+ Dim count = 0, read As Int
+ Do While count < Len And read > -1
+ read = In.ReadBytes(Data, count, Len - count)
+ count = count + read
+ Loop
+ Return Data
+End Sub
+
+Private Sub WriteInt(i As Int, out As OutputStream)
+ Dim data() As Byte
+ data = bc.IntsToBytes(Array As Int(i))
+ out.WriteBytes(data, 0, data.Length)
+End Sub
+
+Private Sub ReadInt(In As InputStream) As Int
+ Dim data(4) As Byte
+ Return bc.IntsFromBytes(ReadBytesFully(In, data, data.Length))(0)
+End Sub
+
+Private Sub ReadByte(In As InputStream) As Byte
+ Dim data(1) As Byte
+ In.ReadBytes(data, 0, 1)
+ Return data(0)
+End Sub
+
+'Handles the Job result and returns a DBResult.
+Public Sub HandleJob(Job As HttpJob) As DBResult
+' Dim start As Long = DateTime.Now
+ Dim In As InputStream = Job.GetInputStream
+ Dim cs As CompressedStreams
+ In = cs.WrapInputStream(In, "gzip")
+ Dim serverVersion As Float = ReadObject(In) 'ignore
+ Dim method As String = ReadObject(In)
+ Dim table As DBResult
+ table.Initialize
+ table.Columns.Initialize
+ table.rows.Initialize
+ table.Tag = Job.Tag
+ If jobTagAnterior <> Job.Tag Then LogColor("HandleJob: '"&Job.Tag&"'", Colors.Blue) 'Mod por CHV - 211023
+ jobTagAnterior = Job.Tag 'Mod por CHV - 211023
+ If method = "query" Then
+ Dim numberOfColumns As Int = ReadInt(In)
+ For i = 0 To numberOfColumns - 1
+ table.Columns.Put(ReadObject(In), i)
+ Next
+ Do While ReadByte(In) = 1
+ Dim rowObjects(numberOfColumns) As Object
+ table.rows.Add(rowObjects)
+ For col = 0 To numberOfColumns - 1
+ Dim o As Object = ReadObject(In)
+ rowObjects(col) = o
+ Next
+ Loop
+ Else If method = "batch" Then
+ table.Columns.Put("AffectedRows", 0)
+ Dim rows As Int = ReadInt(In)
+ For i = 0 To rows - 1
+ table.rows.Add(Array As Object(ReadInt(In)))
+ Next
+ End If
+ In.Close
+ Return table
+End Sub
+
+'Reads a file and returns the file as a bytes array.
+Public Sub FileToBytes(Dir As String, FileName As String) As Byte()
+ Dim out As OutputStream
+ out.InitializeToBytesArray(0)
+ Dim In As InputStream = File.OpenInput(Dir, FileName)
+ File.Copy2(In, out)
+ out.Close
+ Return out.ToBytesArray
+End Sub
+
+'Converts an image to a bytes array (for BLOB fields).
+Public Sub ImageToBytes(Image As Bitmap) As Byte()
+ Dim out As OutputStream
+ out.InitializeToBytesArray(0)
+ Image.WriteToStream(out, 100, "JPEG")
+ out.Close
+ Return out.ToBytesArray
+End Sub
+'Converts a bytes array to an image (for BLOB fields).
+Public Sub BytesToImage(bytes() As Byte) As Bitmap
+ Dim In As InputStream
+ In.InitializeFromBytesArray(bytes, 0, bytes.Length)
+ Dim bmp As Bitmap
+ bmp.Initialize2(In)
+ Return bmp
+End Sub
+
+'Prints the table to the logs.
+Public Sub PrintTable(Table As DBResult)
+ Log("Tag: " & Table.Tag & ", Columns: " & Table.Columns.Size & ", Rows: " & Table.Rows.Size)
+ Dim sb As StringBuilder
+ sb.Initialize
+ For Each col In Table.Columns.Keys
+ sb.Append(col).Append(TAB)
+ Next
+ Log(sb.ToString)
+ For Each row() As Object In Table.Rows
+ Dim sb As StringBuilder
+ sb.Initialize
+ For Each record As Object In row
+ sb.Append(record).Append(TAB)
+ Next
+ ToastMessageShow(sb.ToString, True)
+ Next
+End Sub
+
+
\ No newline at end of file
diff --git a/B4A/Files/alert2.png b/B4A/Files/alert2.png
new file mode 100644
index 0000000..44d3b7e
Binary files /dev/null and b/B4A/Files/alert2.png differ
diff --git a/B4A/Files/alerta.jpg b/B4A/Files/alerta.jpg
new file mode 100644
index 0000000..5edc6ba
Binary files /dev/null and b/B4A/Files/alerta.jpg differ
diff --git a/B4A/Files/buscar.bal b/B4A/Files/buscar.bal
new file mode 100644
index 0000000..afb40f4
Binary files /dev/null and b/B4A/Files/buscar.bal differ
diff --git a/B4A/Files/cliente.bal b/B4A/Files/cliente.bal
new file mode 100644
index 0000000..8806a17
Binary files /dev/null and b/B4A/Files/cliente.bal differ
diff --git a/B4A/Files/clientes.bal b/B4A/Files/clientes.bal
new file mode 100644
index 0000000..0434eaa
Binary files /dev/null and b/B4A/Files/clientes.bal differ
diff --git a/B4A/Files/dbc.png b/B4A/Files/dbc.png
new file mode 100644
index 0000000..1519c8c
Binary files /dev/null and b/B4A/Files/dbc.png differ
diff --git a/B4A/Files/detalle_promo.bal b/B4A/Files/detalle_promo.bal
new file mode 100644
index 0000000..14ef3fb
Binary files /dev/null and b/B4A/Files/detalle_promo.bal differ
diff --git a/B4A/Files/detalleventa.bal b/B4A/Files/detalleventa.bal
new file mode 100644
index 0000000..929cd75
Binary files /dev/null and b/B4A/Files/detalleventa.bal differ
diff --git a/B4A/Files/durakelo1.png b/B4A/Files/durakelo1.png
new file mode 100644
index 0000000..00cb434
Binary files /dev/null and b/B4A/Files/durakelo1.png differ
diff --git a/B4A/Files/engrane.jpg b/B4A/Files/engrane.jpg
new file mode 100644
index 0000000..01159de
Binary files /dev/null and b/B4A/Files/engrane.jpg differ
diff --git a/B4A/Files/fondo_kmt.jpg b/B4A/Files/fondo_kmt.jpg
new file mode 100644
index 0000000..4055faf
Binary files /dev/null and b/B4A/Files/fondo_kmt.jpg differ
diff --git a/B4A/Files/foto.bal b/B4A/Files/foto.bal
new file mode 100644
index 0000000..9cf56b7
Binary files /dev/null and b/B4A/Files/foto.bal differ
diff --git a/B4A/Files/guardagestion.bal b/B4A/Files/guardagestion.bal
new file mode 100644
index 0000000..41d52cf
Binary files /dev/null and b/B4A/Files/guardagestion.bal differ
diff --git a/B4A/Files/guna_viejo.png b/B4A/Files/guna_viejo.png
new file mode 100644
index 0000000..a0c3190
Binary files /dev/null and b/B4A/Files/guna_viejo.png differ
diff --git a/B4A/Files/guna_viejo2.png b/B4A/Files/guna_viejo2.png
new file mode 100644
index 0000000..d937027
Binary files /dev/null and b/B4A/Files/guna_viejo2.png differ
diff --git a/B4A/Files/historico.bal b/B4A/Files/historico.bal
new file mode 100644
index 0000000..929cd75
Binary files /dev/null and b/B4A/Files/historico.bal differ
diff --git a/B4A/Files/infonavit1.jpg b/B4A/Files/infonavit1.jpg
new file mode 100644
index 0000000..b8cce4c
Binary files /dev/null and b/B4A/Files/infonavit1.jpg differ
diff --git a/B4A/Files/itembuttonblue.png b/B4A/Files/itembuttonblue.png
new file mode 100644
index 0000000..af4dc0b
Binary files /dev/null and b/B4A/Files/itembuttonblue.png differ
diff --git a/B4A/Files/kelloggs.png b/B4A/Files/kelloggs.png
new file mode 100644
index 0000000..4debf15
Binary files /dev/null and b/B4A/Files/kelloggs.png differ
diff --git a/B4A/Files/keymon_logo.png b/B4A/Files/keymon_logo.png
new file mode 100644
index 0000000..945e546
Binary files /dev/null and b/B4A/Files/keymon_logo.png differ
diff --git a/B4A/Files/kmt.db b/B4A/Files/kmt.db
new file mode 100644
index 0000000..346ba1a
Binary files /dev/null and b/B4A/Files/kmt.db differ
diff --git a/B4A/Files/kmt.dbx b/B4A/Files/kmt.dbx
new file mode 100644
index 0000000..de16c89
Binary files /dev/null and b/B4A/Files/kmt.dbx differ
diff --git a/B4A/Files/login.bal b/B4A/Files/login.bal
new file mode 100644
index 0000000..add0b8f
Binary files /dev/null and b/B4A/Files/login.bal differ
diff --git a/B4A/Files/logo guna_192x192.png b/B4A/Files/logo guna_192x192.png
new file mode 100644
index 0000000..4dcd00c
Binary files /dev/null and b/B4A/Files/logo guna_192x192.png differ
diff --git a/B4A/Files/logo sanfer.jpg b/B4A/Files/logo sanfer.jpg
new file mode 100644
index 0000000..791fe4f
Binary files /dev/null and b/B4A/Files/logo sanfer.jpg differ
diff --git a/B4A/Files/logo_exitus1.jpg b/B4A/Files/logo_exitus1.jpg
new file mode 100644
index 0000000..b8cce4c
Binary files /dev/null and b/B4A/Files/logo_exitus1.jpg differ
diff --git a/B4A/Files/logo_mariana.jpg b/B4A/Files/logo_mariana.jpg
new file mode 100644
index 0000000..8803ba9
Binary files /dev/null and b/B4A/Files/logo_mariana.jpg differ
diff --git a/B4A/Files/mainpage.bal b/B4A/Files/mainpage.bal
new file mode 100644
index 0000000..acba0d3
Binary files /dev/null and b/B4A/Files/mainpage.bal differ
diff --git a/B4A/Files/malo.jpg b/B4A/Files/malo.jpg
new file mode 100644
index 0000000..bbf3c87
Binary files /dev/null and b/B4A/Files/malo.jpg differ
diff --git a/B4A/Files/mapa.bal b/B4A/Files/mapa.bal
new file mode 100644
index 0000000..d9624ae
Binary files /dev/null and b/B4A/Files/mapa.bal differ
diff --git a/B4A/Files/mapa_cliente.bal b/B4A/Files/mapa_cliente.bal
new file mode 100644
index 0000000..f8fc4a2
Binary files /dev/null and b/B4A/Files/mapa_cliente.bal differ
diff --git a/B4A/Files/mapa_rutas.bal b/B4A/Files/mapa_rutas.bal
new file mode 100644
index 0000000..dfcb856
Binary files /dev/null and b/B4A/Files/mapa_rutas.bal differ
diff --git a/B4A/Files/mariana_logo_192x192.jpg b/B4A/Files/mariana_logo_192x192.jpg
new file mode 100644
index 0000000..73ab234
Binary files /dev/null and b/B4A/Files/mariana_logo_192x192.jpg differ
diff --git a/B4A/Files/no_venta.bal b/B4A/Files/no_venta.bal
new file mode 100644
index 0000000..216c095
Binary files /dev/null and b/B4A/Files/no_venta.bal differ
diff --git a/B4A/Files/nuevocliente.bal b/B4A/Files/nuevocliente.bal
new file mode 100644
index 0000000..584381c
Binary files /dev/null and b/B4A/Files/nuevocliente.bal differ
diff --git a/B4A/Files/pedido.bal b/B4A/Files/pedido.bal
new file mode 100644
index 0000000..defff34
Binary files /dev/null and b/B4A/Files/pedido.bal differ
diff --git a/B4A/Files/planfia_logo.png b/B4A/Files/planfia_logo.png
new file mode 100644
index 0000000..680ffd0
Binary files /dev/null and b/B4A/Files/planfia_logo.png differ
diff --git a/B4A/Files/planfia_logo_old.png b/B4A/Files/planfia_logo_old.png
new file mode 100644
index 0000000..4adb130
Binary files /dev/null and b/B4A/Files/planfia_logo_old.png differ
diff --git a/B4A/Files/planfia_logo_old2.png b/B4A/Files/planfia_logo_old2.png
new file mode 100644
index 0000000..316f337
Binary files /dev/null and b/B4A/Files/planfia_logo_old2.png differ
diff --git a/B4A/Files/principal.bal b/B4A/Files/principal.bal
new file mode 100644
index 0000000..770b979
Binary files /dev/null and b/B4A/Files/principal.bal differ
diff --git a/B4A/Files/proditem.bal b/B4A/Files/proditem.bal
new file mode 100644
index 0000000..210f3ed
Binary files /dev/null and b/B4A/Files/proditem.bal differ
diff --git a/B4A/Files/productos.bal b/B4A/Files/productos.bal
new file mode 100644
index 0000000..9e4df4a
Binary files /dev/null and b/B4A/Files/productos.bal differ
diff --git a/B4A/Files/profina.jpg b/B4A/Files/profina.jpg
new file mode 100644
index 0000000..f092f0f
Binary files /dev/null and b/B4A/Files/profina.jpg differ
diff --git a/B4A/Files/profina.png b/B4A/Files/profina.png
new file mode 100644
index 0000000..d307055
Binary files /dev/null and b/B4A/Files/profina.png differ
diff --git a/B4A/Files/sync.png b/B4A/Files/sync.png
new file mode 100644
index 0000000..ff7d32e
Binary files /dev/null and b/B4A/Files/sync.png differ
diff --git a/B4A/Files/tabulador.bal b/B4A/Files/tabulador.bal
new file mode 100644
index 0000000..d4f90be
Binary files /dev/null and b/B4A/Files/tabulador.bal differ
diff --git a/B4A/Files/telefonos.bal b/B4A/Files/telefonos.bal
new file mode 100644
index 0000000..7c1d382
Binary files /dev/null and b/B4A/Files/telefonos.bal differ
diff --git a/B4A/Files/thumbs.db b/B4A/Files/thumbs.db
new file mode 100644
index 0000000..49c9b96
Binary files /dev/null and b/B4A/Files/thumbs.db differ
diff --git a/B4A/Guna_CK.b4a b/B4A/Guna_CK.b4a
new file mode 100644
index 0000000..36280e4
--- /dev/null
+++ b/B4A/Guna_CK.b4a
@@ -0,0 +1,200 @@
+Build1=Default,guna_ck.keymon.lat,HU2_PUBLIC
+File1=alert2.png
+File10=engrane.jpg
+File11=fondo_kmt.jpg
+File12=foto.bal
+File13=guardagestion.bal
+File14=guna_viejo.png
+File15=guna_viejo2.png
+File16=historico.bal
+File17=infonavit1.jpg
+File18=itembuttonblue.png
+File19=kelloggs.png
+File2=alerta.jpg
+File20=keymon_logo.png
+File21=kmt.db
+File22=kmt.dbx
+File23=login.bal
+File24=Logo Guna_192x192.png
+File25=logo sanfer.jpg
+File26=logo_exitus1.jpg
+File27=logo_mariana.jpg
+File28=MainPage.bal
+File29=malo.jpg
+File3=buscar.bal
+File30=mapa.bal
+File31=mapa_cliente.bal
+File32=mapa_rutas.bal
+File33=mariana_logo_192x192.jpg
+File34=no_venta.bal
+File35=nuevocliente.bal
+File36=pedido.bal
+File37=planfia_logo.png
+File38=planfia_logo_old.png
+File39=planfia_logo_old2.png
+File4=cliente.bal
+File40=principal.bal
+File41=proditem.bal
+File42=productos.bal
+File43=profina.jpg
+File44=PROFINA.png
+File45=sync.png
+File46=tabulador.bal
+File47=telefonos.bal
+File48=Thumbs.db
+File5=clientes.bal
+File6=dbc.png
+File7=detalle_promo.bal
+File8=detalleVenta.bal
+File9=durakelo1.png
+FileGroup1=Default Group
+FileGroup10=Default Group
+FileGroup11=Default Group
+FileGroup12=Default Group
+FileGroup13=Default Group
+FileGroup14=Default Group
+FileGroup15=Default Group
+FileGroup16=Default Group
+FileGroup17=Default Group
+FileGroup18=Default Group
+FileGroup19=Default Group
+FileGroup2=Default Group
+FileGroup20=Default Group
+FileGroup21=Default Group
+FileGroup22=Default Group
+FileGroup23=Default Group
+FileGroup24=Default Group
+FileGroup25=Default Group
+FileGroup26=Default Group
+FileGroup27=Default Group
+FileGroup28=Default Group
+FileGroup29=Default Group
+FileGroup3=Default Group
+FileGroup30=Default Group
+FileGroup31=Default Group
+FileGroup32=Default Group
+FileGroup33=Default Group
+FileGroup34=Default Group
+FileGroup35=Default Group
+FileGroup36=Default Group
+FileGroup37=Default Group
+FileGroup38=Default Group
+FileGroup39=Default Group
+FileGroup4=Default Group
+FileGroup40=Default Group
+FileGroup41=Default Group
+FileGroup42=Default Group
+FileGroup43=Default Group
+FileGroup44=Default Group
+FileGroup45=Default Group
+FileGroup46=Default Group
+FileGroup47=Default Group
+FileGroup48=Default Group
+FileGroup5=Default Group
+FileGroup6=Default Group
+FileGroup7=Default Group
+FileGroup8=Default Group
+FileGroup9=Default Group
+Group=Default Group
+Library1=appupdating
+Library10=phone
+Library11=randomaccessfile
+Library12=reflection
+Library13=runtimepermissions
+Library14=sql
+Library15=xcustomlistview
+Library16=xui
+Library17=xui views
+Library2=b4xpages
+Library3=bctoast
+Library4=byteconverter
+Library5=camera
+Library6=core
+Library7=fileprovider
+Library8=ime
+Library9=okhttputils2
+ManifestCode='This code will be applied to the manifest file during compilation.~\n~'You do not need to modify it in most cases.~\n~'See this link for for more information: https://www.b4x.com/forum/showthread.php?p=78136~\n~AddManifestText(~\n~~\n~)~\n~SetApplicationAttribute(android:icon, "@drawable/icon")~\n~SetApplicationAttribute(android:label, "$LABEL$")~\n~CreateResourceFromFile(Macro, Themes.LightTheme)~\n~'End of default text.~\n~~\n~''''' CAMBIA LA CLAVE API~\n~'AddApplicationText(~\n~'~\n~' ~\n~')~\n~~\n~'CreateResourceFromFile(Macro, FirebaseAnalytics.GooglePlayBase)~\n~SetApplicationAttribute(android:usesCleartextTraffic, "true")~\n~'AddManifestText()~\n~'AddPermission(android.permission.ACCESS_BACKGROUND_LOCATION)~\n~'AddManifestText()~\n~'AddManifestText()~\n~'AddManifestText() 'in order to access the device non-resettable identifiers such as IMEI and serial number.~\n~'AddManifestText()~\n~'/////////////// FLP y FBMessageing MOD Inicia /////////////////////~\n~'CreateResourceFromFile(Macro, FirebaseAnalytics.GooglePlayBase)~\n~'CreateResourceFromFile(Macro, FirebaseAnalytics.Firebase)~\n~'CreateResourceFromFile(Macro, FirebaseAnalytics.FirebaseAnalytics)~\n~'CreateResourceFromFile(Macro, FirebaseNotifications.FirebaseNotifications)~\n~'SetServiceAttribute(Tracker, android:foregroundServiceType, "location")~\n~'/////////////// FLP y FBMessageing MOD Termina /////////////////////~\n~~\n~'Si al cargar un mapa de google mande este error "java.lang.NoClassDefFoundError: Failed resolution of: Lorg/apache/http/ProtocolVersion". agregar la siguiente linea:~\n~AddApplicationText()~\n~~\n~'/////////////////////// App Updating ////////////////~\n~ AddManifestText(~\n~ )~\n~ AddApplicationText(~\n~ ~\n~ ~\n~ ~\n~ )~\n~ CreateResource(xml, provider_paths,~\n~ ~\n~ ~\n~ ~\n~ ~\n~ ~\n~ )~\n~AddManifestText()~\n~AddManifestText()~\n~AddManifestText()~\n~AddManifestText()~\n~~\n~AddPermission(android.permission.REQUEST_INSTALL_PACKAGES)~\n~AddPermission(android.permission.INTERNET)~\n~AddPermission(android.permission.INSTALL_PACKAGES)~\n~AddPermission(android.permission.READ_EXTERNAL_STORAGE)~\n~AddPermission(android.permission.WRITE_EXTERNAL_STORAGE)~\n~AddPermission(android.permission.READ_PHONE_STATE)~\n~AddPermission(android.permission.WAKE_LOCK)~\n~CreateResourceFromFile(Macro, JhsIceZxing1.CaturePortrait)~\n~ ~\n~SetApplicationAttribute(android:largeHeap, "true")~\n~~\n~
+Module1=appUpdater
+Module2=B4XMainPage
+Module3=C_Clientes
+Module4=C_Principal
+Module5=C_UpdateAvailable
+Module6=CameraExClass
+Module7=DBRequestManager
+Module8=Starter
+Module9=Subs
+NumberOfFiles=48
+NumberOfLibraries=17
+NumberOfModules=9
+Version=11.5
+@EndOfDesignText@
+#Region Project Attributes
+ #ApplicationLabel: Guna CK
+ #VersionCode: 1
+ #VersionName: 3.06.28
+ 'SupportedOrientations possible values: unspecified, landscape or portrait.
+ #SupportedOrientations: portrait
+ #CanInstallToExternalStorage: False
+ #AdditionalJar: com.android.support:support-v4
+ #AdditionalJar: com.google.android.gms:play-services-location
+ #BridgeLogger: True
+ #AdditionalJar: com.google.android.gms:play-services-vision
+#End Region
+
+#Region Activity Attributes
+ #FullScreen: False
+ #IncludeTitle: True
+#End Region
+
+Sub Process_Globals
+ Public ActionBarHomeClicked As Boolean
+End Sub
+
+Sub Globals
+ Type CameraInfoAndId (CameraInfo As Object, Id As Int)
+ Type CameraSize (Width As Int, Height As Int)
+End Sub
+
+Sub Activity_Create(FirstTime As Boolean)
+ Dim pm As B4XPagesManager
+ pm.Initialize(Activity)
+End Sub
+
+'Template version: B4A-1.01
+#Region Delegates
+
+Sub Activity_ActionBarHomeClick
+ ActionBarHomeClicked = True
+ B4XPages.Delegate.Activity_ActionBarHomeClick
+ ActionBarHomeClicked = False
+End Sub
+
+Sub Activity_KeyPress (KeyCode As Int) As Boolean
+ Return B4XPages.Delegate.Activity_KeyPress(KeyCode)
+End Sub
+
+Sub Activity_Resume
+ B4XPages.Delegate.Activity_Resume
+End Sub
+
+Sub Activity_Pause (UserClosed As Boolean)
+ B4XPages.Delegate.Activity_Pause
+End Sub
+
+Sub Activity_PermissionResult (Permission As String, Result As Boolean)
+ B4XPages.Delegate.Activity_PermissionResult(Permission, Result)
+End Sub
+
+Sub Create_Menu (Menu As Object)
+ B4XPages.Delegate.Create_Menu(Menu)
+End Sub
+
+#if Java
+public boolean _onCreateOptionsMenu(android.view.Menu menu) {
+ processBA.raiseEvent(null, "create_menu", menu);
+ return true;
+}
+#End If
+#End Region
+
+'Program code should go into B4XMainPage and other pages.
\ No newline at end of file
diff --git a/B4A/Guna_CK.b4a.meta b/B4A/Guna_CK.b4a.meta
new file mode 100644
index 0000000..5988fdf
--- /dev/null
+++ b/B4A/Guna_CK.b4a.meta
@@ -0,0 +1,33 @@
+ModuleBookmarks0=
+ModuleBookmarks1=
+ModuleBookmarks2=
+ModuleBookmarks3=
+ModuleBookmarks4=
+ModuleBookmarks5=
+ModuleBookmarks6=
+ModuleBookmarks7=
+ModuleBookmarks8=
+ModuleBookmarks9=
+ModuleBreakpoints0=
+ModuleBreakpoints1=
+ModuleBreakpoints2=
+ModuleBreakpoints3=
+ModuleBreakpoints4=
+ModuleBreakpoints5=
+ModuleBreakpoints6=
+ModuleBreakpoints7=
+ModuleBreakpoints8=
+ModuleBreakpoints9=
+ModuleClosedNodes0=
+ModuleClosedNodes1=
+ModuleClosedNodes2=2
+ModuleClosedNodes3=2
+ModuleClosedNodes4=1,5,7,8
+ModuleClosedNodes5=
+ModuleClosedNodes6=
+ModuleClosedNodes7=
+ModuleClosedNodes8=
+ModuleClosedNodes9=
+NavigationStack=Subs,fechaKMT,27,0,Subs,Process_Globals,16,0,Starter,Service_Create,37,3,C_Principal,b_escanPlacas_Click,245,0,C_Principal,b_guardar_Click,224,6,C_Principal,Camera1_Preview,222,0,C_Principal,Class_Globals,0,0,C_Principal,Initialize,40,0,C_Principal,B4XPage_Created,48,0,C_Principal,B4XPage_Appear,62,0,C_Principal,B4XPage_CloseRequest,91,0
+SelectedBuild=0
+VisibleModules=2,8,4,9,6
diff --git a/B4A/Starter.bas b/B4A/Starter.bas
new file mode 100644
index 0000000..814ecb4
--- /dev/null
+++ b/B4A/Starter.bas
@@ -0,0 +1,155 @@
+B4A=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Service
+Version=9.85
+@EndOfDesignText@
+#Region Service Attributes
+ #StartAtBoot: False
+ #ExcludeFromLibrary: True
+#End Region
+
+Sub Process_Globals
+ 'These global variables will be declared once when the application starts.
+ 'These variables can be accessed from all modules.
+ Public rp As RuntimePermissions
+' Public FLP As FusedLocationProvider
+ Private flpStarted As Boolean
+ Dim skmt As SQL
+ Dim ruta As String
+' Private BTAdmin As BluetoothAdmin
+ Public BluetoothState As Boolean
+ Dim Timer1 As Timer
+ Dim Interval As Int = 300
+ 'Para WebSockets
+' Dim monitor As Timer 'Lo usamos para monitorear los servicios Tracker y PushService
+' Dim monitorTicks As Int = 0
+ Dim trackerActividad As String = "501231235959"
+ Dim pushServiceActividad As String = "501231235959"
+ 'Para los Logs
+ Private logs As StringBuilder
+ Private logcat As LogCat
+ Public SharedFolder As String 'Para actualizar apk
+' Dim cedisLocation As Location
+ Dim reqManager As DBRequestManager
+ Dim server As String = "http://187.189.244.154:1787"
+ Dim muestraProgreso = 0
+End Sub
+
+Sub Service_Create
+ 'This is the program entry point.
+ 'This is a good place to load resources that are not specific to a single activity.
+ ruta = File.DirInternal 'Ruta de la base de datos por defecto.
+' If File.ExternalWritable Then ruta = rp.GetSafeDirDefaultExternal("") 'Si podemos escribir a la tarjeta, cambiamos la ruta.
+ If Not(File.Exists(ruta, "kmt.db")) Then File.Copy(File.DirAssets, "kmt.db", ruta, "kmt.db") 'Si no existe el archivo de la base de datos, lo copiamos.
+ Log(ruta)
+ Log(File.DirAssets)
+ skmt.Initialize(ruta,"kmt.db", True)
+' CallSubDelayed(PushService, "SubscribeToTopics")
+' CallSubDelayed(FirebaseMessaging, "SubscribeToTopics")
+' BTAdmin.Initialize("admin")
+' If BTAdmin.IsEnabled = False Then
+' If BTAdmin.Enable = False Then
+' ToastMessageShow("Error enabling Bluetooth adapter.", True)
+' Else
+' ToastMessageShow("Enabling Bluetooth adapter...", False)
+' End If
+' Else
+' BluetoothState = True
+' End If
+' reqManager.Initialize(Me, Main.server)
+ Timer1.Initialize("Timer1", Interval * 1000)
+ Timer1.Enabled = True
+ SharedFolder = rp.GetSafeDirDefaultExternal("")
+' cedisLocation.Initialize
+' cedisLocation.Latitude = "19.48118148992086"
+' cedisLocation.Longitude = "-99.15295579261536"
+End Sub
+
+Sub Service_Start (StartingIntent As Intent)
+ Service.StopAutomaticForeground 'Starter service can start in the foreground state in some edge cases.
+' StartService(PushService)
+' monitor.Initialize("monitor", 30000)
+' monitor.Enabled = True
+End Sub
+
+Sub Service_TaskRemoved
+ 'This event will be raised when the user removes the app from the recent apps list.
+End Sub
+
+'Return true to allow the OS default exceptions handler to handle the uncaught exception.
+Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
+ Return True
+End Sub
+
+Sub Service_Destroy
+
+End Sub
+
+Private Sub Timer1_Tick
+' ToastMessageShow("Timer",False)
+' LogColor("Siguiente actualizacion " & DateTime.Time(DateTime.Now + Interval * 1000),Colors.Blue)
+ ENVIA_ULTIMA_GPS
+End Sub
+
+Sub ENVIA_ULTIMA_GPS
+' If IsConnectedToInternet Then
+' Log("Con internet, enviamos UTR!")
+' Dim skmt As SQL
+' Dim cmd As DBCommand
+' Dim reqManager As DBRequestManager
+' reqManager.Initialize(Me, server)
+'' LogColor($"ReqServer = ${server}"$, Colors.red)
+' skmt.Initialize(ruta,"kmt.db", True)
+'' Log("server: "&Main.server)
+' skmt.Initialize(ruta,"kmt.db", True)
+' If B4XPages.MainPage.logger Then LogColor("Iniciamos ENVIA_ULTIMA_GPS", Colors.red)
+' DateTime.TimeFormat = "HHmmss"
+' B4XPages.MainPage.ultimaActualizacionGPS = DateTime.Time(DateTime.Now)
+' cmd.Initialize
+' cmd.Name = "select_fechat"
+' reqManager.ExecuteQuery(cmd , 0, "fechat")
+'
+' Dim cmd As DBCommand
+' cmd.Initialize
+' cmd.Name = "UPDATE_MARDS_ACTUALR3_GPS"
+' cmd.Parameters = Array As Object(B4XPages.MainPage.montoActual, B4XPages.MainPage.clientestotal, B4XPages.MainPage.clientesventa, B4XPages.MainPage.clientesvisitados, B4XPages.MainPage.lat_gps, B4XPages.MainPage.lon_gps, B4XPages.MainPage.batt, B4XPages.MainPage.montoRechazado, B4XPages.MainPage.montoEntregado, B4XPages.MainPage.clientestotal, B4XPages.MainPage.porVisitar, B4XPages.MainPage.entregas, B4XPages.MainPage.rechazos, Application.VersionName, B4XPages.MainPage.ALMACEN, B4XPages.MainPage.rutapreventa )
+' If B4XPages.MainPage.logger Then Log($"montoActual: ${B4XPages.MainPage.montoActual}, cTotal: ${B4XPages.MainPage.clientestotal}, cVenta: ${B4XPages.MainPage.clientesventa}, cVisitados: ${B4XPages.MainPage.clientesvisitados}, ${B4XPages.MainPage.lat_gps}, ${B4XPages.MainPage.lon_gps}, Batt: ${B4XPages.MainPage.batt}, montoRechazado: ${B4XPages.MainPage.montoRechazado}, montoEntregado: ${B4XPages.MainPage.montoEntregado}, porVisitar: ${B4XPages.MainPage.porVisitar}, entregas: ${B4XPages.MainPage.entregas}, rechazos: ${B4XPages.MainPage.rechazos}, Almacen: ${B4XPages.MainPage.ALMACEN}, Ruta: ${B4XPages.MainPage.rutapreventa}"$)
+'
+' reqManager.ExecuteCommand(cmd, "inst_visitas")
+' skmt.ExecNonQuery2("Update cat_variables set CAT_VA_VALOR = ? WHERE CAT_VA_DESCRIPCION = ?" , Array As String(DateTime.Time(DateTime.Now),"HoraIngreso"))
+'
+' 'Reiniciamos el timer para cuando llamamos el Sub desde otra actividad
+' Timer1.Enabled = False
+' Timer1.Interval = Interval * 1000
+' Timer1.Enabled = True
+' Else
+' Log("Sin conexión a internet, no se envió UTR!")
+' End If
+End Sub
+
+Sub IsConnectedToInternet As Boolean 'ignore
+' Dim r As Reflector
+' r.Target = r.GetContext
+' r.Target = r.RunMethod2("getSystemService", "connectivity", "java.lang.String")
+' r.Target = r.RunMethod("getActiveNetworkInfo")
+' If r.Target <> Null Then
+' Return r.RunMethod("isConnectedOrConnecting")
+' End If
+' Return False
+End Sub
+
+Sub JobDone(Job As HttpJob)
+' LogColor("starter jobdone", Colors.Red)
+' Log(Job.ErrorMessage)
+' Private r As DBResult = reqManager.HandleJob(Job)
+ If Job.Success = False Then
+' LogColor("** " & Job.Tag & " Error: " & Job.ErrorMessage, Colors.Red) ' Mod by CHV - 211023
+ If Job.ErrorMessage.Contains("failed to connect") Or Job.ErrorMessage.Contains("Failed to connect") Then
+ ToastMessageShow("!Hubo un error contactando al servidor, por favor revise su conexión!", True)
+ End If
+ 'ToastMessageShow("Error: " & Job.ErrorMessage, True)
+ Else
+' LogColor("JobDone: '" & reqManager.HandleJob(Job).tag & "' - Registros: " & reqManager.HandleJob(Job).Rows.Size, Colors.Green) 'Mod por CHV - 211023
+ End If
+End Sub
\ No newline at end of file
diff --git a/B4A/Subs.bas b/B4A/Subs.bas
new file mode 100644
index 0000000..d4efd29
--- /dev/null
+++ b/B4A/Subs.bas
@@ -0,0 +1,228 @@
+B4A=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=StaticCode
+Version=11
+@EndOfDesignText@
+'Code module
+'Subs in this code module will be accessible from all modules.
+Sub Process_Globals
+ 'These global variables will be declared once when the application starts.
+ 'These variables can be accessed from all modules.
+' Public GZip As GZipStrings
+ Private su As StringUtils
+ Dim phn As Phone
+ Dim devModel As String
+ Dim kmt As SQL 'Requiere la libreria "SQL"
+' Dim wifi As MLwifi
+ Dim ssid As String 'ignore
+ Dim rutaMaxPoints As Int = 3000
+ Dim rutaHrsAtras As Int = 48
+' Dim rutaInicioHoy As String = ""
+End Sub
+
+'Convierte una fecha al formato yyMMddHHmmss
+Sub fechaKMT(fecha As String) As String 'ignore
+' Log(fecha)
+ Dim OrigFormat As String = DateTime.DateFormat 'save orig date format
+ DateTime.DateFormat="yyMMddHHmmss"
+ Dim nuevaFecha As String=DateTime.Date(fecha)
+ DateTime.DateFormat=OrigFormat 'return to orig date format
+' Log(nuevaFecha)
+ Return nuevaFecha
+End Sub
+
+'Trae un string con hora, minutos y segundos - HHmmss
+Sub hmsKMT As String 'ignore
+' Log(fecha)
+ Dim OrigFormat As String = DateTime.DateFormat 'save orig date format
+ DateTime.DateFormat="HHmmss"
+ Private nuevaHora As String=DateTime.Date(DateTime.Now)
+ DateTime.DateFormat=OrigFormat 'return to orig date format
+' Log(nuevaFecha)
+ Return nuevaHora
+End Sub
+
+'Genera una notificacion con importancia alta
+Sub notiHigh(title As String, body As String, activity As Object) 'ignore
+ Private notif As Notification
+ notif.Initialize2(notif.IMPORTANCE_HIGH)
+ notif.Icon = "icon"
+ notif.Vibrate = False
+ notif.Sound = False
+ notif.AutoCancel = True
+ Log("notiHigh: "&title)
+ notif.SetInfo(title, body, activity)
+' Log("notiHigh SetInfo")
+ notif.Notify(777)
+End Sub
+
+'Regresa el objeto de una notificacion con importancia baja
+Sub notiLowReturn(title As String, Body As String, id As Int) As Notification 'ignore
+ Private notification As Notification
+ notification.Initialize2(notification.IMPORTANCE_LOW)
+ Log("notiLowReturn: "&title)
+ notification.Icon = "icon"
+ notification.Sound = False
+ notification.Vibrate = False
+ notification.SetInfo(title, Body, Main)
+ notification.Notify(id)
+' Log("notiLowReturn SetInfo")
+ Return notification
+End Sub
+
+'Revisa que exista la BD y si es necesario crea algunas tablas dentro de ella
+Sub revisaBD 'ignore
+ If Not(File.Exists(Starter.ruta, "kmt.db")) Then File.Copy(File.DirAssets, "kmt.db", Starter.ruta, "kmt.db")
+ If Not(kmt.IsInitialized) Then kmt.Initialize(Starter.ruta, "kmt.db", True)
+' kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS RUTA_GPS(FECHA INTEGER, LAT TEXT, LON TEXT)")
+' kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS UUC(fecha INTEGER, lat TEXT, lon TEXT)") 'LastKnownLocation
+' kmt.ExecNonQuery("CREATE TABLE IF NOT EXISTS bitacora(fecha INTEGER, texto TEXT)") 'Bitacora
+End Sub
+
+'Regresa la fecha y hora de hoy a las 00:00 en el formato "yyMMddHHMMSS"
+Sub fechaInicioHoy As String 'ignore
+ Dim OrigFormat As String = DateTime.DateFormat 'save orig date format
+ DateTime.DateFormat="yyMMdd"
+ Private h As String = DateTime.Date(DateTime.Now)&"000000"
+ DateTime.DateFormat=OrigFormat 'return to orig date format
+ Log("Hoy="&h)
+ Return h
+End Sub
+
+'Regresa verdadero si ya pasaron XX minutos de la fecha dada
+Sub masDeXXMins(hora As Int, mins As Int) As Boolean 'ignore
+ If (hora + mins * DateTime.TicksPerMinute) < DateTime.Now Then
+ Return True
+ Else
+ Return False
+ End If
+End Sub
+
+'Regresa verdadero si ya pasaron XX minutos de la fechaKMT dada
+Sub masDeXXMinsKMT(hora As String, mins As Int) As Boolean 'ignore
+ Try
+ ' LogColor($"Hora=${fechaKMT(fechaKMT2Ticks(hora) + mins * DateTime.TicksPerMinute)}, Mins=${mins}, Actual=${fechaKMT(DateTime.Now)}"$,Colors.red)
+ If fechaKMT2Ticks(hora) + mins * DateTime.TicksPerMinute < DateTime.Now Then
+' Log("+++ +++ "&fechaKMT(fechaKMT2Ticks(hora) + mins * DateTime.TicksPerMinute) & " < " & fechaKMT(DateTime.Now))
+ Return True
+ Else
+ ' Log("+++ +++ "&fechaKMT(fechaKMT2Ticks(hora) + mins * DateTime.TicksPerMinute) & " > " & fechaKMT(DateTime.Now))
+ Return False
+ End If
+ Catch
+ Log(LastException)
+ End Try
+End Sub
+
+'Convierte una fecha en formato YYMMDDHHMMSS a Ticks
+Sub fechaKMT2Ticks(fKMT As String) As Long 'ignore
+ Try
+ If fKMT.Length = 12 Then
+ Private parteFecha As String = fKMT.SubString2(0,6)
+ Private parteHora As String = fKMT.SubString(6)
+ Private OrigFormat As String = DateTime.DateFormat 'save original date format
+ DateTime.DateFormat="yyMMdd"
+ DateTime.TimeFormat="HHmmss"
+ Private ticks As Long = DateTime.DateTimeParse(parteFecha,parteHora)
+' Log(" +++ +++ pFecha:"&parteFecha&" | pHora:"&parteHora)
+ DateTime.DateFormat=OrigFormat 'return to original date format
+ Return ticks
+ Else
+ Log("Formato de fecha incorrecto, debe de ser 'YYMMDDHHMMSS', no '"&fKMT&"' largo="&fKMT.Length)
+ Return 0
+ End If
+ Catch
+ Log(LastException)
+ LogColor($"Fecha dada: ${fKMT}, Parte Fecha: ${parteFecha}, Parte Hora: ${parteHora}"$, Colors.Red)
+ Return 0
+ End Try
+End Sub
+
+Sub InstallAPK(dir As String, apk As String) 'ignore
+ If File.Exists(dir, apk) Then
+ Dim i As Intent
+ i.Initialize(i.ACTION_VIEW, "file://" & File.Combine(dir, apk))
+ i.SetType("application/vnd.android.package-archive")
+ StartActivity(i)
+ End If
+End Sub
+
+'Hace visible el panel con los parametros "Top" y "Left" dados
+Sub panelVisible(panel As Panel, top As Int, left As Int) 'ignore
+ panel.BringToFront
+ panel.Visible = True
+ panel.Top = top
+ panel.Left = left
+End Sub
+
+'Saca el usuario de la tabla USUARIOA
+Sub dameUsuarioDeDB As String 'ignore
+ Private c As Cursor
+ Private u As String = "SinUsuario"
+ If Not(kmt.IsInitialized) Then revisaBD
+ c=kmt.ExecQuery("select USUARIO from usuarioa")
+ c.Position=0
+ If c.RowCount > 0 Then u = c.GetString("USUARIO")
+ c.Close
+ Return u
+End Sub
+
+Sub SetDivider(lv As ListView, Color As Int, Height As Int) 'ignore
+ Dim r As Reflector
+ r.Target = lv
+ Dim CD As ColorDrawable
+ CD.Initialize(Color, 0)
+ r.RunMethod4("setDivider", Array As Object(CD), Array As String("android.graphics.drawable.Drawable"))
+ r.RunMethod2("setDividerHeight", Height, "java.lang.int")
+End Sub
+
+'Centra un listview dentro de un elemento superior
+Sub centraListView(elemento As ListView, anchoElementoSuperior As Int) 'ignore
+ elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2)
+End Sub
+
+'Centra un panel dentro de un elemento superior
+Sub centraPanel(elemento As Panel, anchoElementoSuperior As Int) 'ignore
+ elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2)
+End Sub
+
+'Centra una etiqueta dentro de un elemento superior
+Sub centraEtiqueta(elemento As Label, anchoElementoSuperior As Int) 'ignore
+ elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2)
+End Sub
+
+'Centra un boton dentro de un elemento superior
+Sub centraBoton(elemento As Button, anchoElementoSuperior As Int) 'ignore
+ elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2)
+End Sub
+
+'Trae el cliente desde la BD.
+Sub traeCliente As String 'ignore
+ Private cli As Cursor = Starter.skmt.ExecQuery("Select CUENTA from cuentaa")
+ cli.Position = 0
+ Private cl As String = cli.GetString("CUENTA")
+ cli.Close
+ Return cl
+End Sub
+
+'Agrega una columna a la tabla especificada.
+'Hay que indicar el "tipo" de la columna (TEXT, INTEGER, ETC)
+'Ej. agregaColumna("TABLA", "COLUMNA", "TIPO")
+Sub agregaColumna(tabla As String, columna As String, tipo As String)
+ Try 'Intentamos usar "pragma_table_info" para revisar si existe la columna en la tabla
+ Private c As Cursor = Starter.skmt.ExecQuery($"SELECT COUNT(*) AS fCol FROM pragma_table_info('${tabla}') WHERE name='${columna}'"$)
+ c.Position = 0
+ If c.GetString("fCol") = 0 Then 'Si no esta la columna la agregamos
+ Starter.skmt.ExecNonQuery($"ALTER TABLE ${tabla} ADD COLUMN ${columna} ${tipo}"$)
+ Log($"Columna "${columna} ${tipo}", agregada a "${tabla}"."$)
+ End If
+ Catch 'Si no funciona "pragma_table_info" lo hacemos con try/catch
+ Try
+ Starter.skmt.ExecNonQuery($"ALTER TABLE ${tabla} ADD COLUMN ${columna} ${tipo}"$)
+ Log($"Columna "${columna} ${tipo}", agregada a "${tabla}".."$)
+ Catch
+ Log(LastException)
+ End Try
+ End Try
+End Sub
\ No newline at end of file
diff --git a/B4A/appUpdater.bas b/B4A/appUpdater.bas
new file mode 100644
index 0000000..c0962f9
--- /dev/null
+++ b/B4A/appUpdater.bas
@@ -0,0 +1,284 @@
+B4A=true
+Group=Default Group
+ModulesStructureVersion=1
+Type=Service
+Version=10.2
+@EndOfDesignText@
+#Region Service Attributes
+ #StartAtBoot: False
+#End Region
+
+'////////////////////////////////////////////////////////////////////////////////////////////
+'//// Servicio para revisar si hay actualizacion de aplicación, usa la
+'//// actividad "updateAvailable" para mostrar mensajes.
+'////
+'//// https://www.b4x.com/android/forum/threads/update-your-app-without-using-the-gplaystore.109720/#content
+'////
+'//// En la actividad del la cual se va a llamar la revision de actualizacion
+'//// hay que agregar los siguientes Subs:
+'////
+' Sub boton_que_llama_revision_Click
+' StartService(appUpdater)
+' End Sub
+'
+' appUpdater - Mostramos el anuncio de que se esta descargando el nuevo apk
+' Sub muestraProgreso
+' ProgressDialogShow("Descargando actualización")
+' End Sub
+'
+' appUpdater - Ocultamos el anuncio de que se esta descargando el nuevo apk
+' Sub ocultaProgreso
+' ProgressDialogHide
+' End Sub
+'////
+'//// Requiere las siguientes librerias:
+'////
+'//// * appUpdating
+'//// * JavaObject
+'//// * OkHttpUtils2
+'//// * Phone
+'//// * RuntimePermissions
+'////
+'//// Requiere las siguientes lineas en el manifiesto:
+'////
+' AddManifestText(
+' )
+' AddApplicationText(
+'
+'
+'
+' )
+' CreateResource(xml, provider_paths,
+'
+'
+'
+'
+'
+' )
+' AddPermission(android.permission.REQUEST_INSTALL_PACKAGES)
+' AddPermission(android.permission.INTERNET)
+' AddPermission(android.permission.INSTALL_PACKAGES)
+' AddPermission(android.permission.READ_EXTERNAL_STORAGE)
+' AddPermission(android.permission.WRITE_EXTERNAL_STORAGE)
+' AddPermission(android.permission.READ_PHONE_STATE)
+' AddPermission(android.permission.WAKE_LOCK)
+'////
+'////////////////////////////////////////////////////////////////////////////////////////////
+
+Sub Process_Globals
+ 'These global variables will be declared once when the application starts.
+ 'These variables can be accessed from all modules.
+
+ 'Aqui va la liga al archivo .ver en el servidor que contiene la información de la aplicacion
+ Public lnk As String = "https://keymon.lat/movil/mariana/mariana_reparto.ver"
+
+ '/// En el servidor se necesita un archivo de texto (.ver) que tenga los siguientes
+ '/// datos separados por un tabulador
+ '/// contents of ver file, each field is seperated by a tab
+ ' Field 0 = 2.226.19.09.19.01a <-- Esta es la version de la aplicación disponible
+ ' Field 1 = A new version of the MyAPP is available, Download and update now ? <-- Mensaje para cuando hay actualización
+ ' Field 2 = MyApp is up to date <--- Mensaje para cuando no hay actualización
+ ' Field 3 = http://www.mydomain.com/Public/myapp.apk <--- Liga al apk de la actualización
+
+ Public nNewApp As Notification
+ Public nNewAppnID As Int = 16
+ 'Para Download
+ Dim nativeMe As JavaObject
+ Dim n2 As Notification
+ Dim n2ID As Int = 16
+ 'Para fileProvider
+ Public SharedFolder As String
+ Public UseFileProvider As Boolean
+ Private rp As RuntimePermissions
+
+ Type mNewVersion(update As Boolean, nonewAPP As Boolean, notifyUser As Boolean, _
+ version As String, newMsg As String, okMsg As String, appLink As String)
+ Public newApp As mNewVersion
+End Sub
+
+Sub Service_Create
+ Log("appUpdater(), Service_Create")
+ newApp.Initialize
+ Service.AutomaticForegroundMode = Service.AUTOMATIC_FOREGROUND_NEVER
+ n2.Initialize
+ nativeMe.InitializeContext
+End Sub
+
+Sub Service_Start (StartingIntent As Intent)
+ Log("appUpdater(), Service_Start")
+' CallSubDelayed2(Main, "muestraProgreso", "Buscando actualización")
+ B4XPages.MainPage.muestraProgreso("Buscando actualización")
+ Log("Buscando actualización")
+ fileProvider_init
+ Wait For (Download(Me, lnk)) JobDone (j As HttpJob)
+ If j.Success Then
+ Try
+ Dim app() As String = Regex.Split(Chr(9),j.GetString)
+ ' // Set the data
+ newApp.appLink = app(3) 'Liga a nueva app
+ newApp.newMsg = app(1) 'Texto de que hay actualizacion
+ newApp.okMsg = app(2) 'Texto de app al corriente
+ newApp.version = app(0) 'Version actual
+
+ Log($"Application.VersionName=${Application.VersionName}, newApp=${newApp}"$)
+
+ ' // App version check
+ If newApp.version = Application.VersionName Then
+ newApp.update = False
+ Log("No new app")
+ B4XPages.ShowPage("updateAvailable")
+ 'Se puede mandar tambien una notificacion avisando que NO hay actualizaciones
+ CreateNotification2("Aplicacion al corriente","No hay actualizaciones disponibles","ic_file_download_white_24dp",Main,True,True,nNewApp,nNewAppnID)
+ End If
+ If newApp.version <> Application.VersionName Then
+ newApp.update = True
+ Log("New app true")
+ B4XPages.ShowPage("updateAvailable")
+ 'Se puede mandar tambien una notificacion avisando que hay actualizacion disponible
+' CreateNotification2("Nueva aplicación disponible","Haga clic para descargar.","ic_file_download_white_24dp",C_UpdateAvailable,True,True,nNewApp,nNewAppnID)
+ End If
+ Catch
+ Log("appUpdater(), Job Failed, error " & LastException.Message)
+ End Try
+ Else
+ Log("appUpdater(), Job Failed " & lnk)
+ End If
+ j.Release
+' StopService(Me)
+End Sub
+
+Sub download_Start (StartingIntent As Intent)
+ download_newApk
+End Sub
+
+Sub download_newApk
+' CreateNotification("Descargando actualización", "Descargando apk", "ic_file_download_white_24dp", Main, False, True)
+' CallSubDelayed2(Main, "muestraProgreso", "Descargando actualización")
+ Log("Descargando actualización")
+ B4XPages.ShowPage("login")
+ B4XPages.MainPage.muestraProgreso("Descargando actualización")
+ Starter.muestraProgreso = 1
+ Dim job_newAPP As HttpJob
+ job_newAPP.Initialize("job_newAPP",Me)
+ job_newAPP.Download(newApp.appLink)
+ Wait for (job_newAPP) JobDone (job_newAPP As HttpJob)
+ If job_newAPP.Success = True Then
+ ' // Delete existing file
+ If File.Exists(SharedFolder,"newapp.apk") Then
+ File.Delete(SharedFolder,"newapp.apk")
+ End If
+ ' // Save new file
+ Dim outNewAPK As OutputStream = File.OpenOutput(SharedFolder,"newapp.apk", False)
+ File.Copy2(job_newAPP.GetInputStream, outNewAPK)
+ outNewAPK.Close
+' If Starter.Logger Then Log("APK dir: "&SharedFolder)
+ B4XPages.MainPage.ocultaProgreso
+ Log("ocultamos prigreso DOWNLOAD APK")
+ End If
+ job_newAPP.Release
+ ' // Install the app
+ Dim in As Intent
+ in.Initialize(in.ACTION_VIEW,"" )
+ SetFileUriAsIntentData(in, "newapp.apk")
+ ' // Type must be set after calling SetFileUriAsIntentData
+ in.SetType("application/vnd.android.package-archive")
+ StartActivity(in)
+ n2.Cancel(nNewAppnID)
+' Service.StopForeground(nNewAppnID)
+ StopService(Me)
+' CallSubDelayed(Main,"ocultaProgreso")
+End Sub
+
+Sub download_Destroy
+ n2.Cancel(n2ID)
+ Service.StopForeground(n2ID)
+End Sub
+
+Sub Download (Callback As Object, link As String) As HttpJob
+ Dim j As HttpJob
+ j.Initialize("", Callback)
+ j.Download(link)
+ Return j
+End Sub
+
+Private Sub CreateNotification2(Title As String, Content As String, _ 'ignore
+ Icon As String, TargetActivity As Object, Sound As Boolean, _
+ Vibrate As Boolean, pN As Notification,pNID As Int) As Notification
+ pN.Initialize2(pN.IMPORTANCE_HIGH)
+' pN.Number = pNID
+' pN.Light = False
+ pN.Vibrate = Vibrate
+ pN.Sound = Sound
+' pN.OnGoingEvent = False
+ pN.Icon = Icon
+ pN.AutoCancel = True
+ pN.SetInfo(Title, Content, TargetActivity)
+ pN.Notify(pNID)
+ Return pN
+End Sub
+
+Private Sub CreateNotification(Title As String, Content As String, Icon As String, TargetActivity As Object, Sound As Boolean, Vibrate As Boolean) As Notification 'ignore
+ n2.Initialize
+ n2.Light = False
+ n2.Vibrate = Vibrate
+ n2.Sound = Sound
+ n2.OnGoingEvent = True
+ n2.Icon = Icon
+ n2.SetInfo(Title, Content, TargetActivity)
+ n2.Notify(nNewAppnID)
+End Sub
+
+Sub Service_Destroy
+ Log("appUpdater(), Service_Destroy")
+End Sub
+
+Sub fileProvider_init
+ Dim p As Phone
+ If p.SdkVersion >= 24 Or File.ExternalWritable = False Then
+ UseFileProvider = True
+ SharedFolder = File.Combine(File.DirInternal, "shared")
+ If Not(File.IsDirectory(File.DirInternal,"shared")) Then
+ File.MakeDir("", SharedFolder)
+ End If
+ Else
+ UseFileProvider = False
+ SharedFolder = rp.GetSafeDirDefaultExternal("shared")
+ End If
+ Log($"Using FileProvider? - ${UseFileProvider}"$)
+End Sub
+
+'Returns the file uri.
+Sub GetFileUri (FileName As String) As Object
+ Try
+ If Not(UseFileProvider) Then
+ Dim uri As JavaObject
+ Return uri.InitializeStatic("android.net.Uri").RunMethod("parse", Array("file://" & File.Combine(SharedFolder, FileName)))
+ End If
+ Dim f As JavaObject
+ f.InitializeNewInstance("java.io.File", Array(SharedFolder, FileName))
+ Dim fp As JavaObject
+ Dim context As JavaObject
+ context.InitializeContext
+ fp.InitializeStatic("android.support.v4.content.FileProvider")
+ Return fp.RunMethod("getUriForFile", Array(context, Application.PackageName & ".provider", f))
+ Catch
+ Log("FileProvider::GetFileUri - error - " & LastException.Message)
+ Return ""
+ End Try
+End Sub
+
+'Replaces the intent Data field with the file uri.
+'Resets the type field. Make sure to call Intent.SetType after calling this method
+Sub SetFileUriAsIntentData (Intent As Intent, FileName As String)
+ Dim jo As JavaObject = Intent
+ jo.RunMethod("setData", Array(GetFileUri(FileName)))
+ Intent.Flags = Bit.Or(Intent.Flags, 1) 'FLAG_GRANT_READ_URI_PERMISSION
+End Sub