commit 9312a2444670f0c39702280bea77b22ea0f06af0 Author: cheveguerra Date: Sun Sep 24 03:29:06 2023 -0600 Commit iniical. 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/B4AProject.b4a.meta b/B4A/B4AProject.b4a.meta new file mode 100644 index 0000000..adca1e9 --- /dev/null +++ b/B4A/B4AProject.b4a.meta @@ -0,0 +1,24 @@ +ModuleBookmarks0= +ModuleBookmarks1= +ModuleBookmarks2= +ModuleBookmarks3= +ModuleBookmarks4= +ModuleBookmarks5= +ModuleBookmarks6= +ModuleBreakpoints0= +ModuleBreakpoints1= +ModuleBreakpoints2= +ModuleBreakpoints3= +ModuleBreakpoints4= +ModuleBreakpoints5= +ModuleBreakpoints6= +ModuleClosedNodes0=2,6 +ModuleClosedNodes1= +ModuleClosedNodes2= +ModuleClosedNodes3= +ModuleClosedNodes4= +ModuleClosedNodes5= +ModuleClosedNodes6=1 +NavigationStack=B4XMainPage,b_test_Click,57,0,NotificationService,getGroupName,191,0,NotificationService,getNumberWA,178,0,NotificationService,getGroupName2,200,6,NotificationService,ReplyAuto_NotificationPosted,47,6,NotificationService,regexSimple,121,0,NotificationService,isGroupWA,136,0,NotificationService,isGroupWA2,140,6,NotificationService,isPersonWA,145,6,NotificationService,isPersonWA2,154,6,NotificationService,getPersonFromGroup,205,0 +SelectedBuild=0 +VisibleModules=1,5,2,3,4 diff --git a/B4A/B4XImagenes.bas b/B4A/B4XImagenes.bas new file mode 100644 index 0000000..2e94f30 --- /dev/null +++ b/B4A/B4XImagenes.bas @@ -0,0 +1,77 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=9.86 +@EndOfDesignText@ +Sub Class_Globals + Private Root As B4XView 'ignore + Private xui As XUI 'ignore + Public cvs As B4XCanvas + Public Panel1 As B4XView + Private i_waImg As ImageView + Private l_imgData As Label + Private clv_imagenes As CustomListView +End Sub + +'You can add more parameters here. +Public Sub Initialize + +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("Imagenes") + cvs.Initialize(Panel1) + B4XPages.SetTitle(Me, "Imagenes disponibles") +End Sub + +Sub B4XPage_Appear + Private losDatos As List = Subs.traeImgMsjData + Private bmp As Bitmap + clv_imagenes.Clear + For i = 0 To losDatos.Size - 1 +' Log(losDatos.Get(i).As(Map)) +' Log(losDatos.Get(i).As(Map).Get("imgData").As(Map).Get("file_path")) + Private theDir As String = Starter.waDir & "/" & losDatos.Get(i).As(Map).Get("imgData").As(Map).Get("file_path") +' Log(theDir.SubString2(0, theDir.LastIndexOf("/")+1)) +' Log(theDir.SubString(theDir.LastIndexOf("/")+1)) + If theDir.EndsWith("jpg") Or theDir.EndsWith("png") Then + bmp = LoadBitmap(theDir.SubString2(0, theDir.LastIndexOf("/")+1), theDir.SubString(theDir.LastIndexOf("/")+1)) + clv_imagenes.Add(createImgItem(bmp, losDatos.Get(i).As(Map).Get("msjData").As(Map).Get("media_caption"), 386dip, 90dip), losDatos.Get(i)) + End If + Next +End Sub + +'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage. + +Private Sub btnClear_Click + +End Sub + +Sub btnSet_Click + B4XPages.ClosePage(Me) +End Sub + +Sub createImgItem(img As Bitmap, text As String, Width As Int, Height As Int) As Panel + Dim p As B4XView = xui.CreatePanel("") +' Private pLeft = p_rules.left + p.SetLayoutAnimated(0, 0, 0, Width, Height) + p.LoadLayout("imgItem") + i_waImg.Bitmap = img + l_imgData.Text = text + Return p +End Sub + +Private Sub clv_imagenes_ItemClick (Index As Int, Value As Object) + If Starter.Logger Then Log(Value) +End Sub + +Sub clv_imagenes_ItemLongClick (Index As Int, Value As Object) + B4XPages.MainPage.phv.Vibrate(100) + Subs.mandaWAImageRoot(Null, "Alo Papagena … Tore bella com la papaia", Value) + ToastMessageShow("Imagen mandada.",False) + If starter.Logger Then Log(Value) +End Sub \ No newline at end of file diff --git a/B4A/B4XMainPage.bas b/B4A/B4XMainPage.bas new file mode 100644 index 0000000..d0ce5f1 --- /dev/null +++ b/B4A/B4XMainPage.bas @@ -0,0 +1,410 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=9.85 +@EndOfDesignText@ +Sub Class_Globals + Private Root As B4XView 'ignore + Private xui As XUI 'ignore + Public c_reglas As B4XReglas + Public c_imagenes As B4XImagenes + Public Page4 As B4XPage4 + Dim rp As RuntimePermissions + Dim phv As PhoneVibrate + Public manager As AdminManager + + Dim reqManager As DBRequestManager + Dim cmd As DBCommand + + Type lasNotis(numero As String, notif As StatusBarNotification) + +' Dim rp As ReplyAuto + Private et_mensaje As EditText + Private lv_notificaciones As ListView + Private EditText1 As EditText + Private b_activo As Button + Private b_p2 As Button + Private b_respaldaBD As Button + Private b_notifAccess As Button + Dim writePermission As Boolean + +' Dim Su As SuShell +' Dim Process As SuProcess +' Dim lt As List + Dim notiIcon As Bitmap + Dim OldIntent As Intent + Private b_imgWA As Button + Dim b_config As Button + Dim Timer1 As Timer + Dim interval As Int = 15 + Private p_notisDisponibles As Panel + Private b_NotisDisp As Button + Private p_botones As Panel + Private b_cierra As Button +End Sub + +'You can add more parameters here. +Public Sub Initialize + StartService(NotificationService) + If Not(NotificationService.notisMap2.IsInitialized) Then NotificationService.notisMap2.Initialize + #if not(DEBUG) + Starter.logger = False + #end if +End Sub + +'This event will be called once, before the page becomes visible. +Private Sub B4XPage_Created (Root1 As B4XView) + Timer1.Initialize("Timer1", interval * 1000) + Timer1.Enabled = True + notiIcon = LoadBitmapResize(File.DirAssets, "chatbot7_191x191.png", 24dip, 24dip, False) + Root = Root1 + 'load the layout to Root + Root.LoadLayout("mainPage") + B4XPages.SetTitle(Me, "Bow 2.0") + c_reglas.Initialize + B4XPages.AddPage("Reglas", c_reglas) + c_imagenes.Initialize + B4XPages.AddPage("Imagenes", c_imagenes) + #end region + If Starter.logger Then B4XPages.GetManager.LogEvents = True + getWritePermission + getcontactsPermission +End Sub + +Sub b4xpage_appear + Dim in As Intent = B4XPages.GetNativeParent(Me).GetStartingIntent 'Traemos en StartingIntent de Main. + If in.IsInitialized And in <> OldIntent Then + OldIntent = in + If in.HasExtra("Notification_Tag") Then 'Revisamos que traiga el tag. + If Starter.logger Then Log("Activity started from notification. Tag: " & in.GetExtra("Notification_Tag")) + Private waChat, nombre As String + Private ts() As String = Regex.Split("\|", in.GetExtra("Notification_Tag")) + waChat = ts(0) + nombre = ts(1) + If Starter.logger Then LogColor($"ts=${ts}, ts.Length=${ts.Length}, waChat=${waChat}, nombre=${nombre}"$, Colors.green) + Starter.historicoDB.ExecNonQuery2("update historico set clic = '1' where clic = '0' and nombre = ?", Array As Object(nombre)) 'Ponemos en 1 las notificacion a las que ya se les dió clic. + CallSubDelayed2(Main, "Activity_KeyPress", KeyCodes.KEYCODE_BACK) + Subs.abreWAChat(waChat) + End If + End If + Subs.centraPanel(p_botones, Root.Width) + If NotificationService.notisMap2.IsInitialized Then llenaLV + If Not(CheckNotificationAccess) Then + Private cd1 As ColorDrawable + cd1.Initialize(Colors.red, 10dip) + b_notifAccess.Background = cd1 + b_notifAccess.TextColor = Colors.White + b_notifAccess.Text = "Activar Permisos" + Else + Private cd1 As ColorDrawable + cd1.Initialize(Colors.RGB(109, 221, 101), 10dip) + b_notifAccess.Background = cd1 + b_notifAccess.TextColor = Colors.White + b_notifAccess.Text = "Permisos Activos" + End If +' Dim Su As SuShell +' If Su.DeviceRooted Then +' If Starter.logger Then LogColor("Rooted", Colors.Green) +' Private suCmd As String = $"sqlite3 /data/data/com.whatsapp/databases/msgstore.db 'SELECT _id FROM messages WHERE data="Test 2"';"$ +'' Private suCmd As String = $"ls"$ +' If Su.ExecuteWithEvent(suCmd, "Su").WaitForCompletion Then +' If starter.Logger Then Log("Root - Done") +' Else +' If starter.Logger Then Log("Root - Permissions Error") +' End If +' Else +' If Starter.logger Then LogColor("Root - Device not rooted", Colors.red) +' End If + If Starter.logger Then LogColor("Cola de notificaciones="&NotificationService.notificacionesPorContestar, Colors.RGB(168,0,0)) + getAdminRights +End Sub + +Sub B4XPage_CloseRequest As ResumableSub + 'Return True to close, False to cancel + Return True +End Sub + +Sub Su_Start + If Starter.logger Then Log("Su: Start") +End Sub + +Sub Su_Command(Command As String, Response() As String) + If Starter.logger Then Log("Su: Command") + Dim Lines As String + For i=0 To Response.Length-1 + Lines = Lines & Response(i) & CRLF + Next +' Msgbox(Lines.Trim, Command) + If Starter.logger Then Log(Lines & CRLF) +End Sub + +'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage. +Sub b_notifAccess_Click + Dim In As Intent + In.Initialize("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS", "") + StartActivity(In) +End Sub + +Sub b_notifAccess_LongClick + Subs.abreWAChat("5215554192439@s.whatsapp.net") +End Sub + +Private Sub b_activo_Click + If NotificationService.status = "Servicio Activo" Then + NotificationService.status = "Servicio Apagado" + Private cd1 As ColorDrawable + cd1.Initialize(Colors.red, 10dip) + b_activo.Background = cd1 + b_activo.Text = "Servicio Apagado" + NotificationService.cont = 101 + StopService(NotificationService) + Else + NotificationService.status = "Servicio Activo" + Private cd1 As ColorDrawable + cd1.Initialize(Colors.RGB(109, 221, 101), 10dip) + b_activo.Background = cd1 + b_activo.Text = "Servicio Activo" + NotificationService.cont = 101 + StartService(NotificationService) + End If +End Sub + +Private Sub b_test_Click + If starter.Logger Then Log("Test clicked") +' If NotificationService.notisMap2.IsInitialized Then EditText1.Text = NotificationService.notisMap2.As(JSON).ToString +' Subs.mandaWAMsjSBN("+52 55 1661 1480", $"Prueba - ${DateTime.Time(DateTime.now)}"$) +' If Starter.logger Then LogColor($"starterStatus=${Starter.starterStatus}, nsStatus=${NotificationService.nsStatus}"$, Colors.Blue) +' CallSubDelayed(NotificationService, "procesaColaDeNotificaciones") +' Private jid As String = "5215516611480" +' Subs.mandaWAMsjRoot("1.- Hola", jid) + reqManager.Initialize(Me, Starter.DBRServer) + cmd.Initialize + cmd.Name = "select_revisaBorrarVenta" 'Intentamos conectarnos al servido publico y si no responde cambiamos al interno. + cmd.Parameters = Array As Object("525554192439","16","4","16","4","16","4","16","4","16","4","525554192439") + reqManager.ExecuteQuery(cmd , 0, "revisaVenta", 750) 'request con timeout corto en ms. + +' cmd.Name = "proc_recuperaClientesNuevos" +' cmd.Parameters = Array As Object("35","634","CHATBOT") +' reqManager.ExecuteCommand(cmd ,"procRecuperaClientes") +End Sub + +Private Sub b_test_LongClick +' desbloqueaUsuario("CDAZA") + Private cont As Int = 0 + For j = 1 To 4 + For i = cont To cont+5 + cont = cont + 1 + If Starter.logger Then LogColor("cont="&cont, Colors.Blue) + If Starter.logger Then LogColor("Mandamos mensaje " & cont, Colors.Magenta) + Subs.mandaWAMsjRoot(cont & ".- Hola", "5215516611480") +' Subs.hazRootQuery("killall com.whatsapp", "KillWA") + Next + If Starter.logger Then LogColor("Iniciamos WA", Colors.Blue) + Subs.hazRootQuery("am start -n com.whatsapp/com.whatsapp.Main", "iniciaWA") + +' Try +' Dim Intent1 As Intent +' Dim pm As PackageManager +' Intent1 = pm.GetApplicationIntent("com.whatsapp") +' StartActivity (Intent1) +' Catch +' Log ("Failed to launch app! Is it installed?") +' End Try + + If Starter.logger Then LogColor("Esperamos 5 segs", Colors.red) + Sleep(5000) + Next + cont = 0 + If Starter.logger Then Log("TERMINAMOS") +' Subs.copyWADB +' Subs.mandaWAImageRoot_0(1) +' Subs.traeImgMsjData +End Sub + +Sub llenaLV +' Log("llenaLV") +' lv_notificaciones.Initialize("lv_notificaciones") + lv_notificaciones.Color = Colors.LightGray + lv_notificaciones.Clear + Dim label1 As Label + label1 = lv_notificaciones.SingleLineLayout.Label + label1.TextSize = 16 + label1.TextColor = Colors.Black + lv_notificaciones.SingleLineLayout.ItemHeight = 110 'Alto de la opcion de la lista. + label1.Height = 40dip 'Alto de la etiqueta dentro de la opcion de la lista. +' Log(NotificationService.notisMap2.Keys) + For Each k As String In NotificationService.notisMap2.Keys + lv_notificaciones.AddSingleLine(k) + Next +End Sub + +Sub lv_notificaciones_ItemClick (Position As Int, Value As Object) +' Log($"posicion: ${Position}, valor: ${Value}, sender: ${Sender}"$) + Private t0 As Map = NotificationService.notisMap2.Get(Value) + Dim t1 As StatusBarNotification = t0.Get(Value).As(lasNotis).notif +' Dim t2 As StatusBarNotification = t1.notif + Subs.abreWAChat(Subs.getShortcut(t1)) +End Sub + +Private Sub lv_notificaciones_ItemLongClick (Position As Int, Value As Object) + If Starter.logger Then Log($"posicion: ${Position}, valor: ${Value}, sender: ${Sender}"$) + Private tempMap As Map = NotificationService.notisMap2.Get(Value) 'Valeria Guerra Rivera + Private t1 As lasNotis = tempMap.Get(Value) + Private t2 As StatusBarNotification = t1.notif +' Log(t2) + If et_mensaje.Text = "" Then ToastMessageShow("El texto del mensaje no debe estar en blanco.", False) + If t2.IsInitialized And et_mensaje.Text <> "" Then + NotificationService.rp.reply(t2.Notification, t2.PackageName, et_mensaje.text) +' CallSubDelayed3(NotificationService, "guardaMsjSalida", t2, et_mensaje.text) + ToastMessageShow("Mensaje enviado!", False) + End If +End Sub + +Private Sub b_p2_Click + B4XPages.ShowPage("Reglas") +End Sub + +Private Sub b_respaldaBD_Click + Starter.rp.CheckAndRequest(Starter.rp.PERMISSION_WRITE_EXTERNAL_STORAGE) + Wait For Activity_PermissionResult (Permission As String, Result As Boolean) + If Result Then + Subs.copiaDB + Else + ToastMessageShow("Sin permisos", False) + End If +End Sub + +Sub b_respaldaBD_LongClick + Try + File.Copy(File.DirRootExternal&"/Bow2.0","bow.db",File.DirInternal,"bow.db") + ToastMessageShow("Listo, reglas restauradas " & File.DirRootExternal&"/Bow2.0", False) + If Starter.logger Then Log("Listo, reglas restauradas " & File.DirRootExternal&"/Bow2.0") + Subs.traeReglas + Starter.reglasDB.Initialize(Starter.ruta, "bow.db", True) + B4XPages.MainPage.c_reglas.muestraReglas + Catch + ToastMessageShow("No se pudo hacer la copia: "&LastException, True) + End Try +End Sub + +Sub CheckNotificationAccess As Boolean + Dim ph As Phone + Dim nstr, pstr As String + Dim r As Reflector + pstr = r.GetStaticField("anywheresoftware.b4a.BA", "packageName") + nstr = ph.GetSettings("enabled_notification_listeners") + Return nstr.Contains(pstr) +End Sub + +Sub getcontactsPermission + If Starter.logger Then Log("getcontactsPermission") + rp.CheckAndRequest(rp.PERMISSION_READ_CONTACTS) + Wait For Activity_PermissionResult (Permission As String, Result As Boolean) + Dim p2 As B4XReglas = B4XPages.GetManager.GetPage("Reglas") + If Result Then + p2.contactsPermission = True + If Starter.logger Then Log(p2.contactsPermission) + Else + p2.contactsPermission = False + If Starter.logger Then Log(p2.contactsPermission) + ToastMessageShow("Sin permisos de contactos", False) + End If +End Sub + +Sub getWritePermission + If Starter.logger Then Log("getcontactsPermission") + rp.CheckAndRequest(rp.PERMISSION_WRITE_EXTERNAL_STORAGE) + Wait For Activity_PermissionResult (Permission As String, Result As Boolean) + If Result Then + writePermission = True + If Starter.logger Then Log(writePermission) + Else + writePermission = False + If Starter.logger Then Log(writePermission) + ToastMessageShow("Sin permisos de escritura", False) + End If +End Sub + +Private Sub b_imgWA_Click + B4XPages.ShowPage("Imagenes") +End Sub + +Sub getAdminRights + If manager.Enabled = False Then + manager.Enable("Please enable in order to get access to the secured server.") + End If +End Sub + +Private Sub b_config_Click + Private cd1 As ColorDrawable + cd1.Initialize(Colors.Gray, 10dip) + B4XPages.MainPage.b_config.Background = cd1 + NotificationService.pruebaPaso = 0 + CallSubDelayed(NotificationService, "revisaConexion") +End Sub + +Private Sub Timer1_Tick +' ToastMessageShow("Timer",False) +' ENVIA_ULTIMA_GPS 'Comentado para que no estorbe hasta que no esten los queries correctos en el config.properties + NotificationService.pruebaPaso = 0 + CallSubDelayed(NotificationService, "revisaConexion") +End Sub + +Private Sub Panel1_Click + If p_notisDisponibles.Visible Then p_notisDisponibles.Visible = False +End Sub + +Private Sub p_notisDisponibles_Click + +End Sub + +Private Sub b_NotisDisp_Click + p_notisDisponibles.Width = Root.Width * 0.9 + Subs.centraPanel(p_notisDisponibles, Root.Width) + p_notisDisponibles.Top = (Root.Height/2) - (p_notisDisponibles.Height/2) + lv_notificaciones.Width = p_notisDisponibles.Width * 0.9 + lv_notificaciones.Left = (p_notisDisponibles.Width/2) - (lv_notificaciones.Width/2) + b_cierra.Left = p_notisDisponibles.Width - (b_cierra.Width + 10) + et_mensaje.Width = p_notisDisponibles.Width * 0.8 + p_notisDisponibles.BringToFront + p_botones.SendToBack + p_notisDisponibles.Visible = True +End Sub + +Private Sub b_cierra_Click + p_notisDisponibles.Visible = False +End Sub + +Sub JobDone(Job As HttpJob) 'ignore + If Starter.logger Then LogColor("jobDone: " & Job.Tag, Colors.Magenta) + If Job.Success = False Then + If Starter.Logger Then LogColor("***** jobDone Error *****", Colors.Red) + If Starter.Logger Then LogColor(Job.ErrorMessage, Colors.Red) + Else + If Starter.Logger Then LogColor("JobDone: '" & reqManager.HandleJob(Job).tag & "' - Registros: " & reqManager.HandleJob(Job).Rows.Size, Colors.Green) 'Mod por CHV - 211027 + If Job.JobName = "DBRequest" Then 'Para desbloquear un usuario Guna. + Dim result As DBResult = reqManager.HandleJob(Job) + If Starter.Logger Then Log("******************************************************") + If Starter.Logger Then Log($"************ ${result.Tag} ***********"$) + If Starter.Logger Then Log("******************************************************") + + If result.Tag=="revisaVenta" Then 'query tag + Private num As String = result.Tag + num = num.SubString(num.IndexOf("_")+1) + If Starter.logger Then Log(num) + For Each records() As Object In result.Rows + For Each k As String In result.Columns.Keys + If Starter.logger Then LogColor(result.Tag & ": " & k & "=" & records(result.Columns.Get(k)), Colors.blue) + Next +' Dim autorizado As String = records(result.Columns.Get("AUTORIZADO")) +' Dim existe_venta As String = records(result.Columns.Get("EXISTE_VENTA")) +' Dim impresa As String = records(result.Columns.Get("IMPRESA")) +' Dim comercial As String = records(result.Columns.Get("COMERCIAL")) +' Dim condescuento As String = records(result.Columns.Get("CONDESCUENTO")) + Next + End If + End If + Job.Release + End If +End Sub \ No newline at end of file diff --git a/B4A/B4XPage2.bas b/B4A/B4XPage2.bas new file mode 100644 index 0000000..d0590b3 --- /dev/null +++ b/B4A/B4XPage2.bas @@ -0,0 +1,598 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=9.86 +@EndOfDesignText@ +Sub Class_Globals + Private Root As B4XView 'ignore + Private xui As XUI 'ignore + Dim ime As IME 'ignore +' Private lblHello As B4XView + Private ImageView1 As B4XView 'ignore +' Private Page3 As B4XPage3 + Private CustomListView1 As CustomListView 'ignore +' Private Tree As CLVTree +' Private b_colapsa As Button +' Private b_expande As Button +' Private Panel2 As Panel + Private clv_reglas2 As CustomListView + Private et_regla As EditText + Private p_rules As Panel + Private l_tit As Label +' Private l_rule As Label + Private p_reglas As Panel + Private l_tit2 As Label + Private et_regla2 As EditText + Private cb_activa As CheckBox + Private l_regla As Label + Private p_editarRegla As Panel + Private et_nombre As EditText + Private b_cancelar As Button + Private et_entra As EditText + Private et_sale As EditText + Private l_sale As Label + Private l_regla_1 As Label + Private l_regla_2 As Label + Private p_separador As Panel + Private r_destinatario_p As RadioButton + Private r_destinatario_g As RadioButton + Private r_destinatario_a As RadioButton + Dim destinatario As String = "Personas" + Private l_flecha As Label + Private fb_add As cvFloatingBtn + Private p_msgBox As Panel + Private l_msgBoxTitle As Label + Private l_msgBoxText As Label + Private b_msgBoxYes As Button + Private b_msgBoxNo As Button + Private p_sombra As Panel + Private p_contestacion As Panel + Private l_sale2 As Label + Private et_sale2 As EditText + Private p_recibimos As Panel + Private l_entra As Label + Private p_contactosEspecificos As Panel + Private et_contEsp As EditText + Private l_contEsp As Label + Dim contactsPermission As Boolean = False + Private clv_contactPicker As CustomListView + Private PCLV As PreoptimizedCLV + Private l_contact As Label + Private cb_selectContact As CheckBox + Private p_contacts As Panel + Private p_contactPicker As Panel + Dim contactosEspecificos As List + Private p_conEsp As Panel + Private b_guardaConEsp As Button + Private et_conEsp As EditText + Private et_conEsp2 As EditText + Private b_getContacts As Button + Dim listaReglasContestaciones As List + Private b_addET As Button + Private ScrollView1 As ScrollView +End Sub + +'You can add more parameters here. +Public Sub Initialize + +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("Page2") +' Root.LoadLayout("floatbutton_layout") + B4XPages.SetTitle(Me, "Reglas") +' Page3 = B4XPages.GetPage("Page 3") + contactosEspecificos.Initialize + PCLV.Initialize(Me, "PCLV", clv_contactPicker) + PCLV_AddItems + muestraReglas +End Sub + +Private Sub B4XPage_Appear +' NotificationService.mapReglas = Subs.traeReglas +' clv_reglas2.Clear +' clv_reglas2.PressedColor = Colors.Transparent +' For Each m As Map In NotificationService.mapReglas.Values +' clv_reglas2.Add(CreateListItem(m.get("id"), m.get("nombre"), "Recibimos:", m.Get("recibe"), "Contestamos:", m.Get("contesta"), m.Get("activa"), 386dip, 90dip), m.get("id")) +' Next +' p_editarRegla.Visible = False +' p_sombra.Visible = False +' p_reglas.Width = Root.Width - 20 +' Subs.centraPanel(p_editarRegla, Root.Width) +End Sub + +Sub clv_contactPicker_VisibleRangeChanged (FirstIndex As Int, LastIndex As Int) + For Each i As Int In PCLV.VisibleRangeChanged(FirstIndex, LastIndex) + Dim item As CLVItem = clv_contactPicker.GetRawListItem(i) + Dim pnl As B4XView = xui.CreatePanel("") + pnl.Color = Colors.White + item.Color = Colors.White + item.Panel.AddView(pnl, 0, 0, item.Panel.Width, item.Panel.Height) + 'Create the item layout + pnl.LoadLayout("contactItem") + cb_selectContact.Tag = item.Value + l_contact.Text = item.Value + Next +End Sub + +Sub PCLV_AddItems + For Each contact As String In Subs.getContactos + PCLV.AddItem(40dip, xui.Color_White, contact) + Next + PCLV.Commit +End Sub + +'Return the hint that will be displayed when the user fast scrolls the list. It can be a string or CSBuilder. +Sub PCLV_HintRequested (Index As Int) As Object + Dim word As String = clv_contactPicker.GetValue(Index) + Return word +End Sub + +Sub muestraReglas + NotificationService.mapReglas = Subs.traeReglas +' Log("mapReglas=" & NotificationService.mapReglas) + clv_reglas2.Clear + clv_reglas2.PressedColor = Colors.Transparent +' clv_reglas2.AsView.Color = Colors.red + For Each m As Map In NotificationService.mapReglas.Values + clv_reglas2.Add(CreateListItem(m.get("id"), m.get("nombre"), "Recibimos:", m.Get("recibe"), "Contestamos:", m.Get("contesta"), m.Get("activa"), 386dip, 90dip), m.get("id")) + Next + p_editarRegla.Visible = False + p_sombra.Visible = False + p_reglas.Width = Root.Width - 20 + p_sombra.Width = Root.Width + p_sombra.Height = Root.Height + Subs.centraPanel(p_editarRegla, Root.Width) + Subs.centraPanel(p_sombra, Root.Width) +End Sub + +Sub CreateListItem(id As Int, nom As String, tit As String, rule As String, tit2 As String, rule2 As String, activa As Int, Width As Int, Height As Int) As Panel + Dim p As B4XView = xui.CreatePanel("") + Dim active As Boolean = False +' Private pLeft = p_rules.left + If activa = 1 Then active = True + p.SetLayoutAnimated(0, 0, 0, Width, Height) + p.LoadLayout("ruleItem") + l_tit.Text = tit + l_regla_1.Text = rule + l_tit2.Text = tit2 + l_regla_2.Text = rule2 + Subs.SetButtonTintList(cb_activa, Colors.red, Colors.RGB(7, 183, 0)) + If nom.IndexOf(".") > -1 Then + Private cuantos As Int = Subs.CountChars(nom, ".") +' Log(cuantos) + Private leftOffs As Int = 15 + If cuantos > 0 Then leftOffs = leftOffs * cuantos + p_rules.Left = p_rules.Left + leftOffs + p_rules.Width = p_rules.Width - leftOffs + l_regla_1.Width = l_regla_1.Width - leftOffs + l_regla_2.Width = l_regla_2.Width - leftOffs + cb_activa.Left = cb_activa.Left - leftOffs + Dim cd1 As ColorDrawable + cd1.Initialize2(Colors.White, 30, 5, Colors.Red) + l_regla.TextColor = Colors.red +' l_flecha.TextColor = Colors.red +' p_rules.Color = Colors.RGB(209, 0, 0) + p_rules.Background = cd1 + + If cuantos > 0 Then + l_flecha.Visible = True + l_regla.Left = l_regla.Left + 40 +' If cuantos = 2 Then p_rules.Color = Colors.RGB(134, 246, 126) +' If cuantos > 2 Then p_rules.Color = Colors.RGB(217, 217, 217) + If cuantos = 2 Then + cd1.Initialize2(Colors.White, 30, 5, Colors.Gray) + l_regla.TextColor = Colors.Gray +' l_flecha.TextColor = Colors.Gray + End If + If cuantos = 3 Then + cd1.Initialize2(Colors.White, 30, 6, Colors.RGB(255, 140, 125)) + l_regla.TextColor = Colors.RGB(255, 140, 125) +' l_flecha.TextColor = Colors.RGB(255, 140, 125) + End If + If cuantos > 3 Then + cd1.Initialize2(Colors.White, 30, 6, Colors.RGB(250, 161, 38)) + l_regla.TextColor = Colors.RGB(250, 161, 38) +' l_regla.TextColor = Colors.RGB(250, 161, 38) + End If + p_rules.Background = cd1 + End If + End If + + Dim su As StringUtils + ' recalculate new heights +' Dim prhTemp As Int = p_rules.Height + l_regla_1.height = su.MeasureMultilineTextHeight(l_regla_1, l_regla_1.Text) + l_regla_2.height = su.MeasureMultilineTextHeight(l_regla_2, l_regla_2.Text) + p_separador.Top = l_regla_1.Top + l_regla_1.Height + 10 + l_tit2.Top = p_separador.Top + 20 + l_regla_2.Top = l_tit2.top + p_rules.Height = l_regla_1.Height + l_regla_2.Height + 110 + p.SetLayoutAnimated(0, 0, 0, Width, p_rules.Height +10) + + cb_activa.Checked = active + cb_activa.Tag = id + l_regla.Text = nom + l_regla.Tag = id + Return p +End Sub + +'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage. +Sub b_1_Click +' B4XPages.ShowPage("Page 3") +End Sub + +Sub btnSignOut_Click +' Page3.ClearImage +' UpdateImage +' B4XPages.ShowPageAndRemovePreviousPages("MainPage") +End Sub + +Private Sub cb_activa_CheckedChange(Checked As Boolean) + Dim chk As CheckBox = Sender +' if starter.showLogs then Log(Checked & " | " & chk.tag ) + If chk.Tag <> Null And chk.Tag <> "" Then + Dim p_regla As Panel = Sender.As(View).Parent.As(Panel) +' if starter.showLogs then Log("|"&p_regla.NumberOfViews) + Private idRegla As Int = chk.tag + Private activa As Boolean = Checked +' Private recibimos As String = p_regla.GetView(1).as(Label).text +' Private mandamos As String = p_regla.GetView(3).as(Label).text + If Starter.showLogs Then Log("|"&p_regla.GetView(5)) + Subs.guardaRegla(idRegla, activa) + NotificationService.mapReglas = Subs.traeReglas + End If +' Log(NotificationService.mapReglas) +End Sub + +'Borramos la regla. +Sub cb_activa_LongClick + Private chk As CheckBox = Sender + If Starter.showLogs Then Log(chk.tag) + p_msgBox.Top = (Root.Height/2) - (p_msgBox.Height/2) + Subs.centraPanel(p_msgBox, Root.Width) + l_msgBoxTitle.Text = "Borrar regla" + l_msgBoxText.text = $"¿Seguro que desea borrar la regla ${chk.tag}?"$ + p_msgBox.Visible = True + b_msgBoxYes.Tag = chk.tag + p_msgBox.Tag = clv_reglas2.GetItemFromView(Sender.As(View)) + If Starter.showLogs Then LogColor(p_msgBox.tag, Colors.Magenta) +' if starter.showLogs then LogColor(clv_reglas2.Size,Colors.Magenta) +End Sub + +Private Sub b_msgBoxYes_Click + p_msgBox.Visible = False + If Starter.showLogs Then Log(Sender.As(Button).tag) + Subs.borrarRegla(Sender.As(Button).tag) + NotificationService.mapReglas = Subs.traeReglas +' B4XPage_Appear + clv_reglas2.RemoveAt(p_msgBox.Tag) +' muestraReglas +End Sub + +Private Sub b_msgBoxNo_Click + p_msgBox.Visible = False +End Sub + +Sub p_msgBox_Click + 'Do nothing +End Sub + +Private Sub et_regla_TextChanged (Old As String, New As String) + Dim p_regla As Panel = Sender.As(View).Parent.As(Panel) + Private cb As CheckBox = p_regla.GetView(2) + cb.Checked = False +' Log(cb.checked) +End Sub + +Private Sub et_regla2_TextChanged (Old As String, New As String) + Dim p_regla As Panel = Sender.As(View).Parent.As(Panel) + Private cb As CheckBox = p_regla.GetView(2) + cb.Checked = False +' Log(cb.checked) +End Sub + +Private Sub L_regla_LongClick +' et_nombre.Text = Sender.As(Label).text +' et_nombre.Tag = Sender.As(Label).tag +' Log(Sender.As(Label)) +'' Log(Sender.As(Label).Tag & "|"&NotificationService.mapReglas) +' Private d As Map = NotificationService.mapReglas.Get(Sender.As(Label).tag) +'' Log(d) +' et_entra.Text = d.Get("recibe") +' et_sale.Text = d.Get("contesta") +' p_editarRegla.visible = True +' RecalculateHeightViews +End Sub + +Private Sub b_guardar_Click + For i = 0 To listaReglasContestaciones.Size -1 + et_sale.Text = et_sale.Text & "//" & listaReglasContestaciones.Get(i).As(EditText).text + Next + if starter.showLogs then Log(et_sale.text) + Subs.actualizaRegla(et_nombre.Tag, et_nombre.text, et_entra.Text, et_sale.text, r_destinatario_p.tag, et_contEsp.text) +' NotificationService.mapReglas = Subs.traeReglas + muestraReglas + p_editarRegla.Visible = False + p_sombra.Visible = False + ime.HideKeyboard +End Sub + +Private Sub b_cancelar_Click + p_editarRegla.Visible = False + p_editarRegla.SendToBack +' ScrollView1.Visible = False + p_sombra.Visible = False + ime.HideKeyboard +End Sub + +Sub RecalculateHeightViews +' Log("Recalcula") + Dim su As StringUtils + 'Recalculate new heights + et_entra.height = su.MeasureMultilineTextHeight(et_entra, et_entra.Text) + 60 + et_sale.height = su.MeasureMultilineTextHeight(et_sale, et_sale.Text)+ 60 + et_contEsp.Height = su.MeasureMultilineTextHeight(et_contEsp, et_contEsp.Text)+ 60 + p_recibimos.Height = et_entra.Height + 20 + p_contestacion.Height = et_sale.Height + 20 + p_contactosEspecificos.Height = et_contEsp.Height + 20 + ' Recalculate new vertical positions + p_recibimos.Top =l_entra.Top + l_entra.Height + 5 + l_sale.Top = p_recibimos.Top + p_recibimos.height + 5 + p_contestacion.Top = l_sale.Top + l_sale.height + 5 + If listaReglasContestaciones.Size > 0 Then + For j = 0 To listaReglasContestaciones.Size - 1 + listaReglasContestaciones.Get(j).As(EditText).Height = su.MeasureMultilineTextHeight(listaReglasContestaciones.Get(j).As(EditText), listaReglasContestaciones.Get(j).As(EditText).Text) + 60 + p_contestacion.Height = p_contestacion.Height + listaReglasContestaciones.Get(j).As(EditText).Height - 15 + Next + End If + ScrollView1.Panel.Height = p_recibimos.Height + p_contestacion.Height + p_contactosEspecificos.Height + 500 + For n = 0 To listaReglasContestaciones.Size - 1 + If n = 0 Then + listaReglasContestaciones.Get(n).As(EditText).Top = et_sale.Top + et_sale.Height - 15 + Else if n > 0 Then + listaReglasContestaciones.Get(n).As(EditText).Top = listaReglasContestaciones.Get(n-1).As(EditText).Top + listaReglasContestaciones.Get(n-1).As(EditText).Height - 15 + End If +' LogColor(listaReglasContestaciones.Get(n).As(EditText).Top, Colors.red) + Next + r_destinatario_p.Top = p_contestacion.Top + p_contestacion.Height + r_destinatario_g.Top = r_destinatario_p.top + r_destinatario_a.Top = r_destinatario_p.top + l_contEsp.Top = r_destinatario_p.Top + r_destinatario_p.Height + b_addET.Top = l_sale.top - 1 + b_getContacts.Top = l_contEsp.top - 5 + p_contactosEspecificos.Top = l_contEsp.Top + l_contEsp.Height +End Sub + +Private Sub et_entra_TextChanged (Old As String, New As String) + RecalculateHeightViews +End Sub + +Private Sub et_sale_TextChanged (Old As String, New As String) + RecalculateHeightViews +End Sub + +Private Sub et_sale2_TextChanged (Old As String, New As String) + RecalculateHeightViews +End Sub + +Private Sub et_contEsp_TextChanged (Old As String, New As String) + RecalculateHeightViews +End Sub + +Private Sub clv_reglas2_ItemClick (Index As Int, Value As Object) + If Starter.showLogs Then Log(Index &"|" & Value) + listaReglasContestaciones.Initialize +' p_editarRegla.Visible = True +' p_editarRegla.BringToFront + ScrollView1.Panel.RemoveAllViews + ScrollView1.Panel.LoadLayout("editaRegla") + ScrollView1.Height = p_editarRegla.Height * 0.9 + ScrollView1.Panel.Height = ScrollView1.Height + Private et_sale As EditText + et_sale.Initialize("et_sale") + et_sale.TextColor = Colors.Black + et_sale.TextSize = 12 + p_contestacion.RemoveAllViews + p_contestacion.AddView(et_sale, 10, 10, (p_contestacion.Width*0.95), 30dip) + Private d As Map = NotificationService.mapReglas.Get(Value) + If Starter.showLogs Then Log(d) + et_entra.InputType = Bit.Or(0x00080000, 0x00000090) 'TYPE_TEXT_FLAG_NO_SUGGESTIONS | TYPE_TEXT_VARIATION_VISIBLE_PASSWORD + et_entra.SingleLine = False + et_sale.InputType = Bit.Or(0x00080000, 0x00000090) 'TYPE_TEXT_FLAG_NO_SUGGESTIONS | TYPE_TEXT_VARIATION_VISIBLE_PASSWORD + et_sale.SingleLine = False + et_contEsp.InputType = Bit.Or(0x00080000, 0x00000090) 'TYPE_TEXT_FLAG_NO_SUGGESTIONS | TYPE_TEXT_VARIATION_VISIBLE_PASSWORD + et_contEsp.SingleLine = False + et_nombre.Tag = Value + et_nombre.Text = d.Get("nombre") + et_entra.Text = d.Get("recibe") + Private ets() As String = Regex.Split("//", d.Get("contesta")) 'Dividimos el regla en sus multiples respuestas. +' et_sale.Text = d.Get("contesta") + et_sale.Text = ets(0).trim + If ets.Length > 1 Then + For x = 1 To ets.Length - 1 + addET(ets(x).Trim) + Next + End If + destinatario = "Personas" + If d.Get("destinatario") <> Null Then destinatario = d.Get("destinatario") + If destinatario = "Personas" Then r_destinatario_p.Checked = True + If destinatario = "Grupos" Then r_destinatario_g.Checked = True + If destinatario = "Ambos" Then r_destinatario_a.Checked = True + et_contEsp.Text = d.Get("contactoEspecifico") + r_destinatario_p.Tag = destinatario + p_editarRegla.visible = True + p_sombra.Visible = True + If Starter.showLogs Then Log(contactsPermission) +' If contactsPermission Then +' Dim res As List = InputMultiList(Subs.getContactos, "Select") +' Log(res) +' End If + RecalculateHeightViews +End Sub + +Private Sub r_destinatario_p_CheckedChange(Checked As Boolean) + If Starter.showLogs Then Log(Sender.As(RadioButton).text & "|" &Checked) + destinatario = Sender.As(RadioButton).text + r_destinatario_p.Tag = destinatario +End Sub + +Private Sub r_destinatario_g_CheckedChange(Checked As Boolean) + If Starter.showLogs Then Log(Sender.As(RadioButton).text & "|" &Checked) + destinatario = Sender.As(RadioButton).text + r_destinatario_p.Tag = destinatario +End Sub + +Private Sub r_destinatario_a_CheckedChange(Checked As Boolean) +' Log(Sender.As(RadioButton).text & "|" &Checked) + destinatario = Sender.As(RadioButton).text + r_destinatario_p.Tag = destinatario +End Sub + +'Agregamos regla. +Sub fb_add_Clicked(X As Float,Y As Float) +' ToastMessageShow("Button Clicked",False) + Subs.agregaRegla + NotificationService.mapReglas = Subs.traeReglas +' B4XPage_Appear + muestraReglas +End Sub + +Private Sub B4XPage_CloseRequest As ResumableSub + Sleep(0) + If Starter.showLogs Then Log("B4XPage_CloseRequest") +' if starter.showLogs then Log(p_contactPicker.Visible) + If p_contactPicker.Visible = True Then + p_contactPicker.Visible = False + Return False + End If + If p_editarRegla.Visible Then + p_editarRegla.Visible = False + p_sombra.Visible = False + Return False + End If + Return True +End Sub + +Private Sub p_editarRegla_Click + 'Nothing here. +End Sub + +Private Sub p_sombra_Click + 'Nothing here. +End Sub + +Sub muestraContactos + If Starter.showLogs Then Log("muestraContactos") + p_contactPicker.Visible = True + ime.HideKeyboard + p_contactPicker.left = 0 + p_contactPicker.Top = 0 + p_contactPicker.Width = Root.Width + p_contactPicker.Height = Root.Height + clv_contactPicker.GetBase.SetLayoutAnimated(0, 5dip, 30dip, Root.Width - 10, Root.Height * 0.68) 'Cambiamos el tamaño y posición de la lista de productos + clv_contactPicker.Base_Resize(clv_contactPicker.GetBase.Width, clv_contactPicker.GetBase.Height) 'Cambiamos el tamaño del panel interno de la lista para que ajuste al nuevo tamaño. + p_conEsp.Top = clv_contactPicker.GetBase.Top + clv_contactPicker.GetBase.Height + 20 + b_guardaConEsp.top = p_conEsp.Top + p_conEsp.Height + 20 +End Sub + +Sub CreateContactsItem(nom As String, Width As Int, Height As Int) As Panel 'ignore + Dim p As B4XView = xui.CreatePanel("") + p.SetLayoutAnimated(0, 0, 0, Width, Height) + p.LoadLayout("contactItem") + l_contact.Text = nom + p_contacts.Height = Height +' Log($"${p_contacts.Height}, ${l_contact.Height}"$) + cb_selectContact.Top = (p_contacts.Height/2) - (cb_selectContact.Height/2) + l_contact.Top = (p_contacts.Height/2) - (l_contact.Height/2) + Subs.SetButtonTintList(cb_selectContact, Colors.red, Colors.RGB(7, 183, 0)) + cb_selectContact.Tag = nom + l_contact.Text = nom + Return p +End Sub + +Private Sub clv_contactPicker_ItemClick (Index As Int, Value As Object) +' Log($"${Index}, ${Value}"$ ) + Dim cb As CheckBox = clv_contactPicker.GetPanel(Index).GetView(0).GetView(0) + If cb.Checked Then cb.Checked = False Else cb.Checked = True +End Sub + +Private Sub et_contEsp_FocusChanged (HasFocus As Boolean) +' If HasFocus Then +' muestraContactos +' End If +End Sub + +Private Sub cb_selectContact_CheckedChange(Checked As Boolean) + if starter.showLogs then Log(Sender.As(CheckBox).tag) + et_conEsp2.Text = "" + If Checked Then + contactosEspecificos.Add(Sender.As(CheckBox).tag) 'Si no está en la lista, lo agregamos. + Else + If contactosEspecificos.IndexOf(Sender.As(CheckBox).tag) > -1 Then + contactosEspecificos.RemoveAt(contactosEspecificos.IndexOf(Sender.As(CheckBox).tag)) 'Si ya esta en la lista lo quitamos. + End If + End If +' if starter.showLogs then Log(contactosEspecificos) + For Each c In contactosEspecificos + If et_conEsp2.Text <> "" Then et_conEsp2.Text = et_conEsp2.Text & ", " & c Else et_conEsp2.Text = c + Next +End Sub + +Private Sub b_guardaConEsp_Click + Dim l As List + l.initialize + Dim t() As String = Regex.Split(",", et_contEsp.text) + For i = 0 To t.Length-1 + l.add(t(i).trim) + Next + contactosEspecificos.AddAll(l) + contactosEspecificos = Subs.removeListDuplicates(contactosEspecificos) + et_contEsp.Text = "" + For Each c In contactosEspecificos + If et_contEsp.Text <> "" Then et_contEsp.Text = et_contEsp.Text & ", " & c Else et_contEsp.Text = c + Next + et_contEsp.text = et_contEsp.text.Replace(", ,", ",") + p_contactPicker.Visible = False + et_conEsp2.Text = "" + contactosEspecificos.Clear + clv_contactPicker.Clear + PCLV_AddItems +End Sub + +Private Sub b_getContacts_Click + muestraContactos +End Sub + +Sub addET(texto As String) + Dim etX As EditText + etX.Initialize("etX") + etX.TextColor = Colors.Black + etX.TextSize = 12 + etX.Tag = listaReglasContestaciones.size + listaReglasContestaciones.add(etX) + Dim newTop As Int = et_sale.top + et_sale.Height + If listaReglasContestaciones.Size > 0 Then + For k = 0 To listaReglasContestaciones.Size - 1 + newTop = newTop + listaReglasContestaciones.Get(k).As(EditText).Height + Next + End If + p_contestacion.AddView(etX, et_sale.left, newTop, et_sale.Width, 35dip) + etX.Text = texto +End Sub + +Private Sub b_addET_Click + addET("") +' Log("Agregamos ET, " & listaReglasContestaciones.size & "|" & etX.Tag & ", top=" & newTop) + RecalculateHeightViews +' Log(etX.top) +End Sub + +Sub etX_TextChanged (Old As String, New As String) +' Log(Sender.As(EditText).tag) + RecalculateHeightViews +End Sub \ No newline at end of file diff --git a/B4A/B4XPage3.bas b/B4A/B4XPage3.bas new file mode 100644 index 0000000..2d647fa --- /dev/null +++ b/B4A/B4XPage3.bas @@ -0,0 +1,77 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=9.86 +@EndOfDesignText@ +Sub Class_Globals + Private Root As B4XView 'ignore + Private xui As XUI 'ignore + Public cvs As B4XCanvas + Public Panel1 As B4XView +End Sub + +'You can add more parameters here. +Public Sub Initialize + +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("Page3") + cvs.Initialize(Panel1) + B4XPages.SetTitle(Me, "Draw Something") + #if B4A + B4XPages.AddMenuItem(Me, "Random Background") + #End If +End Sub + + + +'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage. + +Sub Panel1_Touch (Action As Int, X As Float, Y As Float) + If Action <> Panel1.TOUCH_ACTION_MOVE_NOTOUCH Then + cvs.DrawCircle(X, Y, 10dip, Rnd(xui.Color_Black, xui.Color_White), True, 0) + cvs.Invalidate + End If +End Sub + +Private Sub btnClear_Click + ClearImage +End Sub + +Public Sub ClearImage + If Panel1.IsInitialized Then + cvs.ClearRect(cvs.TargetRect) + cvs.Invalidate + End If +End Sub + +Sub btnSet_Click + B4XPages.ClosePage(Me) +End Sub + +Sub B4XPage_Resize (Width As Int, Height As Int) + ClearImage + cvs.Resize(Width, Height) +End Sub + +Sub B4XPage_MenuClick (Tag As String) + If Tag = "Random Background" Then + cvs.DrawRect(cvs.TargetRect, Rnd(xui.Color_Black, xui.Color_White), True, 0) + cvs.Invalidate + End If +End Sub + +#if B4J +'Delegate the native menu action to B4XPage_MenuClick. +Sub MenuBar1_Action + Dim mi As MenuItem = Sender + Dim t As String + If mi.Tag = Null Then t = mi.Text.Replace("_", "") Else t = mi.Tag + B4XPage_MenuClick(t) +End Sub +#End If \ No newline at end of file diff --git a/B4A/B4XPage4.bas b/B4A/B4XPage4.bas new file mode 100644 index 0000000..9525b97 --- /dev/null +++ b/B4A/B4XPage4.bas @@ -0,0 +1,24 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=11.45 +@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 + +End Sub + +'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage. \ No newline at end of file diff --git a/B4A/B4XReglas.bas b/B4A/B4XReglas.bas new file mode 100644 index 0000000..af0454f --- /dev/null +++ b/B4A/B4XReglas.bas @@ -0,0 +1,609 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=9.86 +@EndOfDesignText@ +Sub Class_Globals + Private Root As B4XView 'ignore + Private xui As XUI 'ignore + Dim ime As IME 'ignore +' Private lblHello As B4XView + Private ImageView1 As B4XView 'ignore +' Private Page3 As B4XPage3 + Private CustomListView1 As CustomListView 'ignore +' Private Tree As CLVTree +' Private b_colapsa As Button +' Private b_expande As Button +' Private Panel2 As Panel + Private clv_reglas2 As CustomListView + Private et_regla As EditText + Private p_rules As Panel + Private l_tit As Label +' Private l_rule As Label + Private p_reglas As Panel + Private l_tit2 As Label + Private et_regla2 As EditText + Private cb_activa As CheckBox + Private l_regla As Label + Private p_editarRegla As Panel + Private et_nombre As EditText + Private b_cancelar As Button + Private et_entra As EditText + Private et_sale As EditText + Private l_sale As Label + Private l_regla_1 As Label + Private l_regla_2 As Label + Private p_separador As Panel + Private r_destinatario_p As RadioButton + Private r_destinatario_g As RadioButton + Private r_destinatario_a As RadioButton + Dim destinatario As String = "Personas" + Private l_flecha As Label + Private fb_add As cvFloatingBtn + Private p_msgBox As Panel + Private l_msgBoxTitle As Label + Private l_msgBoxText As Label + Private b_msgBoxYes As Button + Private b_msgBoxNo As Button + Private p_sombra As Panel + Private p_contestacion As Panel + Private l_sale2 As Label + Private et_sale2 As EditText + Private p_recibimos As Panel + Private l_entra As Label + Private p_contactosEspecificos As Panel + Private et_contEsp As EditText + Private l_contEsp As Label + Dim contactsPermission As Boolean = False + Private clv_contactPicker As CustomListView + Private PCLV As PreoptimizedCLV + Private l_contact As Label + Private cb_selectContact As CheckBox + Private p_contacts As Panel + Private p_contactPicker As Panel + Dim contactosEspecificos As List + Private p_conEsp As Panel + Private b_guardaConEsp As Button + Private et_conEsp As EditText + Private et_conEsp2 As EditText + Private b_getContacts As Button + Dim listaReglasContestaciones As List + Private b_addET As Button + Private ScrollView1 As ScrollView + Private l_idRegla As Label +End Sub + +'You can add more parameters here. +Public Sub Initialize + +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("Reglas") +' Root.LoadLayout("floatbutton_layout") + B4XPages.SetTitle(Me, "Reglas") +' Page3 = B4XPages.GetPage("Page 3") + contactosEspecificos.Initialize + PCLV.Initialize(Me, "PCLV", clv_contactPicker) + PCLV_AddItems + muestraReglas +End Sub + +Private Sub B4XPage_Appear + If Starter.logger Then Log("======================= REGLAS =====================") + Subs.traeReglas +' NotificationService.mapReglas = Subs.traeReglas +' clv_reglas2.Clear +' clv_reglas2.PressedColor = Colors.Transparent +' For Each m As Map In NotificationService.mapReglas.Values +' clv_reglas2.Add(CreateListItem(m.get("id"), m.get("nombre"), "Recibimos:", m.Get("recibe"), "Contestamos:", m.Get("contesta"), m.Get("activa"), 386dip, 90dip), m.get("id")) +' Next +' p_editarRegla.Visible = False +' p_sombra.Visible = False +' p_reglas.Width = Root.Width - 20 +' Subs.centraPanel(p_editarRegla, Root.Width) +End Sub + +Sub clv_contactPicker_VisibleRangeChanged (FirstIndex As Int, LastIndex As Int) + For Each i As Int In PCLV.VisibleRangeChanged(FirstIndex, LastIndex) + Dim item As CLVItem = clv_contactPicker.GetRawListItem(i) + Dim pnl As B4XView = xui.CreatePanel("") + pnl.Color = Colors.White + item.Color = Colors.White + item.Panel.AddView(pnl, 0, 0, item.Panel.Width, item.Panel.Height) + 'Create the item layout + pnl.LoadLayout("contactItem") + cb_selectContact.Tag = item.Value + l_contact.Text = item.Value + Next +End Sub + +Sub PCLV_AddItems + For Each contact As String In Subs.getContactos + PCLV.AddItem(40dip, xui.Color_White, contact) + Next + PCLV.Commit +End Sub + +'Return the hint that will be displayed when the user fast scrolls the list. It can be a string or CSBuilder. +Sub PCLV_HintRequested (Index As Int) As Object + Dim word As String = clv_contactPicker.GetValue(Index) + Return word +End Sub + +Sub muestraReglas + NotificationService.mapReglas = Subs.traeReglas +' Log("mapReglas=" & NotificationService.mapReglas) + clv_reglas2.Clear + clv_reglas2.PressedColor = Colors.Transparent +' clv_reglas2.AsView.Color = Colors.red + For Each m As Map In NotificationService.mapReglas.Values + clv_reglas2.Add(CreateListItem(m.get("id"), m.get("nombre"), "Recibimos:", m.Get("recibe"), "Contestamos:", m.Get("contesta"), m.Get("activa"), 386dip, 90dip), m.get("id")) + Next + p_editarRegla.Visible = False + p_sombra.Visible = False + p_reglas.Width = Root.Width + p_reglas.Height = Root.Height - 20 + fb_add.Top = p_reglas.Height - 50dip + fb_add.Left = p_reglas.Width - 50dip + clv_reglas2.GetBase.SetLayoutAnimated(0, 5dip, 5dip, Root.Width + 10, Root.Height) 'Cambiamos el tamaño y posición de la lista de reglas + clv_reglas2.Base_Resize(clv_reglas2.GetBase.Width, clv_reglas2.GetBase.Height) 'Cambiamos el tamaño del panel interno de la lista para que ajuste al nuevo tamaño. + p_sombra.Width = Root.Width + p_sombra.Height = Root.Height + If Starter.logger Then Log($"${Root.Width}, ${p_reglas.Width}, ${p_sombra.Width}, ${clv_reglas2.AsView.Width }"$) + Subs.centraPanel(p_editarRegla, Root.Width) +' Subs.centraPanel(p_sombra, Root.Width) +End Sub + +Sub CreateListItem(id As Int, nom As String, tit As String, rule As String, tit2 As String, rule2 As String, activa As Int, Width As Int, Height As Int) As Panel + Dim p As B4XView = xui.CreatePanel("") + Dim active As Boolean = False +' Private pLeft = p_rules.left + If activa = 1 Then active = True + p.SetLayoutAnimated(0, 0, 0, Width, Height) + p.LoadLayout("ruleItem") + l_tit.Text = tit + l_regla_1.Text = rule + l_tit2.Text = tit2 + l_regla_2.Text = rule2 + p_rules.Width = Root.Width - 10dip + Subs.SetButtonTintList(cb_activa, Colors.red, Colors.RGB(7, 183, 0)) + If nom.IndexOf(".") > -1 Then + Private cuantos As Int = Subs.CountChars(nom, ".") +' Log(cuantos) + Private leftOffs As Int = 15 + If cuantos > 0 Then leftOffs = leftOffs * cuantos + p_rules.Left = p_rules.Left + leftOffs + p_rules.Width = p_rules.Width - leftOffs + l_regla_1.Width = l_regla_1.Width - leftOffs + l_regla_2.Width = l_regla_2.Width - leftOffs + cb_activa.Left = cb_activa.Left - leftOffs + Dim cd1 As ColorDrawable + cd1.Initialize2(Colors.White, 30, 5, Colors.Red) + l_regla.TextColor = Colors.red +' l_flecha.TextColor = Colors.red +' p_rules.Color = Colors.RGB(209, 0, 0) + p_rules.Background = cd1 + + If cuantos > 0 Then + l_flecha.Visible = True + l_regla.Left = l_regla.Left + 40 +' If cuantos = 2 Then p_rules.Color = Colors.RGB(134, 246, 126) +' If cuantos > 2 Then p_rules.Color = Colors.RGB(217, 217, 217) + If cuantos = 2 Then + cd1.Initialize2(Colors.White, 30, 5, Colors.Gray) + l_regla.TextColor = Colors.Gray +' l_flecha.TextColor = Colors.Gray + End If + If cuantos = 3 Then + cd1.Initialize2(Colors.White, 30, 6, Colors.RGB(255, 140, 125)) + l_regla.TextColor = Colors.RGB(255, 140, 125) +' l_flecha.TextColor = Colors.RGB(255, 140, 125) + End If + If cuantos > 3 Then + cd1.Initialize2(Colors.White, 30, 6, Colors.RGB(250, 161, 38)) + l_regla.TextColor = Colors.RGB(250, 161, 38) +' l_regla.TextColor = Colors.RGB(250, 161, 38) + End If + p_rules.Background = cd1 + End If + End If + + Dim su As StringUtils + ' recalculate new heights +' Dim prhTemp As Int = p_rules.Height + l_regla_1.height = su.MeasureMultilineTextHeight(l_regla_1, l_regla_1.Text) + l_regla_2.height = su.MeasureMultilineTextHeight(l_regla_2, l_regla_2.Text) + p_separador.Top = l_regla_1.Top + l_regla_1.Height + 10 + l_tit2.Top = p_separador.Top + 20 + l_regla_2.Top = l_tit2.top + p_rules.Height = l_regla_1.Height + l_regla_2.Height + 110 + p.SetLayoutAnimated(0, 0, 0, Width, p_rules.Height +10) + + cb_activa.Checked = active + cb_activa.Tag = id + l_regla.Text = nom + l_regla.Tag = id + Return p +End Sub + +'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage. +Sub b_1_Click +' B4XPages.ShowPage("Page 3") +End Sub + +Sub btnSignOut_Click +' Page3.ClearImage +' UpdateImage +' B4XPages.ShowPageAndRemovePreviousPages("MainPage") +End Sub + +Private Sub cb_activa_CheckedChange(Checked As Boolean) + Dim chk As CheckBox = Sender +' if starter.showLogs then Log(Checked & " | " & chk.tag ) + If chk.Tag <> Null And chk.Tag <> "" Then + Dim p_regla As Panel = Sender.As(View).Parent.As(Panel) +' if starter.showLogs then Log("|"&p_regla.NumberOfViews) + Private idRegla As Int = chk.tag + Private activa As Boolean = Checked +' Private recibimos As String = p_regla.GetView(1).as(Label).text +' Private mandamos As String = p_regla.GetView(3).as(Label).text + If Starter.showLogs Then Log("|"&p_regla.GetView(5)) + Subs.guardaRegla(idRegla, activa) + NotificationService.mapReglas = Subs.traeReglas + End If +' Log(NotificationService.mapReglas) +End Sub + +'Borramos la regla. +Sub cb_activa_LongClick + Private chk As CheckBox = Sender + If Starter.showLogs Then Log(chk.tag) + p_msgBox.Top = (Root.Height/2) - (p_msgBox.Height/2) + Subs.centraPanel(p_msgBox, Root.Width) + l_msgBoxTitle.Text = "Borrar regla" + l_msgBoxText.text = $"¿Seguro que desea borrar la regla ${chk.tag}?"$ + p_msgBox.Visible = True + b_msgBoxYes.Tag = chk.tag + p_msgBox.Tag = clv_reglas2.GetItemFromView(Sender.As(View)) + If Starter.showLogs Then LogColor(p_msgBox.tag, Colors.Magenta) +' if starter.showLogs then LogColor(clv_reglas2.Size,Colors.Magenta) +End Sub + +Private Sub b_msgBoxYes_Click + p_msgBox.Visible = False + If Starter.showLogs Then Log(Sender.As(Button).tag) + Subs.borrarRegla(Sender.As(Button).tag) + NotificationService.mapReglas = Subs.traeReglas +' B4XPage_Appear + clv_reglas2.RemoveAt(p_msgBox.Tag) +' muestraReglas +End Sub + +Private Sub b_msgBoxNo_Click + p_msgBox.Visible = False +End Sub + +Sub p_msgBox_Click + 'Do nothing +End Sub + +Private Sub et_regla_TextChanged (Old As String, New As String) + Dim p_regla As Panel = Sender.As(View).Parent.As(Panel) + Private cb As CheckBox = p_regla.GetView(2) + cb.Checked = False +' Log(cb.checked) +End Sub + +Private Sub et_regla2_TextChanged (Old As String, New As String) + Dim p_regla As Panel = Sender.As(View).Parent.As(Panel) + Private cb As CheckBox = p_regla.GetView(2) + cb.Checked = False +' Log(cb.checked) +End Sub + +Private Sub L_regla_LongClick +' et_nombre.Text = Sender.As(Label).text +' et_nombre.Tag = Sender.As(Label).tag +' Log(Sender.As(Label)) +'' Log(Sender.As(Label).Tag & "|"&NotificationService.mapReglas) +' Private d As Map = NotificationService.mapReglas.Get(Sender.As(Label).tag) +'' Log(d) +' et_entra.Text = d.Get("recibe") +' et_sale.Text = d.Get("contesta") +' p_editarRegla.visible = True +' RecalculateHeightViews +End Sub + +Private Sub b_guardar_Click + For i = 0 To listaReglasContestaciones.Size -1 + et_sale.Text = et_sale.Text & "//" & listaReglasContestaciones.Get(i).As(EditText).text + Next + If Starter.showLogs Then Log(et_sale.text) + Subs.actualizaRegla(et_nombre.Tag, et_nombre.text, et_entra.Text, et_sale.text, r_destinatario_p.tag, et_contEsp.text) +' NotificationService.mapReglas = Subs.traeReglas + muestraReglas + p_editarRegla.Visible = False + p_sombra.Visible = False + ime.HideKeyboard +End Sub + +Private Sub b_cancelar_Click + p_editarRegla.Visible = False + p_editarRegla.SendToBack +' ScrollView1.Visible = False + p_sombra.Visible = False + ime.HideKeyboard +End Sub + +Sub RecalculateHeightViews +' Log("Recalcula") + Dim su As StringUtils + 'Recalculate new heights + et_entra.height = su.MeasureMultilineTextHeight(et_entra, et_entra.Text) + 60 + et_sale.height = su.MeasureMultilineTextHeight(et_sale, et_sale.Text)+ 60 + et_contEsp.Height = su.MeasureMultilineTextHeight(et_contEsp, et_contEsp.Text)+ 60 + p_recibimos.Height = et_entra.Height + 20 + p_contestacion.Height = et_sale.Height + 20 + p_contactosEspecificos.Height = et_contEsp.Height + 20 + ' Recalculate new vertical positions + p_recibimos.Top =l_entra.Top + l_entra.Height + 5 + l_sale.Top = p_recibimos.Top + p_recibimos.height + 5 + p_contestacion.Top = l_sale.Top + l_sale.height + 5 + If listaReglasContestaciones.Size > 0 Then + For j = 0 To listaReglasContestaciones.Size - 1 + listaReglasContestaciones.Get(j).As(EditText).Height = su.MeasureMultilineTextHeight(listaReglasContestaciones.Get(j).As(EditText), listaReglasContestaciones.Get(j).As(EditText).Text) + 60 + p_contestacion.Height = p_contestacion.Height + listaReglasContestaciones.Get(j).As(EditText).Height - 15 + Next + End If + ScrollView1.Panel.Height = p_recibimos.Height + p_contestacion.Height + p_contactosEspecificos.Height + 500 + For n = 0 To listaReglasContestaciones.Size - 1 + If n = 0 Then + listaReglasContestaciones.Get(n).As(EditText).Top = et_sale.Top + et_sale.Height - 15 + Else if n > 0 Then + listaReglasContestaciones.Get(n).As(EditText).Top = listaReglasContestaciones.Get(n-1).As(EditText).Top + listaReglasContestaciones.Get(n-1).As(EditText).Height - 15 + End If +' LogColor(listaReglasContestaciones.Get(n).As(EditText).Top, Colors.red) + Next + r_destinatario_p.Top = p_contestacion.Top + p_contestacion.Height + r_destinatario_g.Top = r_destinatario_p.top + r_destinatario_a.Top = r_destinatario_p.top + l_contEsp.Top = r_destinatario_p.Top + r_destinatario_p.Height + b_addET.Top = l_sale.top - 1 + b_getContacts.Top = l_contEsp.top - 5 + p_contactosEspecificos.Top = l_contEsp.Top + l_contEsp.Height +End Sub + +Private Sub et_entra_TextChanged (Old As String, New As String) + RecalculateHeightViews +End Sub + +Private Sub et_sale_TextChanged (Old As String, New As String) + RecalculateHeightViews +End Sub + +Private Sub et_sale2_TextChanged (Old As String, New As String) + RecalculateHeightViews +End Sub + +Private Sub et_contEsp_TextChanged (Old As String, New As String) + RecalculateHeightViews +End Sub + +Private Sub clv_reglas2_ItemClick (Index As Int, Value As Object) + If Starter.showLogs Then Log(Index &"|" & Value) + listaReglasContestaciones.Initialize +' p_editarRegla.Visible = True +' p_editarRegla.BringToFront + ScrollView1.Panel.RemoveAllViews + ScrollView1.Panel.LoadLayout("editaRegla") + ScrollView1.Height = p_editarRegla.Height * 0.9 + ScrollView1.Panel.Height = ScrollView1.Height + Private et_sale As EditText + et_sale.Initialize("et_sale") + et_sale.TextColor = Colors.Black + et_sale.TextSize = 15 + p_contestacion.RemoveAllViews + p_contestacion.AddView(et_sale, 10, 10, (p_contestacion.Width*0.95), 30dip) + Private d As Map = NotificationService.mapReglas.Get(Value) + If Starter.showLogs Then Log(d) + et_entra.InputType = Bit.Or(0x00080000, 0x00000090) 'TYPE_TEXT_FLAG_NO_SUGGESTIONS | TYPE_TEXT_VARIATION_VISIBLE_PASSWORD + et_entra.SingleLine = False + et_sale.InputType = Bit.Or(0x00080000, 0x00000090) 'TYPE_TEXT_FLAG_NO_SUGGESTIONS | TYPE_TEXT_VARIATION_VISIBLE_PASSWORD + et_sale.SingleLine = False + et_contEsp.InputType = Bit.Or(0x00080000, 0x00000090) 'TYPE_TEXT_FLAG_NO_SUGGESTIONS | TYPE_TEXT_VARIATION_VISIBLE_PASSWORD + et_contEsp.SingleLine = False + et_nombre.Tag = Value + et_nombre.Text = d.Get("nombre") + l_idRegla.Text = "(" & d.Get("id") & ")" + et_entra.Text = d.Get("recibe") + Private ets() As String = Regex.Split("//", d.Get("contesta")) 'Dividimos el regla en sus multiples respuestas. +' et_sale.Text = d.Get("contesta") + et_sale.Text = ets(0).trim + If ets.Length > 1 Then + For x = 1 To ets.Length - 1 + addET(ets(x).Trim) + Next + End If + destinatario = "Personas" + If d.Get("destinatario") <> Null Then destinatario = d.Get("destinatario") + If destinatario = "Personas" Then r_destinatario_p.Checked = True + If destinatario = "Grupos" Then r_destinatario_g.Checked = True + If destinatario = "Ambos" Then r_destinatario_a.Checked = True + et_contEsp.Text = d.Get("contactoEspecifico") + r_destinatario_p.Tag = destinatario + p_editarRegla.visible = True + p_sombra.Visible = True + If Starter.showLogs Then Log(contactsPermission) +' If contactsPermission Then +' Dim res As List = InputMultiList(Subs.getContactos, "Select") +' Log(res) +' End If + RecalculateHeightViews +End Sub + +Private Sub r_destinatario_p_CheckedChange(Checked As Boolean) + If Starter.showLogs Then Log(Sender.As(RadioButton).text & "|" &Checked) + destinatario = Sender.As(RadioButton).text + r_destinatario_p.Tag = destinatario +End Sub + +Private Sub r_destinatario_g_CheckedChange(Checked As Boolean) + If Starter.showLogs Then Log(Sender.As(RadioButton).text & "|" &Checked) + destinatario = Sender.As(RadioButton).text + r_destinatario_p.Tag = destinatario +End Sub + +Private Sub r_destinatario_a_CheckedChange(Checked As Boolean) +' Log(Sender.As(RadioButton).text & "|" &Checked) + destinatario = Sender.As(RadioButton).text + r_destinatario_p.Tag = destinatario +End Sub + +'Agregamos regla. +Sub fb_add_Clicked(X As Float,Y As Float) +' ToastMessageShow("Button Clicked",False) + Subs.agregaRegla + NotificationService.mapReglas = Subs.traeReglas +' B4XPage_Appear + muestraReglas +End Sub + +Private Sub B4XPage_CloseRequest As ResumableSub + Sleep(0) + If Starter.showLogs Then Log("B4XPage_CloseRequest") +' if starter.showLogs then Log(p_contactPicker.Visible) + If p_contactPicker.Visible = True Then + p_contactPicker.Visible = False + Return False + End If + If p_editarRegla.Visible Then + p_editarRegla.Visible = False + p_sombra.Visible = False + Return False + End If + Return True +End Sub + +Private Sub p_editarRegla_Click + 'Nothing here. +End Sub + +Private Sub p_sombra_Click + 'Nothing here. +End Sub + +Sub muestraContactos + If Starter.showLogs Then Log("muestraContactos") + p_contactPicker.Visible = True + ime.HideKeyboard + p_contactPicker.left = 0 + p_contactPicker.Top = 0 + p_contactPicker.Width = Root.Width + p_contactPicker.Height = Root.Height + clv_contactPicker.GetBase.SetLayoutAnimated(0, 5dip, 30dip, Root.Width - 10, Root.Height * 0.68) 'Cambiamos el tamaño y posición de la lista de productos + clv_contactPicker.Base_Resize(clv_contactPicker.GetBase.Width, clv_contactPicker.GetBase.Height) 'Cambiamos el tamaño del panel interno de la lista para que ajuste al nuevo tamaño. + p_conEsp.Top = clv_contactPicker.GetBase.Top + clv_contactPicker.GetBase.Height + 20 + b_guardaConEsp.top = p_conEsp.Top + p_conEsp.Height + 20 +End Sub + +Sub CreateContactsItem(nom As String, Width As Int, Height As Int) As Panel 'ignore + Dim p As B4XView = xui.CreatePanel("") + p.SetLayoutAnimated(0, 0, 0, Width, Height) + p.LoadLayout("contactItem") + l_contact.Text = nom + p_contacts.Height = Height +' Log($"${p_contacts.Height}, ${l_contact.Height}"$) + cb_selectContact.Top = (p_contacts.Height/2) - (cb_selectContact.Height/2) + l_contact.Top = (p_contacts.Height/2) - (l_contact.Height/2) + Subs.SetButtonTintList(cb_selectContact, Colors.red, Colors.RGB(7, 183, 0)) + cb_selectContact.Tag = nom + l_contact.Text = nom + Return p +End Sub + +Private Sub clv_contactPicker_ItemClick (Index As Int, Value As Object) +' Log($"${Index}, ${Value}"$ ) + Dim cb As CheckBox = clv_contactPicker.GetPanel(Index).GetView(0).GetView(0) + If cb.Checked Then cb.Checked = False Else cb.Checked = True +End Sub + +Private Sub et_contEsp_FocusChanged (HasFocus As Boolean) +' If HasFocus Then +' muestraContactos +' End If +End Sub + +Private Sub cb_selectContact_CheckedChange(Checked As Boolean) + If Starter.showLogs Then Log(Sender.As(CheckBox).tag) + et_conEsp2.Text = "" + If Checked Then + contactosEspecificos.Add(Sender.As(CheckBox).tag) 'Si no está en la lista, lo agregamos. + Else + If contactosEspecificos.IndexOf(Sender.As(CheckBox).tag) > -1 Then + contactosEspecificos.RemoveAt(contactosEspecificos.IndexOf(Sender.As(CheckBox).tag)) 'Si ya esta en la lista lo quitamos. + End If + End If +' if starter.showLogs then Log(contactosEspecificos) + For Each c In contactosEspecificos + If et_conEsp2.Text <> "" Then et_conEsp2.Text = et_conEsp2.Text & ", " & c Else et_conEsp2.Text = c + Next +End Sub + +Private Sub b_guardaConEsp_Click + Dim l As List + l.initialize + Dim t() As String = Regex.Split(",", et_contEsp.text) + For i = 0 To t.Length-1 + l.add(t(i).trim) + Next + contactosEspecificos.AddAll(l) + contactosEspecificos = Subs.removeListDuplicates(contactosEspecificos) + et_contEsp.Text = "" + For Each c In contactosEspecificos + If et_contEsp.Text <> "" Then et_contEsp.Text = et_contEsp.Text & ", " & c Else et_contEsp.Text = c + Next + et_contEsp.text = et_contEsp.text.Replace(", ,", ",") + p_contactPicker.Visible = False + et_conEsp2.Text = "" + contactosEspecificos.Clear + clv_contactPicker.Clear + PCLV_AddItems +End Sub + +Private Sub b_getContacts_Click + muestraContactos +End Sub + +Sub addET(texto As String) + Dim etX As EditText + etX.Initialize("etX") + etX.TextColor = Colors.Black + etX.TextSize = 12 + etX.Tag = listaReglasContestaciones.size + listaReglasContestaciones.add(etX) + Dim newTop As Int = et_sale.top + et_sale.Height + If listaReglasContestaciones.Size > 0 Then + For k = 0 To listaReglasContestaciones.Size - 1 + newTop = newTop + listaReglasContestaciones.Get(k).As(EditText).Height + Next + End If + p_contestacion.AddView(etX, et_sale.left, newTop, et_sale.Width, 35dip) + etX.Text = texto +End Sub + +Private Sub b_addET_Click + addET("") +' Log("Agregamos ET, " & listaReglasContestaciones.size & "|" & etX.Tag & ", top=" & newTop) + RecalculateHeightViews +' Log(etX.top) +End Sub + +Sub etX_TextChanged (Old As String, New As String) +' Log(Sender.As(EditText).tag) + RecalculateHeightViews +End Sub diff --git a/B4A/DBRequestManager.bas b/B4A/DBRequestManager.bas new file mode 100644 index 0000000..140d51d --- /dev/null +++ b/B4A/DBRequestManager.bas @@ -0,0 +1,271 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=6.8 +@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 - 211027 +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. +'Timeout - The http request timeout in ms, or 0 if default (30 secs) +Public Sub ExecuteQuery(Command As DBCommand, Limit As Int, Tag As Object, Timeout As Int) 'Mod por CHV, agregué el parametro Timeout - 211229 + 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) + If Timeout <> 0 Then j.GetRequest.Timeout = Timeout +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 +' Log("HandleJob: " & (DateTime.Now - start)) + 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) + If Starter.logger Then 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 + If Starter.logger Then 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/DBRequestManagerV1.bas b/B4A/DBRequestManagerV1.bas new file mode 100644 index 0000000..b10711a --- /dev/null +++ b/B4A/DBRequestManagerV1.bas @@ -0,0 +1,271 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=6.8 +@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 - 211027 +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. +'Timeout - The http request timeout in ms, or 0 if default (30 secs) +Public Sub ExecuteQuery(Command As DBCommand, Limit As Int, Tag As Object, Timeout As Int) 'Mod por CHV, agregué el parametro Timeout - 211229 + 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) + If Timeout <> 0 Then j.GetRequest.Timeout = Timeout +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 +' Log("HandleJob: " & (DateTime.Now - start)) + 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/DBRequestManagerV2.bas b/B4A/DBRequestManagerV2.bas new file mode 100644 index 0000000..93bff84 --- /dev/null +++ b/B4A/DBRequestManagerV2.bas @@ -0,0 +1,149 @@ +B4J=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=5.45 +@EndOfDesignText@ +'Requires support for resumable subs +'Class module + +Sub Class_Globals + Private mTarget As Object + Private link As String + Private VERSION As Float = 2 + +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, Timeout As Int) As HttpJob + Dim ser As B4XSerializator + Dim data() As Byte = ser.ConvertObjectToBytes(CreateMap("command": Command, "limit": Limit, "version": VERSION)) + Return SendJob(CreateJob, data, Tag, "query2", Timeout) +End Sub + +Private Sub SendJob(j As HttpJob, Data() As Byte, Tag As Object, Method As String, Timeout As Int) As HttpJob + j.Tag = Tag + j.PostBytes(link & "?method=" & Method , Data) + If Timeout <> 0 Then j.GetRequest.Timeout = Timeout + Return j +End Sub + +Private Sub CreateJob As HttpJob + Dim j As HttpJob + j.Initialize("DBRequest", mTarget) + Return j +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) As HttpJob + Dim j As HttpJob = CreateJob + ExecuteBatchImpl(j, ListOfCommands, Tag) + Return j +End Sub + +Private Sub ExecuteBatchImpl(Job As HttpJob, ListOfCommands As List, Tag As Object) + Dim ser As B4XSerializator + ser.ConvertObjectToBytesAsync(CreateMap("commands": ListOfCommands, "version": VERSION), "ser") + Wait For (ser) ser_ObjectToBytes (Success As Boolean, Bytes() As Byte) + If Success = False Then + Log("Error building command: " & LastException) + Return + End If + Dim ser As B4XSerializator = Sender + SendJob(Job, Bytes, Tag, "batch2", 0) +End Sub + + +'Similar to ExecuteBatch. Sends a single command. +Public Sub ExecuteCommand(Command As DBCommand, Tag As Object) As HttpJob + Return ExecuteBatch(Array As DBCommand(Command), Tag) +End Sub + +'Handles the Job result and returns a DBResult. +'It is recommended to use HandleJobAsync instead. +Public Sub HandleJob(Job As HttpJob) As DBResult + Dim ser As B4XSerializator + Dim data() As Byte = Bit.InputStreamToBytes(Job.GetInputStream) + Dim res As DBResult = ser.ConvertBytesToObject(data) + res.Tag = Job.Tag + Return res +End Sub +'Handles the Job result and raises the Result event when the data is ready. + +Public Sub HandleJobAsync(Job As HttpJob, EventName As String) + Dim ser As B4XSerializator + Dim data() As Byte = Bit.InputStreamToBytes(Job.GetInputStream) + ser.ConvertBytesToObjectAsync(data, "ser") + Wait For (ser) ser_BytesToObject (Success As Boolean, NewObject As Object) + If Success = False Then + Log("Error reading response: " & LastException) + Return + End If + Dim res As DBResult = NewObject + res.Tag = Job.Tag + CallSubDelayed2(mTarget, EventName & "_result", res) +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 +#if Not(B4J) +'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 +#End If + +'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 + Log(sb.ToString) + Next +End Sub + + diff --git a/B4A/Files/add.png b/B4A/Files/add.png new file mode 100644 index 0000000..0604bac Binary files /dev/null and b/B4A/Files/add.png differ diff --git a/B4A/Files/add2.png b/B4A/Files/add2.png new file mode 100644 index 0000000..31edc3a Binary files /dev/null and b/B4A/Files/add2.png differ diff --git a/B4A/Files/chatbot6_191x191.png b/B4A/Files/chatbot6_191x191.png new file mode 100644 index 0000000..b08a0ff Binary files /dev/null and b/B4A/Files/chatbot6_191x191.png differ diff --git a/B4A/Files/chatbot7_191x191.png b/B4A/Files/chatbot7_191x191.png new file mode 100644 index 0000000..0aabc7b Binary files /dev/null and b/B4A/Files/chatbot7_191x191.png differ diff --git a/B4A/Files/contactitem.bal b/B4A/Files/contactitem.bal new file mode 100644 index 0000000..209f269 Binary files /dev/null and b/B4A/Files/contactitem.bal differ diff --git a/B4A/Files/editaregla.bal b/B4A/Files/editaregla.bal new file mode 100644 index 0000000..b8f078e Binary files /dev/null and b/B4A/Files/editaregla.bal differ diff --git a/B4A/Files/errores.db b/B4A/Files/errores.db new file mode 100644 index 0000000..b10e173 Binary files /dev/null and b/B4A/Files/errores.db differ diff --git a/B4A/Files/floatbutton_layout.bal b/B4A/Files/floatbutton_layout.bal new file mode 100644 index 0000000..118c9f1 Binary files /dev/null and b/B4A/Files/floatbutton_layout.bal differ diff --git a/B4A/Files/imagenes.bal b/B4A/Files/imagenes.bal new file mode 100644 index 0000000..f53430e Binary files /dev/null and b/B4A/Files/imagenes.bal differ diff --git a/B4A/Files/imgitem.bal b/B4A/Files/imgitem.bal new file mode 100644 index 0000000..8ab8dcb Binary files /dev/null and b/B4A/Files/imgitem.bal differ diff --git a/B4A/Files/mainpage.bal b/B4A/Files/mainpage.bal new file mode 100644 index 0000000..44f2ac7 Binary files /dev/null and b/B4A/Files/mainpage.bal differ diff --git a/B4A/Files/page2.bal b/B4A/Files/page2.bal new file mode 100644 index 0000000..a5b13c1 Binary files /dev/null and b/B4A/Files/page2.bal differ diff --git a/B4A/Files/page3.bal b/B4A/Files/page3.bal new file mode 100644 index 0000000..28eeca3 Binary files /dev/null and b/B4A/Files/page3.bal differ diff --git a/B4A/Files/reglas.bal b/B4A/Files/reglas.bal new file mode 100644 index 0000000..db1655b Binary files /dev/null and b/B4A/Files/reglas.bal differ diff --git a/B4A/Files/reglas.db b/B4A/Files/reglas.db new file mode 100644 index 0000000..4216872 Binary files /dev/null and b/B4A/Files/reglas.db differ diff --git a/B4A/Files/robot-icons_2_191x191.png b/B4A/Files/robot-icons_2_191x191.png new file mode 100644 index 0000000..49fb61e Binary files /dev/null and b/B4A/Files/robot-icons_2_191x191.png differ diff --git a/B4A/Files/robot3_191x191.png b/B4A/Files/robot3_191x191.png new file mode 100644 index 0000000..8aa0009 Binary files /dev/null and b/B4A/Files/robot3_191x191.png differ diff --git a/B4A/Files/robot4_191x191.png b/B4A/Files/robot4_191x191.png new file mode 100644 index 0000000..61ff555 Binary files /dev/null and b/B4A/Files/robot4_191x191.png differ diff --git a/B4A/Files/robot8_191x191.png b/B4A/Files/robot8_191x191.png new file mode 100644 index 0000000..8070acc Binary files /dev/null and b/B4A/Files/robot8_191x191.png differ diff --git a/B4A/Files/robot_192x192.png b/B4A/Files/robot_192x192.png new file mode 100644 index 0000000..1fb0408 Binary files /dev/null and b/B4A/Files/robot_192x192.png differ diff --git a/B4A/Files/robotic_191x191.png b/B4A/Files/robotic_191x191.png new file mode 100644 index 0000000..4d2fae7 Binary files /dev/null and b/B4A/Files/robotic_191x191.png differ diff --git a/B4A/Files/ruleitem.bal b/B4A/Files/ruleitem.bal new file mode 100644 index 0000000..8e06100 Binary files /dev/null and b/B4A/Files/ruleitem.bal differ diff --git a/B4A/NotificationService.bas b/B4A/NotificationService.bas new file mode 100644 index 0000000..63198ec --- /dev/null +++ b/B4A/NotificationService.bas @@ -0,0 +1,1042 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Service +Version=11 +@EndOfDesignText@ +#Region Service Attributes + #StartAtBoot: False +#End Region + +Sub Process_Globals + 'These global variables will be declared once when the application starts. + 'These variables can be accessed from all modules. + Dim rp As ReplyAuto + Dim status As String = "Servicio Activo" + Dim notisMap2 As Map + Dim nsStatus, starterStatus As Map + Dim mapReglas As Map = CreateMap() +' Type reglasUsuario(numero As String, histRegas As List) + Type notificacionesGuardadasType(numero As String, notif As StatusBarNotification) + Dim notificacionesGuardadas As Map + Dim notificacionesPorContestar As List + Dim histReglas As Map + Dim reqManager As DBRequestManager + Dim cmd As DBCommand + Dim numRemitente As String = "" + Dim cont As Int = 0 + Dim espera As Int = 100 + Dim procesandoNotificaciones As Boolean = False + Dim notisIds As Map + Dim DBRChecked As Boolean + Dim pruebaPaso As Int = 0 +End Sub + +Sub Service_Create + If status = "Servicio Activo" Then + rp.Initialize("Bow2") +' notisMap2.Initialize +' If starter.Logger Then LogColor("notiService Created", Colors.Magenta) + If Not(nsStatus.IsInitialized) Then nsStatus.Initialize + nsStatus.put(Subs.fechaKMT(DateTime.now),"inicia") + mapReglas = Subs.traeReglas + notificacionesGuardadas.Initialize + notificacionesPorContestar.Initialize + histReglas.Initialize + reqManager.Initialize(Me, Starter.DBRServer) + Service.StartForeground(747, CreateNotification("Servicio Activo")) + notisIds.Initialize + End If +End Sub + +Sub Service_Start (StartingIntent As Intent) + If status = "Servicio Activo" Then +' If starter.Logger Then LogColor("notiService Start - " & cont, Colors.Magenta) + If cont > 25 Then 'Regeneramos la notificación permanente despues de 25 notificaciones varias. + Service.StartForeground(747, CreateNotification(status)) + cont = 0 + End If + cont = cont + 1 + If Not(notisMap2.IsInitialized) Then notisMap2.Initialize + If notisMap2.Size = 0 And Starter.notisMap2.IsInitialized Then +' If starter.Logger Then Log($"nsNotisMap2.size=${notisMap2.Size}, Starter.notisMap2=${Starter.notisMap2.size}"$) + notisMap2.Initialize + notisMap2 = Starter.notisMap2 +' If starter.Logger Then LogColor("Copie notisMap2 desde Starter.notisMap2, tamaño=" & notisMap2.Size, Colors.Green) + End If + If Not(nsStatus.IsInitialized) Then nsStatus.Initialize + If Starter.nsStatus.IsInitialized Then nsStatus = Starter.nsStatus + If Starter.starterStatus.IsInitialized Then + starterStatus.Initialize + starterStatus = Starter.starterStatus + Else If Not(Starter.starterStatus.IsInitialized) And starterStatus.IsInitialized Then + Starter.starterStatus.Initialize + Starter.starterStatus = nsStatus + Else + starterStatus.Initialize + Starter.starterStatus.Initialize + starterStatus.Put(Subs.fechaKMT(DateTime.now),"inicia") + Starter.starterStatus.Put(Subs.fechaKMT(DateTime.now),"inicia") + End If +' If starter.Logger Then Log($"starterStatus=${Starter.starterStatus}, nsStatus=${nsStatus}"$) + If rp.HandleIntent(StartingIntent) Then Return + + cmd.Initialize + cmd.Name = "select_soporte" 'Intentamos conectarnos al servido publico y si no responde cambiamos al interno. + reqManager.ExecuteQuery(cmd , 0, "pruebaConexion", 750) 'request con timeout corto en ms. + DBRChecked = False + Do While Not(DBRChecked) ' Esperamos a que termine la prueba de conexion. + Sleep(20) + Loop + End If +End Sub + +Sub CreateNotification (Body As String) As Notification + Dim notification As Notification + notification.Initialize2(notification.IMPORTANCE_LOW) + notification.Icon = "icon" + notification.SetInfo("Esperando notificaciones.", Body, Main) + Return notification +End Sub + +Sub Service_Destroy + nsStatus.Put(Subs.fechaKMT(DateTime.now),"termina") + If Starter.notisMap2.IsInitialized Then + Starter.notisMap2 = notisMap2 + Else + Starter.notisMap2.Initialize + Starter.notisMap2 = notisMap2 + End If + If Starter.logger Then LogColor("NotificationService Destroyed, copied notimap2 to starter=" & Starter.notisMap2.Size , Colors.Red) +End Sub + +Sub Bow2_NotificationPosted (SBN As StatusBarNotification) + If status = "Servicio Activo" Then + If Starter.logger Then LogColor(SBN.PackageName, Colors.Red) + '==============================================================================================================' + '============================================== Inicia Whatsapp =============================================' + '==============================================================================================================' + If SBN.PackageName = "com.whatsapp" Or SBN.PackageName = "com.whatsapp.w4b" Then + #Region Variables de la notificación +' If starter.Logger Then LogColor("ObjetoNoti:"&SBN,Colors.Blue) +' If starter.Logger Then Log(SBN.Id) 'get Id Notification +' If starter.Logger Then Log("PackageName:" & SBN.PackageName) 'get PackageName Application posted Notification +' If starter.Logger Then LogColor("NotiObject:"&SBN.Notification, Colors.Blue) 'get Notification object +' If starter.Logger Then LogColor("NotiExtras:"&SBN.Extras, Colors.Blue) 'get extras Notification +' If starter.Logger Then Log("NotiIntent:"&SBN.ContentIntent) 'get ContentIntent not used +' If starter.Logger Then Log("NotiKey:"&SBN.Key) 'get Key +' If starter.Logger Then Log("Title:" & SBN.Title) +' If starter.Logger Then Log("Mensaje:"&SBN.Message) +' If starter.Logger Then Log("Ticker:" & SBN.TickerText) +' If starter.Logger Then Log("Numero:" & getNumberWA(SBN)) +' If starter.Logger Then Log("Nombre persona:" & getPersonFromGroup(SBN.Title)) + #end region + If SBN.PackageName == "com.whatsapp" Or SBN.PackageName = "com.whatsapp.w4b" Then + If Starter.logger Then Log("Llega WA Notificacion = " & SBN.Title & " - " & SBN.Message) + Dim whatsappkey As String = SBN.Key + If Starter.logger Then Log(SBN.key) + Dim ww() As String = Regex.Split("\|", whatsappkey) + If ww(3) <> "null" Then + Subs.guardaNotificacion(SBN)'Aqui guardamos en un mapa las notificaciones y posteriormente poder mandar notificacion a esos números. +' Starter.colaNotifs.ExecNonQuery($"insert into cola (numero, contestada, timestamp) values ('${getNumberWA(SBN)}', 0, ${DateTime.Now})"$) +' If starter.Logger Then Log(notisMap2) +' If starter.Logger Then Log(notificacionesPorContestar) + #Region Grupo o persona +' If starter.Logger Then LogColor("isGroupWA: "&isGroupWA2(SBN.Title),Colors.Magenta) +' If starter.Logger Then LogColor("isGroupWA2: "&isGroupWA(SBN),Colors.Magenta) +' If starter.Logger Then LogColor("isPersonWA: "&isPersonWA(SBN),Colors.Magenta) +' If starter.Logger Then LogColor("isPersonWA2 :"&isPersonWA2(SBN),Colors.Magenta) +' If starter.Logger Then LogColor("getPersonFromGroup: "& getPersonFromGroup(SBN.Title) ,Colors.Magenta) +' If starter.Logger Then LogColor("groupName: "& getGroupName(SBN.Title) ,Colors.Magenta) +' If starter.Logger Then LogColor("groupName2: "& getGroupName2(SBN) ,Colors.Magenta) +' If starter.Logger Then LogColor("getNumberOrGroupWA: "& getNumberOrGroupWA(SBN) ,Colors.Magenta) +' If starter.Logger Then LogColor("getNumberWA: "& getNumberWA(SBN) ,Colors.Magenta) +' If starter.Logger Then LogColor("getShortcut: "& getShortcut(SBN) ,Colors.Magenta) +' If starter.Logger Then LogColor("mapReglas="&mapReglas, Colors.Magenta) + #End Region + Try 'A veces el sistema finaliza la aplicación, el servicio continua interceptando notificaciones, pero la lista de notificaciones recibidas ya no se actualiza. + CallSubDelayed(B4XPages.MainPage, "llenaLV") 'Poblamos el listview con las notificaciones recibidas. + Catch + LogColor(LastException, Colors.red) + End Try + End If + procesaColaDeNotificaciones + End If + #Region Codigo para Whatsapp Bussiness - Deshabilitado +' If SBN.PackageName == "com.whatsapp.w4b" Then +' Dim whatsappkey As String = SBN.Key +' Dim ww() As String = Regex.Split("\|", whatsappkey) +' If ww(3) <> "null" Then +' 'rp.ClearNotification(SBN) +' rp.reply(SBN.Notification, SBN.PackageName, "Reply HelloWorld WhatsApp-Business") +' Log("Reply Whatsapp Success") +' End If +' End If + #end region + End If + End If +End Sub + +'Modo simple de regex que permite poner un * para significar cualquier cadena y // para significar OR. +Sub regexSimple(cadenaOriginal As String) As String + cadenaOriginal = Regex.Replace("\*", cadenaOriginal, "\.\*") + cadenaOriginal = Regex.Replace("\/\/", cadenaOriginal, "\|") +' If starter.Logger Then Log(cadenaOriginal) + Return cadenaOriginal +End Sub + +'Regresa "verdadero" si el el texto "aBuscar" existe en el texto "sbnMensaje", se pueden +'agregar * para significar cualquier cadena y // para significar OR. +'Ej. coincideRegexSimple("*hola*//*buenas*", "Hola, como estas") = verdadero +' coincideRegexSimple("*hola*//*buenas*", "Buenas tardes") = verdadero +Sub coincideRegexSimple(aBuscar As String, sbnMensaje As String) As Boolean +' If starter.Logger Then Log(sbnMensaje) + Private x As Boolean + Dim sbnMensaje As String = Regex.Replace("[\r?\n|\r]",sbnMensaje," ") 'Sustituimos los "retornos" por un espacio porque si tiene retornos el mensaje la busqueda no va a coinicidir. +' If starter.Logger Then Log($"|${aBuscar}|${sbnMensaje}|"$) + x = Regex.IsMatch2(regexSimple(aBuscar), Regex.CASE_INSENSITIVE, sbnMensaje) + If aBuscar = "%solo_numeros%" Then x = Regex.IsMatch("\d+", sbnMensaje) 'Solo acepta numeros en la respuesta. + If aBuscar = "%solo_correos%" Then x = Regex.IsMatch("([a-zA-Z0-9]+[_a-zA-Z0-9\.-]*[a-zA-Z0-9]+)@([a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*\.[a-zA-Z]{2,12})", sbnMensaje) 'Solo acepta direcciones de correo en la respuesta. + If aBuscar = "%solo_urls%" Then x = Regex.IsMatch("^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \?=.-]*)\/?$", sbnMensaje) 'Solo acepta URLs en la respuesta. + Return x +End Sub + +'Returns TRUE if the sender is a GROUP. +'Searches the provided sbn.title for the string ": " to know if the sender is a group. +Sub isGroupWA2(sbnTitle As String) As Boolean 'ignore + Private x As Boolean = Regex.ismatch(".*(: ).*", sbnTitle) + Return x +End Sub + +'Returns TRUE if the sender is a GROUP. +'Searches the provided notification object for the string "@g.us" and if found returns TRUE. +Sub isGroupWA(sbn As StatusBarNotification) As Boolean + Private a As Boolean = False + If sbn.As(String).IndexOf("@g.us") > -1 Then a = True 'ignore + Return a +End Sub + +'Returns TRUE if the sender is a PERSON. +'Searches the provided notification object for the string "@s.whatsapp.net" and if found returns TRUE. +Sub isPersonWA(sbn As StatusBarNotification) As Boolean 'ignore + Private a As Boolean = False + If sbn.As(String).IndexOf("@s.whatsapp.net") > -1 Then a = True 'ignore + Return a +End Sub + +'Returns TRUE if the sender is a PERSON. +'Searches the provided notification object for the string "channel=individual" and if found returns TRUE. +Sub isPersonWA2(sbn As StatusBarNotification) As Boolean 'ignore + Private a As Boolean = False + If sbn.As(String).IndexOf("channel=individual") > -1 Then a = True 'ignore + Return a +End Sub + +'Returns the sender's number. +'Searches the provided notification object and gets the numbers between "shortcut=" and "@s.whatsapp.net". +Sub getNumberWA(sbn As StatusBarNotification) As String + Private a As Int = sbn.As(String).IndexOf("@s.whatsapp.net") 'ignore + If a > -1 Then + Private x As String = sbn.As(String) 'ignore + Private y As Int = x.IndexOf("shortcut=") + If (y+9) > 0 And a > (y+9) Then x = x.SubString2(y+9, a) Else x = "Not a person" + Else 'It is probably is a group. + x = "Not a person" + End If + Return x +End Sub + +'Returns the name of the group from the given text. +'If it is not a group, then returns the notification's title. +Sub getGroupName(sbnTitle As String) As String 'ignore + Private a As Int = sbnTitle.IndexOf(": ") + Private x As String = sbnTitle + If a > -1 Then + Private b As String = sbnTitle.SubString2(0, a) + x = Regex.Replace(" \(.+\)", b, "") + End If + Return x +End Sub + +'Returns the name of the group from the given notification object. +'Searches the provided notification for the string "hiddenConversationTitle" and if found, gets the name. +'If it is not a group,then it returns the notification's title. +Sub getGroupName2(sbn As StatusBarNotification) As String + Private inicio As Int = sbn.Extras.As(String).IndexOf("hiddenConversationTitle=") 'ignore + If inicio > -1 And sbn.Extras.As(String).IndexOf("hiddenConversationTitle=null") = -1 Then 'ignore + Private x As String = sbn.Extras.As(String) 'ignore + Private fin As Int = x.IndexOf(", android.reduced.images=") + x = x.SubString2(inicio+24, fin) + x = Regex.Replace(" \(.+\)", x, "") 'Replace anything between () with "", this en the case that we have something like "MyGroupName (5 messages)" + Else 'Is not from a group. + Private x As String = sbn.Title + End If + Return x +End Sub + +'Returns the person's name (or the number) when the message comes from a group. +'Searches the provided sbn.title for the string ": " in the title and returns the string after that, +'if it does not find ": " then returns the complete string. +Sub getPersonFromGroup(sbnTitle As String) As String 'ignore + Private a As Int = sbnTitle.IndexOf(": ") + If a = -1 Then a = -2 'Is not from a group. + Private b As String = sbnTitle.SubString(a+2) + Return b +End Sub + +'Returns the NUMBER of the sender and if NOT a person, then returns the name of the group. +Sub getNumberOrGroupWA(sbn As StatusBarNotification) As String + Private numRemitente As String = getNumberWA(sbn) + If numRemitente = "Not a person" Then numRemitente = getGroupName(sbn.Title) + Return numRemitente +End Sub + +'Desbloquea el usuario de Guna especificado usando JRDC. +Sub desbloqueaUsuario(sbn As StatusBarNotification) 'ignore + Private elNumero As String = getNumberWA(sbn) + If elNumero = "Not a person" Then elNumero = getGroupName(sbn.Title) + agregaNotiParaJobDone(sbn) + cmd.Initialize + cmd.Name = "update_usuario_guna_nobajas" + Dim tempUsr As String = sbn.Message +' Dim tempUsr As String = "cdaza" + If Starter.logger Then LogColor("Usuario a desbloquear="&tempUsr, Colors.Green) + cmd.Parameters = Array As Object(tempUsr.ToUpperCase.Trim) 'Quitamos espacios de antes y despues y lo mandamos en mayúsculas. + reqManager.ExecuteCommand(cmd , $"desbloqueaUsuario_${elNumero}"$) + If Starter.logger Then Log("Mandamos DBRequest desbloqueo: " & tempUsr) +End Sub + +'Trae los datos del cliente especificado de Guna usando JRDC. +Sub revisaCliente(sbn As StatusBarNotification) 'ignore + Private elNumero As String = getNumberWA(sbn) +' If elNumero = "Not a person" Then elNumero = getGroupName(sbn.Title) + agregaNotiParaJobDone(sbn) + If Starter.logger Then Log("Buscamos cliente "&sbn.Message) + cmd.Initialize + cmd.Name = "select_cliente_GUNA" + Dim tempUsr As String = sbn.Message + If Starter.logger Then LogColor("Cliente="&tempUsr, Colors.Green) + cmd.Parameters = Array As Object(tempUsr.ToUpperCase.Trim) 'Quitamos espacios de antes y despues y lo mandamos en mayúsculas. + reqManager.ExecuteQuery(cmd, 0 , $"traeCliente_${elNumero}"$, 0) + If Starter.logger Then Log("Mandamos DBRequest traeCliente: " & tempUsr) +End Sub + +'Revisa si el cliente especificado existe en Guna. +Sub revisacliente2(sbn As StatusBarNotification) + Private elNumero As String = getNumberWA(sbn) + agregaNotiParaJobDone(sbn) + If Starter.Logger Then Log("Buscamos cliente "&sbn.Message) + cmd.Initialize + cmd.Name = "select_revisacliente_GUNA" + Dim tempUsr As String = sbn.Message + If Starter.logger Then LogColor("Cliente="&tempUsr, Colors.Green) + cmd.Parameters = Array As Object(tempUsr.ToUpperCase.Trim) 'Quitamos espacios de antes y despues y lo mandamos en mayúsculas. + reqManager.ExecuteQuery(cmd, 0 , $"revisaCliente_${elNumero}"$, 0) + If Starter.logger Then Log("Mandamos DBRequest revisaCliente: " & tempUsr) +End Sub + +'Guarda los datos de la promoción de la gallina en Guna. +Sub guardaInfoGallina(sbn As StatusBarNotification) + If Starter.logger Then LogColor("================= INFO GALLINA ============", Colors.Red) + Private elNumero As String = getNumberWA(sbn) + agregaNotiParaJobDone(sbn) + Dim preventa As String = sbn.Message +' If starter.Logger Then Log(procesaRemplazos($"%msj_ant_03G.1_0%|%msj_ant_03G.1.1_0%"$, traeNotificacion(elNumero))) + Private paramss() As String=Regex.Split("\|", procesaRemplazos($"%msj_ant_03G.1_0%|%msj_ant_03G.1.1_0%"$, traeNotificacion(elNumero))) + If Starter.logger Then LogColor($"${elNumero}, ${paramss(0)}, ${paramss(0)}, ${preventa}"$, Colors.green) + cmd.Initialize + cmd.Name = "insert_registroGallina_GUNA" + cmd.Parameters = Array As Object(elNumero, paramss(0), paramss(0), preventa) + reqManager.ExecuteCommand(cmd, $"guardaInfoGallina_${elNumero}"$) + If Starter.logger Then Log("Mandamos DBRequest guardaInfoGallina_: " & elNumero) +End Sub + +'Agregamos la notificacion a un mapa para una vez que tengamos el jobDone poder mandar un mensaje especificado. +Sub agregaNotiParaJobDone(sbn As StatusBarNotification) + Dim n As notificacionesGuardadasType + n.Initialize + n.numero = getNumberWA(sbn) + n.notif = sbn + Dim titulo As String = getNumberWA(sbn) + If isGroupWA(sbn) Then titulo = getGroupName2(sbn) + Private tmpMap As Map + tmpMap.Initialize + tmpMap.Put(titulo, n) + tmpMap.Put("msg", sbn.Message) + notificacionesGuardadas.Put(titulo, tmpMap) +' If starter.Logger Then Log($"Mapa notificacionesGuardadas=${notificacionesGuardadas}"$) +End Sub + +Sub JobDone(Job As HttpJob) 'ignore + If Starter.Logger Then LogColor("jobDone: " & Job.Tag, Colors.Magenta) + If Job.Success = False Then + If Starter.Logger Then LogColor("***** jobDone Error *****", Colors.Red) + If Starter.Logger Then LogColor(Job.ErrorMessage, Colors.Red) + If Job.Tag = "pruebaConexion" Then 'And Job.ErrorMessage.IndexOf("Failed to connect to ") = -1 + B4XPages.MainPage.Timer1.Interval = (20 * 1000) + Private cd1 As ColorDrawable + cd1.Initialize(Colors.red, 10dip) + B4XPages.MainPage.b_config.Background = cd1 + B4XPages.MainPage.b_config.text = "Desconectado" + If Starter.DBRServer == "http://10.0.0.205:1782" Then + Starter.DBRServer = "http://keymon.lat:1782" + Else + Starter.DBRServer = "http://10.0.0.205:1782" + End If +' DBRServer = "http://11.0.0.231:1783" 'Para pruebas locales + reqManager.Initialize(Me, Starter.DBRServer) + pruebaPaso = pruebaPaso + 1 +' Toast("Cambiando a servidor interno. 🕵🏼", 0) +' ToastMessageShow("Cambiando a servidor interno. 🕵🏼", False) + If Starter.logger Then Log($"PruebaPaso = ${pruebaPaso}"$) + If Starter.Logger Then LogColor("Reintentando conexion: " & Starter.DBRServer, Colors.RGB(255,123,0)) + ToastMessageShow("Reintentando conexion: " & Starter.DBRServer, False) + If pruebaPaso < 2 Then + If Starter.Logger Then Log("Reintentamos conexión con servidor nuevo.") + cmd.Initialize + cmd.Name = "select_soporte" 'Reintentamos conexión. + reqManager.ExecuteQuery(cmd , 0, "pruebaConexion", 0) + End If + If Starter.Logger Then LogColor("Servidor actual: " & Starter.DBRServer, Colors.Magenta) + End If + Else + If Starter.Logger Then LogColor("JobDone: '" & reqManager.HandleJob(Job).tag & "' - Registros: " & reqManager.HandleJob(Job).Rows.Size, Colors.Green) 'Mod por CHV - 211027 + If Job.JobName = "DBRequest" Then 'Para desbloquear un usuario Guna. + Dim result As DBResult = reqManager.HandleJob(Job) + If Starter.logger Then Log("******************************************************") + If Starter.logger Then Log($"************ ${result.Tag} ***********"$) + If Starter.logger Then Log("******************************************************") + If result.Tag = "pruebaConexion" Then + If Starter.logger Then Log($"${Starter.ultimoServidorConectado}+${Starter.DBRServer} "$) + If Starter.logger Then LogColor("Servidor actual: " & Starter.DBRServer, Colors.Magenta) + If Starter.ultimoServidorConectado <> Starter.DBRServer Then + ToastMessageShow($"Conexión establecida${CRLF}${Starter.DBRServer}"$, False) + Else + ToastMessageShow($"OK"$, False) + End If + Starter.ultimoServidorConectado = Starter.DBRServer + Private cd1 As ColorDrawable + cd1.Initialize(Colors.RGB(109, 221, 101), 10dip) + B4XPages.MainPage.b_config.Background = cd1 + B4XPages.MainPage.b_config.text = "Conectado" + B4XPages.MainPage.Timer1.Interval = (120 * 1000) +' For Each records() As Object In result.Rows +' If starter.Logger Then Log("========================= ") +' For Each k As String In result.Columns.Keys +' If starter.Logger Then LogColor(result.Tag & ": " & k & "=" & records(result.Columns.Get(k)), Colors.blue) +' Next +' Next + End If + If result.Tag.As(String).IndexOf("desbloqueaUsuario_") > -1 Then 'query tag + For Each records() As Object In result.Rows + Private num As String = result.Tag + num = num.SubString(num.IndexOf("_")+1) + Private usr As String = notificacionesGuardadas.Get(num).As(Map).Get("msg") + If Starter.Logger Then Log("========================= "&usr) + If records(result.Columns.Get("AffectedRows")) > 0 Then + If Starter.Logger Then Log("Usuario desbloqueado! 🔓") + mandaRespuesta(num, $"Usuario *${usr.ToUpperCase}* desbloqueado, por favor cerrar navegadores y reingresar."$) + Else + If Starter.Logger Then Log("Usuario no encontrado!!") + mandaRespuesta(num, $"El usuario *${usr.ToUpperCase} no existe* o esta dado de *baja*, por favor revisarlo y volver a intentar."$) + End If +' If starter.Logger Then Log( result.Tag & " | " & num) +' If starter.Logger Then Log(Starter.desbloqueoUsrs) +' For Each k As String In result.Columns.Keys +' If starter.Logger Then Log(result.Tag & ": " & k & ": " & records(result.Columns.Get(k))) +' Next + Next + End If + If result.Tag.As(String).IndexOf("traeCliente_") > -1 Then 'query tag + Private num As String = result.Tag + num = num.SubString(num.IndexOf("_")+1) + If Starter.Logger Then Log(num) + For Each records() As Object In result.Rows + If Starter.Logger Then Log("========================= "&usr) + If Starter.Logger Then Log("Cliente encontrado!") + For Each k As String In result.Columns.Keys + If Starter.logger Then LogColor(result.Tag & ": " & k & ": " & records(result.Columns.Get(k)), Colors.blue) + Next + Private cod As String = records(result.Columns.Get("CAT_CL_CODIGO")) + Private nombre As String = records(result.Columns.Get("CAT_CL_NOMBRE")) + Private calle As String = records(result.Columns.Get("CAT_CL_CALLE")) + Private noInt As String = records(result.Columns.Get("CAT_CL_NOINT")) + Private noExt As String = records(result.Columns.Get("CAT_CL_NOEXT")) + Private msj As String = $"*Cliente:* ${cod}${CRLF}*Tienda:* ${nombre}${CRLF}*Calle:* ${calle}${CRLF}*No. Int:* ${noInt}${CRLF}*No. Ext:* ${noExt}"$ + mandaRespuesta(num, msj) + mandaRespuesta(num, "Por favor dame el nombre del encargado de la tienda.") + Next + If starter.Logger Then Log(result.Rows.Size) + If result.Rows.Size = 0 Then + If Starter.Logger Then Log("Cliente no encontrado!!") + mandaRespuesta(num, $"*No se encontró el cliente en nuestros registros*, por favor validar la información y volver a intentar."$) + End If + End If + If result.Tag.As(String).IndexOf("revisaCliente_") > -1 Then 'query tag + Private num As String = result.Tag + num = num.SubString(num.IndexOf("_")+1) + If Starter.Logger Then Log(num) + For Each records() As Object In result.Rows + If Starter.Logger Then Log("========================= "&usr) + For Each k As String In result.Columns.Keys + If Starter.logger Then LogColor(result.Tag & ": " & k & "=" & records(result.Columns.Get(k)), Colors.blue) + Next + Next + If records(result.Columns.Get("CUANTOS")) = "0" Then + If Starter.Logger Then Log("No existe el usuario") + mandaRespuesta(num, $"*No existe* ese número de cliente, por favor ingresa el número correcto."$) + Subs.vamosA(traeNotificacion(num), "03G") + Else + mandaRespuesta(num, "Gracias, ahora por favor el número del preventa.") +' Subs.vamosA(traeNotificacion(num), "03G.1") + End If + If Starter.Logger Then Log(result.Rows.Size) + End If + If result.Tag.As(String).IndexOf("guardaInfoGallina_") > -1 Then 'query tag + Private num As String = result.Tag + num = num.SubString(num.IndexOf("_")+1) + If Starter.Logger Then Log(num) + For Each records() As Object In result.Rows + If Starter.Logger Then Log("========================= "&usr) + For Each k As String In result.Columns.Keys + If Starter.logger Then LogColor(result.Tag & ": " & k & "=" & records(result.Columns.Get(k)), Colors.blue) + Next + Next +' If starter.Logger Then Log("|"&records(result.Columns.Get("AffectedRows"))&"|") + If records(result.Columns.Get("AffectedRows")) = 1 Then + Private msj As String = procesaRemplazos($"Muchas gracias.${CRLF}Quedas registrado con:${CRLF}*Cliente:* %msj_ant_03G.1_0%${CRLF}*Preventa:* %msj%"$, traeNotificacion(num)) + mandaRespuesta(num, msj) + Else + mandaRespuesta(num, "*¡Hubo un error, por favor intenta de nuevo!*") + End If + If Starter.Logger Then Log(result.Rows.Size) + End If + If result.Tag.As(String).IndexOf("procRecuperaClientes_") > -1 Then 'query tag + Private num As String = result.Tag + num = num.SubString(num.IndexOf("_")+1) + If Starter.Logger Then Log(num) + For Each records() As Object In result.Rows + If Starter.Logger Then Log("========================= "&usr) + For Each k As String In result.Columns.Keys + If Starter.logger Then LogColor(result.Tag & ": " & k & "=" & records(result.Columns.Get(k)), Colors.blue) + Next + Next + + If records(result.Columns.Get("AffectedRows")) = 1 Then + mandaRespuesta(num, procesaRemplazos("Listos, clientes de %msj% recuperados", traeNotificacion(num))) + End If +' If starter.Logger Then Log("|"&records(result.Columns.Get("AffectedRows"))&"|") +' If records(result.Columns.Get("AffectedRows")) = 1 Then +' Private msj As String = procesaRemplazos($"Muchas gracias.${CRLF}Quedas registrado con:${CRLF}*Cliente:* %msj_ant_03G.1_0%${CRLF}*Preventa:* %msj%"$, traeNotificacion(num)) +' mandaRespuesta(num, msj) +' Else +' mandaRespuesta(num, "*¡Hubo un error, por favor intenta de nuevo!*") +' End If + If Starter.Logger Then Log(result.Rows.Size) + End If + End If + Job.Release + End If +End Sub + +'Muestra un toast con texto y ancho dados, si el ancho es 0, entonces se queda el default. +Sub Toast(texto As String, ancho As Int) 'ignore +' p_toast.BringToFront +' If ancho <> 0 Then p_toast.Width = ancho +' p_toast.left = (Activity.Width/2)-(p_toast.Width/2) 'Centramos el panel en la actividad. +' l_toast.Width = p_toast.Width +' p_toast.top = (Activity.Height * 0.8) 'Ponemos el toast a 3/4 de la pantalla. +' l_toast.Text = texto +' p_toast.SetVisibleAnimated(1000, True) +' Sleep(2000) +' p_toast.SetVisibleAnimated(1000, False) +End Sub + +'Manda un notificacion al numero indicado con el mensaje especificado. +'Nota: El número especificado debe de existir en el mapa de notificaciones guardadas (notificacionesGuardadas). +Sub mandaRespuesta(numero As String, mensaje As String) + If Starter.logger Then Log("Busco: "& numero & " hay: " & notificacionesGuardadas) + If Starter.logger Then Log(notificacionesGuardadas) + Private tm As Map = notificacionesGuardadas.Get(numero) + If tm.IsInitialized Then + Dim t1 As notificacionesGuardadasType = tm.Get(numero) + Dim t2 As StatusBarNotification = t1.notif + If Starter.logger Then LogColor("Mandamos respuesta", Colors.red) + If t2.IsInitialized Then + rp.reply(t2.Notification, t2.PackageName, mensaje) + guardaMsjSalida(t2, mensaje) + End If + Else +' ToastMessageShow("No hay notificaciones de xxxxxxxx", False) + If Starter.logger Then Log("No hay notificación para ese número.") + End If +End Sub + +'Ejecuta la subrutina especificada. +Sub correSub(comando As String, sbn As StatusBarNotification) + Private c As String = comando + c = c.SubString(c.IndexOf(" ")+1) + If Starter.logger Then Log(c) + If SubExists(Me, c) Then CallSubDelayed2(Me, c, sbn) +End Sub + +Sub muestraHistorico(sbn As StatusBarNotification) 'ignore + If Starter.logger Then Log("Corriendo muestraHistorico") + Private tmpMap As Map + Private tmpList As List + Private n As String = getNumberWA(sbn) + If n = "Not a person" Then n = getGroupName(sbn.Title) + Private s As String = "" + If Starter.logger Then Log(n) + tmpMap = histReglas.Get(n) + If Starter.logger Then Log(tmpMap) + If tmpMap.ContainsKey("historico") Then tmpList = tmpMap.Get("historico") + For i = tmpList.Size -1 To 0 Step -1 +' If starter.Logger Then Log(i & ".- " & tmpList.Get(i).As(Map).Get("mensaje")) + s = s & CRLF + s = s & tmpList.Get(i).As(Map).Get("mensaje") + Next +' If starter.Logger Then Log(s) + mandaRespuesta(n, s) +End Sub + +'Regresa verdadero si la regla es dependiente (subRegla) de otra regla. +'Recibe un mapa con las reglas. +Sub esDependiente(m As Map)As Boolean + Private d As Boolean = False + If m.Get("nombre").As(String).IndexOf(".") > -1 Then d = True + Return d +End Sub + +'Regresa el nombre de la regla superior. +'Recibe un mapa con las reglas. +Sub traeSuperior(m As Map) As String + Dim i As Int + Dim s As String = "" + If m.Get("nombre").As(String).LastIndexOf(".") > -1 Then + i = m.Get("nombre").As(String).LastIndexOf(".") +' If starter.Logger Then Log(i) + s = m.Get("nombre").As(String).SubString2(0, i) +' If starter.Logger Then Log(s) + End If + Return s +End Sub + +'Regresa el id de la ultima regla cumplida. +Sub ultimaRegla As String + Dim ultReg As String = "" + If histReglas.get(numRemitente).As(Map).IsInitialized Then ultReg = histReglas.get(numRemitente).As(Map).Get("histReglas").As(List).Get(0) + Return ultReg +End Sub + +'Regresa el mensaje especificado dentro de las reglas anteriores cumplidas. +'regla: El nombre de la regla de la que queremos el mensaje. +'reglasAtras: Que mensaje queremos traer, 0 para el último, 1 para el penúltimo, 2 para el antepenúltimo, etc. +Sub mensajeAnterior(regla As String, reglasAtras As Int) As String + Dim msjAnterior As String = "" + If reglasAtras = 0 Then reglasAtras = 1 + If histReglas.get(numRemitente).As(Map).IsInitialized And _ + histReglas.get(numRemitente).As(Map).Get("historico").As(List).Size >= reglasAtras Then + Private hist As List = histReglas.get(numRemitente).As(Map).Get("historico") +' If starter.Logger Then Log(hist) + If regla <> "0" Then 'Si se especifica una regla, entonces filtramos y solo usamos el historico de esa regla. + Private h As List + h.Initialize + For Each h2 As Map In hist + If h2.Get("regla") = regla Then + h.Add(h2) +' If starter.Logger Then Log(regla & "|" & h2) + End If + Next + hist = h +' If starter.Logger Then Log(h) + End If +' If starter.Logger Then Log($"size:${hist.Size}, reglaAtras:${reglasAtras}"$) + If hist.Size >= reglasAtras Then msjAnterior = hist.Get(reglasAtras-1).As(Map).Get("mensaje") + End If + Return msjAnterior +End Sub + +'Regresa el "shortcut" del remitente. +'Si es de un grupo, es algo como "120363023512345678@g.us" +'Si es de una persona, entonces "5215512345678@s.whatsapp.net" +Sub getShortcut(sbn As StatusBarNotification) As String 'ignore + Private ap As Int = sbn.As(String).IndexOf("@s.whatsapp.net") 'ignore + Private ag As Int = sbn.As(String).IndexOf("@g.us") 'ignore + Private x As String = sbn.As(String) 'ignore + Private y As Int = x.IndexOf("shortcut=") + If ap > -1 Then + Private x As String = sbn.As(String) 'ignore + Private y As Int = x.IndexOf("shortcut=") + x = x.SubString2(y+9, ap+15) + Else if ag > -1 Then 'It is probably is a group. + Private x As String = sbn.As(String) 'ignore + Private y As Int = x.IndexOf("shortcut=") + x = x.SubString2(y+9, ag+5) + End If + Return x +End Sub + +'Reemplaza texto en la respuesta con variables predefinidas. +Sub procesaRemplazos(msjStr As String, sbn As StatusBarNotification) As String + If Starter.logger Then Log("Procesamos reemplazos '"& msjStr & "'") + Dim Matcher1 As Matcher + Matcher1 = Regex.Matcher("%[a-z A-Z_0-9,\.\uD83C-\uDBFF\uDC00-\uDFFF\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff]]+%", msjStr) + Do While Matcher1.Find + If Starter.logger Then Log("Found: " &Matcher1.Match) + If Matcher1.Match.IndexOf("msj_ant_") > -1 Then 'Reemplaza el texto "%msj_ant_0_1%" por mensajes anteriores segun el desplazamiento y la regla especificados. + Private offs As String = Matcher1.Match.IndexOf("_") + Dim offs2() As String = Regex.Split("_", Matcher1.Match) + If Starter.logger Then Log(offs2.Length) + If offs2.Length = 4 Then 'Solo procesamos el reemplazo si tiene 4 parametros. + Private offs As String = offs2(offs2.Length-1) 'El desplazamiento para el mensaje (cuantos mensaje hacia atras vamos a traer) + Private rulz As String = offs2(offs2.Length-2) 'La regla a usar para traer el mensaje. + offs = offs.SubString2(0, offs.Length-1) + If Starter.logger Then Log("################### "& rulz & "|" & offs) + msjStr = msjStr.Replace(Matcher1.Match, mensajeAnterior(rulz, offs)) +' If starter.Logger Then Log(Matcher1.Match) +' If starter.Logger Then Log("==== msjAnt - " & msjStr) + End If + else If Matcher1.Match.IndexOf("%msj%") > -1 Then 'Reemplaza el texto "%msj%" con el mensaje recibido. + msjStr = msjStr.Replace(Matcher1.Match, sbn.Message) + else if Matcher1.Match.IndexOf("%nombre%") > -1 Then 'Reemplaza el texto "%nombre%" por el nombre completo (o numero si no esta en los contactos) del remitente. + Private pn As String = sbn.Title + If isGroupWA(sbn) Then pn = getPersonFromGroup(sbn.Title) + msjStr = msjStr.Replace(Matcher1.Match, pn) + else if Matcher1.Match.IndexOf("%primer_nombre%") > -1 Then 'Reemplaza el texto "%primerNombre%" por el nombre (hasta el primer espacio) o numero (si no esta en los contactos) del remitente. + Private pn As String = sbn.Title + If isGroupWA(sbn) Then pn = getPersonFromGroup(sbn.Title) + If Starter.logger Then Log(pn) + If Not(pn.StartsWith("+")) Then pn = Regex.Split(" ", pn)(0) + msjStr = msjStr.Replace(Matcher1.Match, pn) + else If Matcher1.Match.IndexOf("goto_") > -1 Then 'Manda el procesamiento de la siguiente regla a la regla especificada. + Private offs As String = Matcher1.Match.IndexOf("_") + offs = Matcher1.Match.SubString2(offs+1, Matcher1.Match.Length-1) + Subs.vamosA(sbn, offs) + msjStr = msjStr.Replace(Matcher1.Match, "") +' If starter.Logger Then Log(Matcher1.Match) +' If starter.Logger Then Log("==== goto: " & offs) + else If Matcher1.Match.IndexOf("rnd_") > -1 Then 'Remplaza %rnd_1,b,A,5% por una opcion al azar de las especificadas. + Private offs As String = Matcher1.Match.IndexOf("_") + offs = Matcher1.Match.SubString2(offs+1, Matcher1.Match.Length-1) + Private x() As String = Regex.Split(",", offs) + Private rando As Int = 0 ' Por si solo hay un elemento en la lista. + If x.Length > 1 Then rando = Rnd(0, x.Length) + If Starter.logger Then LogColor($"Random: 0-${x.Length-1} ${x(rando)} "$, Colors.Magenta) + msjStr = msjStr.Replace(Matcher1.Match, x(rando)) + else If Matcher1.Match.IndexOf("espera2_") > -1 Then 'Genera el tiempo de espera especificado en ms antes de mandar la respuesta. + Private offs As String = Matcher1.Match.IndexOf("_") + offs = Matcher1.Match.SubString2(offs+1, Matcher1.Match.Length-1) + espera = offs + msjStr = msjStr.Replace(Matcher1.Match, "") + else If Matcher1.Match.IndexOf("espera_") > -1 Then 'Genera el tiempo de espera al azar entre el minimo y maximo especificados en segundos antes de mandar la respuesta. +' Private offs As String = Matcher1.Match.IndexOf("_") + Dim params() As String = Regex.Split("_", Matcher1.Match) + If params.Length = 3 Then 'Solo procesamos el reemplazo si tiene 3 parametros. + Private minS As String = params(params.Length-2) 'Los segundos minimos. + Private maxS As String = params(params.Length-1) 'Los segundos maximos. + maxS = maxS.SubString2(0, maxS.Length-1) 'Quitamos el "%" del final. + Private espera2 As Int = Rnd(minS, maxS+1)*1000 + If Starter.logger Then LogColor($"min=${minS}, max=${maxS}, espera=${espera2}"$, Colors.red) + espera = espera2 + msjStr = msjStr.Replace(Matcher1.Match, "") + End If + End If + Loop + If Starter.logger Then LogColor("Remplazos completados - " & msjStr, Colors.Green) + Return msjStr +End Sub + +'Toma una lista de posibles respuestas (separadas por //) y regresa solo una al azar. +Sub procesaMultiMensajeRandom(mensaje As String) As String + Dim x() As String = Regex.Split("//", mensaje) +' For i = 0 To x.Length - 1 +' If starter.Logger Then Log($"len:${x.Length}, ${i}: ${x(i)}"$) +' Next + Private rando As Int = 0 ' Por si solo hay un elemento en la lista. + If x.Length > 1 Then rando = Rnd(0, x.Length) +' If starter.Logger Then LogColor($"Random: 0-${x.Length-1} ${x(rando).Trim} "$, Colors.Magenta) + Return x(rando) +End Sub + +'Procesa la cola de notificaciones (lista notificacionesPorContestar). +Sub procesaColaDeNotificaciones +' If starter.Logger Then LogColor("COLA = " & notificacionesPorContestar.Size, Colors.Green) +' If starter.Logger Then Log(notificacionesPorContestar) +' If starter.Logger Then Log($"${procesandoNotificaciones}, ${notificacionesPorContestar.size}"$) + Private hayError As Boolean = False + If Not(procesandoNotificaciones) And notificacionesPorContestar.Size > 0 Then + If Starter.logger Then Log("iniciamos procesando") + procesandoNotificaciones = True +' Private la As Int = 0 +' For i = 0 To notificacionesPorContestar.Size - 1 + If notificacionesPorContestar.Get(0) <> "DONE" Then + Try + Private tempMap As Map = notificacionesPorContestar.Get(0) + Private num As String = notificacionesPorContestar.Get(0).As(Map).GetKeyAt(0) + Dim t1 As lasNotis = tempMap.Get(num) +' If starter.Logger Then LogColor($"${num} - ${t1.notif.Message}"$, Colors.Blue) +' If starter.Logger Then Log(t1) + Dim t2 As StatusBarNotification = t1.notif +' If starter.Logger Then Log(t2) + Catch + Log(LastException) + hayError = True + End Try + If Not(hayError) Then + procesaNotificacion(t2) + If Starter.logger Then Log($"${notificacionesPorContestar.Get(0)}, ${notificacionesPorContestar.size}"$) + If Starter.logger Then Log("Ponemos 0 en DONE") + notificacionesPorContestar.Set(0, "DONE") + End If + End If +' la = i +' Next +' If starter.Logger Then Log(notificacionesPorContestar.Size) + End If + If notificacionesPorContestar.Size > 0 Then + For i=0 To notificacionesPorContestar.Size-1 'Borramos las notificaciones procesadas de la lista. + If notificacionesPorContestar.get(i) = "DONE" Then + notificacionesPorContestar.RemoveAt(i) + If Starter.logger Then Log("Removemos posicion " & i) + End If + Next + End If +' If starter.Logger Then Log(notificacionesPorContestar) +' If starter.Logger Then LogColor("COLA = " & notificacionesPorContestar.Size, Colors.red) + procesandoNotificaciones = False + Sleep(1) + If notificacionesPorContestar.Size > 0 Then procesaColaDeNotificaciones +End Sub + +'Procesa la notificación y reglas correspondientes. +'Recibe un objecto SBN (statusBarNotification). +Sub procesaNotificacion(sbn As StatusBarNotification) +' Try + Private numRemitente As String = getNumberOrGroupWA(sbn) + For Each m As Map In mapReglas.Values 'Revisamos si el mensaje dispara alguna regla. +' If starter.Logger Then Log(m) + Private destinatarioOk As Boolean = False + If m.Get("destinatario") = "Ambos" Then destinatarioOk = True + If m.Get("destinatario") = "Grupos" And isGroupWA(sbn) Then destinatarioOk = True + If m.Get("destinatario") = "Personas" And isPersonWA(sbn) Then destinatarioOk = True +' If starter.Logger Then Log(m.Get("destinatario") & "|" &"destinatarioOk="&destinatarioOk) +' If starter.Logger Then Log($"Regla: ${m.Get("nombre")}, activa:${m.Get("activa")}, recibe=${m.Get("recibe")}, contesta=${m.Get("contesta")}, mensaje: ${sbn.Message}"$) +' If starter.Logger Then LogColor(m.Get("contactoEspecifico"), Colors.Magenta) +' If starter.Logger Then LogColor($"================ Procesando regla ${m.Get("nombre")} ==========================="$, Colors.Magenta) + Private cumpleContactosEspecificos As Boolean = revisaContactosEspecificos(getGroupName(sbn.Title), m.Get("contactoEspecifico")) +' If starter.Logger Then Log(cumpleContactosEspecificos) +' If starter.Logger Then Log("COINCIDE="&coincideRegexSimple(m.Get("recibe"), sbn.Message)) + If m.Get("activa") = 1 And destinatarioOk And cumpleContactosEspecificos And coincideRegexSimple(m.Get("recibe"), sbn.Message) Then 'ignore +' If starter.Logger Then Log($"${m.Get("recibe")}, ${sbn.Message}"$) +' If starter.Logger Then LogColor("histReglas="&histReglas, Colors.Blue) + Dim esDep As Boolean = esDependiente(m) + Dim superior As String = traeSuperior(m) + Dim anterior As String = ultimaRegla +' If starter.Logger Then Log("Msg="&sbn.Message&" - Es dependiente="& esDep) +' If starter.Logger Then Log("dep="&esDep&" - regla superior="& superior & " Ultima R=" & anterior) + Private msjStr As String + If Not(esDep) Or (superior = anterior) Then 'Si no es dependiente, O si es dependiente Y la anterior es de la que dependemos, entonces + guardaMsjEntrada(sbn, m.Get("nombre")) +' If starter.Logger Then LogColor($"Regla:${m.Get("nombre")}"$, Colors.Blue) + Subs.guardaUltimaRegla(sbn, m.Get("nombre")) +' If starter.Logger Then Log(msjStr) + msjStr = procesaMultiMensajeRandom(m.Get("contesta")) +' If starter.Logger Then Log("===================== Mensaje ================="&CRLF& msjStr) + If msjStr.IndexOf("&&") > -1 Then 'Si hay respuestas multiples. + Private y() As String = Regex.Split("&&", msjStr) + For j = 0 To y.Length - 1 + espera = 10 + msjStr = procesaRemplazos(y(j).Trim, sbn) +' If starter.Logger Then LogColor("ESPERA="&espera, Colors.red) +' If starter.Logger Then LogColor("Reply: " & msjStr, Colors.Blue) + Sleep(espera) + If y(j).IndexOf("/cmd") > -1 Then 'Si hay que correr un comando ... + correSub(msjStr, sbn) + Sleep(1500) + Else if msjStr <> "" Then + If Starter.logger Then LogColor($"Mandamos respuesta (${msjStr})"$, Colors.Blue) + rp.reply(sbn.Notification, sbn.PackageName, msjStr) + guardaMsjSalida(sbn, msjStr) + End If + Next + Else 'Si SOLO es UNA respuesta ... + espera = 10 + msjStr = procesaRemplazos(msjStr.Trim, sbn) +' If starter.Logger Then LogColor("ESPERA="&espera, Colors.red) + If msjStr.IndexOf("/cmd") > -1 Then 'Si hay que correr un comando ... + correSub(msjStr, sbn) + Sleep(1500) + Else if msjStr <> "" Then + Sleep(espera) + If Starter.logger Then LogColor($"Mandamos respuesta (${msjStr})"$, Colors.Blue) + rp.reply(sbn.Notification, sbn.PackageName, msjStr) + guardaMsjSalida(sbn, msjStr) + End If + End If + Private thisP As String = getGroupName(sbn.Title) + If Not(notisIds.ContainsKey(thisP)) Then notisIds.Put(thisP, notisIds.Size+1) + If Starter.logger Then Log(notisIds.Get(thisP)) + If Starter.logger Then Log(notisIds) + + +' BigText_Notification(sbn, msjStr) 'Retiro temporal + + + + Exit 'Si ya encontramos una regla que se cumple, entonces salimos. + Else if superior = anterior Then 'Si es regla dependiente y la anterior es de la que dependemos, entonces ... +' If starter.Logger Then LogColor($"Regla anterior=${anterior}${CRLF}Sup:${superior} = anterior:${anterior}${CRLF}Regla anterior es igual a superior - ${msjStr}"$, Colors.green) +' Subs.guardaUltimaRegla(sbn, m.Get("nombre")) +' If starter.Logger Then Log("****************************************************"&CRLF& msjStr) +' msjStr = procesaRemplazos(m.Get("contesta"), sbn) +' If msjStr.IndexOf("&&") > -1 Then 'Si hay respuestas multiples ... +' Private y() As String = Regex.Split("&&", msjStr) +' For j = 0 To y.Length - 1 +' If starter.Logger Then LogColor("Reply: " & y(j), Colors.Blue) +' If y(j).IndexOf("/cmd") > -1 Then 'Si hay que correr un comando ... +' correSub(y(j), sbn) +' Else +' 'LogColor("Mandamos respuesta", Colors.red) +' rp.reply(sbn.Notification, sbn.PackageName, y(j)) +' End If +' Sleep(1200) +' Next +' Else 'Si SOLO es una respuesta ... +' If msjStr.IndexOf("/cmd") > -1 Then 'Si hay que correr un comando ... +' correSub(msjStr, sbn) +' Else +' 'If starter.Logger Then LogColor("Mandamos respuesta", Colors.red) +' rp.reply(sbn.Notification, sbn.PackageName, msjStr) +' End If +' End If +' Exit 'Si ya encontramos una regla que se cumple, entonces salimos. + End If + End If + Next +' Catch +' LogColor(LastException, Colors.red) +' End Try +End Sub + +'Regresa true o False dependiendo de: +'Si NO hay contactos especificados regresa TRUE. +'Si hay contactos especificados y el remitente esta dentro de ellos regresa TRUE +'Si hay contactos especificados y el remitente NO esta dentro de ellos regresa FALSE +Sub revisaContactosEspecificos(contacto As String, contactos As String) As Boolean 'ignore + Private result As Boolean = True + If contactos <> Null And contactos <> "" And contactos.Length > 3 Then 'Si hay contactos especificados ... +' If starter.Logger Then LogColor("Hay contactos especificados.", Colors.blue) +' If starter.Logger Then Log($"Buscamos ${contacto} en |${contactos}|"$) + result = False +' Private contEsp() As String = Regex.Split(",", contactos) +' Private l As List +' l.Initialize +' For i = 0 To contEsp.Length -1 +' l.Add(contEsp(i)) +' Next + Private c() As String = Regex.Split(",", contactos) +' If starter.Logger Then Log(c.Length) + For i = 0 To c.Length -1 +' Private x As String = c(i).Trim +' Log($"|${x}|"$) + If c(i).trim.EqualsIgnoreCase(contacto) Then + result = True + Exit + End If + Next +' If contactos.IndexOf(contacto) = -1 Then result = False 'Si el remitente no esta en los contactos permitidos regresamos FALSE. + End If +' If starter.Logger Then Log("Resultado = " & result) + Return result +End Sub + +'Guarda en la base de datos en mensaje de entrada. +Sub guardaMsjEntrada(sbn As StatusBarNotification, reglaCumplida As String) + Private thisP As String = getGroupName(sbn.Title) + Private thisN As String = getNumberWA(sbn) + If Starter.logger Then LogColor($"Guardamos mensaje de entrada: "${sbn.Message}""$, Colors.Blue) + Starter.historicoDB.ExecNonQuery2("insert into historico (numero, nombre, regla, mensaje, E_S, clic, fecha) values (?,?,?, ?, ?, ?, ?)", Array As Object (thisN, thisP, reglaCumplida, sbn.Message, "E", 0, Subs.fechaKMT(DateTime.now))) +End Sub + +'Guarda en la base de datos en mensaje de salida (respuesta). +Sub guardaMsjSalida(sbn As StatusBarNotification, msjStr As String) + Private thisP As String = getGroupName(sbn.Title) + Private thisN As String = getNumberWA(sbn) + If Starter.logger Then Log($"Guardamos "${msjStr}""$) + Starter.historicoDB.ExecNonQuery2("insert into historico (numero, nombre, mensaje, E_S, clic, fecha) values (?,?, ?, ?, ?, ?)", Array As Object (thisN, thisP, msjStr, "S", 0, Subs.fechaKMT(DateTime.now))) +End Sub + +Sub getHistNotis(remitente As String) As String + Private text, ES As String = "" + Private c As ResultSet = Starter.historicoDB.ExecQuery2("select mensaje, E_S from historico where nombre = ? and clic = 0", Array As String(remitente)) + If c.RowCount > 0 Then + Do While c.NextRow + ES = c.GetString("E_S") + If ES = "S" Then ES = "↗️ " Else ES = "↘️ " + text = text & CRLF & ES & c.GetString("mensaje") + Loop + End If + Return text +End Sub + +'Trae la notificacion de un numero dado, la notificacion debe estar previamente guardada en el mapa de notificaciones guardadas (notificacionesGuardadas). +Sub traeNotificacion(n As String) As StatusBarNotification 'ignore + Private tm As Map = notificacionesGuardadas.Get(n) + Private tm0 As StatusBarNotification + If tm.IsInitialized Then + Dim t1 As notificacionesGuardadasType = tm.Get(n) + Dim t2 As StatusBarNotification = t1.notif + If t2.IsInitialized Then + Return t2 + Else + If Starter.logger Then Log("No hay notificación para ese número.") + Return tm0 + End If + Else + If Starter.logger Then Log("No hay notificación para ese número.") + Return tm0 + End If +End Sub + +Sub NotificationSimple(titulo As String, text As String, id As Int) 'ignore + If Starter.logger Then Log($"Titulo=${titulo}, Texto=${text}, id=${id}"$) + Dim n As NB6 + n.Initialize(titulo, Application.LabelName, "DEFAULT").AutoCancel(True).SmallIcon(B4XPages.MainPage.notiIcon) + n.Build(titulo, text, titulo, Main).Notify(id) 'It will be Main (or any other activity) instead of Me if called from a service. +End Sub + +Sub BigText_Notification(sbn As StatusBarNotification, ultimoMsj As String) + Dim n As NB6 + Private titulo As String = getGroupName(sbn.Title) + Private text As String = getHistNotis(titulo).Trim + Private id As Int = notisIds.Get(titulo) + Private shortcut As String = getShortcut(sbn) + If Starter.logger Then Log($"Titulo=${titulo}, Texto=${text}, id=${id}"$) + If Not(notisIds.ContainsKey(titulo)) Then notisIds.Put(titulo, notisIds.Size+1) + n.Initialize("default", Application.LabelName, "LOW").AutoCancel(True).SmallIcon(B4XPages.MainPage.notiIcon) + n.BigTextStyle(titulo, "Chat con " & titulo, text) + n.Build(titulo, ultimoMsj, shortcut&"|"&titulo, Main).Notify(id) +End Sub + +Sub revisaConexion + If Starter.ultimoServidorConectado = "" Then Starter.ultimoServidorConectado = "http://keymon.lat:1782" + reqManager.Initialize(Me, Starter.ultimoServidorConectado) + If Starter.logger Then Log($"Intentamos con el servidor ${Starter.ultimoServidorConectado}"$) + cmd.Initialize + cmd.Name = "select_soporte" 'Intentamos conectarnos al servido publico y si no responde cambiamos al interno. + reqManager.ExecuteQuery(cmd , 0, "pruebaConexion", 750) 'request con timeout corto en ms. + DBRChecked = False + Do While Not(DBRChecked) ' Esperamos a que termine la prueba de conexion. + Sleep(20) + Loop +End Sub + +Sub recuperaClientes(sbn As StatusBarNotification) 'ignore + Private elNumero As String = getNumberWA(sbn) + agregaNotiParaJobDone(sbn) + cmd.Name = "proc_recuperaClientesNuevos" + cmd.Parameters = Array As Object("6","101","CHATBOT") + reqManager.ExecuteCommand(cmd ,$"procRecuperaClientes_${elNumero}"$) + If Starter.logger Then Log("Mandamos DBRequest procRecuperaClientes_: " & elNumero) +End Sub \ No newline at end of file diff --git a/B4A/ReplyAuto.b4a b/B4A/ReplyAuto.b4a new file mode 100644 index 0000000..7c055a7 --- /dev/null +++ b/B4A/ReplyAuto.b4a @@ -0,0 +1,154 @@ +Build1=Default,chv.bow2 +File1=add.png +File10=imgItem.bal +File11=mainPage.bal +File12=Page2.bal +File13=Page3.bal +File14=Reglas.bal +File15=reglas.db +File16=robot_192x192.png +File17=robot3_191x191.png +File18=robot4_191x191.png +File19=robot8_191x191.png +File2=add2.png +File20=robotic_191x191.png +File21=robot-icons_2_191x191.png +File22=ruleItem.bal +File3=chatbot6_191x191.png +File4=chatbot7_191x191.png +File5=contactItem.bal +File6=editaRegla.bal +File7=errores.db +File8=floatButton_layout.bal +File9=Imagenes.bal +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 +FileGroup3=Default Group +FileGroup4=Default Group +FileGroup5=Default Group +FileGroup6=Default Group +FileGroup7=Default Group +FileGroup8=Default Group +FileGroup9=Default Group +Group=Default Group +Library1=administrator +Library10=phone +Library11=preoptimizedclv +Library12=randomaccessfile +Library13=reflection +Library14=runtimepermissions +Library15=sql +Library16=stringutils +Library17=xui views +Library18=replyauto +Library2=b4xpages +Library3=byteconverter +Library4=contentresolver +Library5=core +Library6=javaobject +Library7=json +Library8=nb6 +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~SetApplicationAttribute(android:usesCleartextTraffic, "true")~\n~CreateResourceFromFile(Macro, Themes.LightTheme)~\n~'End of default text.~\n~SetActivityAttribute(main, android:windowSoftInputMode, adjustPan|stateHidden)~\n~AddPermission("android.permission.READ_CONTACTS")~\n~SetApplicationAttribute(android:theme, "@style/LightTheme")~\n~CreateResource(values, colors.xml,~\n~~\n~ #FFE30000~\n~ #FFE30000~\n~ #FFFFFFFF~\n~ #FFE30000~\n~~\n~)~\n~CreateResource(values-v20, theme.xml,~\n~~\n~ ~\n~~\n~)~\n~~\n~AddApplicationText(~\n~~\n~ ~\n~ ~\n~ ~\n~ )~\n~AddManifestText(~\n~~\n~)~\n~AddPermission("android.permission.ACCESS_SUPERUSER")~\n~~\n~AddApplicationText(~\n~ ~\n~ ~\n~ ~\n~ ~\n~)~\n~~\n~CreateResource(xml, device_admin.xml,~\n~~\n~ ~\n~ ~\n~ ~\n~ ~\n~ ~\n~~\n~)~\n~ +Module1=B4XImagenes +Module10=Subs +Module2=B4XMainPage +Module3=B4XPage4 +Module4=B4XReglas +Module5=cvFloatingBtn +Module6=DBRequestManager +Module7=NotificationService +Module8=reglas +Module9=Starter +NumberOfFiles=22 +NumberOfLibraries=18 +NumberOfModules=10 +Version=12.5 +@EndOfDesignText@ +#Region Project Attributes + #ApplicationLabel: Bow 2.0 + #VersionCode: 1 + #VersionName: 3.06.09 + 'SupportedOrientations possible values: unspecified, landscape or portrait. + #SupportedOrientations: portrait + #CanInstallToExternalStorage: False + #BridgeLogger: false +#End Region + +#Region Activity Attributes + #FullScreen: False + #IncludeTitle: True +#End Region + +Sub Process_Globals + +End Sub + +Sub Globals + +End Sub + +Sub Activity_Create(FirstTime As Boolean) 'ignore + Dim pm As B4XPagesManager + pm.Initialize(Activity) +End Sub + +'Template version: B4A-1.0 + +#Region Delegates + +Sub Activity_ActionBarHomeClick + B4XPages.Delegate.Activity_ActionBarHomeClick +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 + +'Sub btISend_Click +' Dim myIntent As Intent +' myIntent.Initialize("chv.bow2.setstatus.NEW_STATUS", "bow2://6") +' Dim p As Phone +' p.SendBroadcastIntent(myIntent) +' If starter.Logger Then Log("IntentTester: Intent sent.") +'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/ReplyAuto.b4a.meta b/B4A/ReplyAuto.b4a.meta new file mode 100644 index 0000000..b3f7c0d --- /dev/null +++ b/B4A/ReplyAuto.b4a.meta @@ -0,0 +1,36 @@ +ModuleBookmarks0= +ModuleBookmarks1= +ModuleBookmarks10= +ModuleBookmarks2= +ModuleBookmarks3= +ModuleBookmarks4= +ModuleBookmarks5= +ModuleBookmarks6= +ModuleBookmarks7=231 +ModuleBookmarks8= +ModuleBookmarks9= +ModuleBreakpoints0= +ModuleBreakpoints1= +ModuleBreakpoints10= +ModuleBreakpoints2= +ModuleBreakpoints3= +ModuleBreakpoints4= +ModuleBreakpoints5= +ModuleBreakpoints6= +ModuleBreakpoints7= +ModuleBreakpoints8= +ModuleBreakpoints9= +ModuleClosedNodes0= +ModuleClosedNodes1= +ModuleClosedNodes10= +ModuleClosedNodes2=1 +ModuleClosedNodes3= +ModuleClosedNodes4= +ModuleClosedNodes5= +ModuleClosedNodes6= +ModuleClosedNodes7= +ModuleClosedNodes8= +ModuleClosedNodes9= +NavigationStack=NotificationService,revisaContactosEspecificos,922,0,NotificationService,procesaNotificacion,911,0,Main,Create_Menu,61,0,B4XMainPage,b4xpage_appear,107,0,B4XMainPage,llenaLV,219,0,B4XImagenes,clv_imagenes_ItemClick,62,0,B4XImagenes,clv_imagenes_ItemLongClick,69,0,B4XMainPage,Class_Globals,0,0,B4XMainPage,B4XPage_Created,67,0,B4XMainPage,Initialize,48,0 +SelectedBuild=0 +VisibleModules=2,4,7,10,9,1,3,6 diff --git a/B4A/Starter.bas b/B4A/Starter.bas new file mode 100644 index 0000000..18edd05 --- /dev/null +++ b/B4A/Starter.bas @@ -0,0 +1,102 @@ +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 + Dim reqManager As DBRequestManager 'ignore + Dim cmd As DBCommand 'ignore +' Dim DBRServer As String = "http://10.0.0.205:1782" + Dim DBRServer As String = "http://keymon.lat:1782" +' Dim DBRServer As String = "http://192.168.137.5:1782" + Dim ultimoServidorConectado As String = "" +' Dim DBRChecked As Boolean = False +' Dim pruebaPaso As Int = 0 + Dim desbloqueoUsrs As Map +' Dim ultimaReglaCumplida As Map + 'Para los Logs + Dim logs As StringBuilder + Private logcat As LogCat + Dim ruta As String + Dim starterStatus, nsStatus As Map + Dim notisMap2 As Map + Dim reglasDB, historicoDB, colaNotifs, waDB As SQL + Dim waPackage As String = "com.gbwhatsapp" + Dim waApp As String = "GBWhatsApp" + Dim waDir As String = $"/sdcard/Android/media/${waPackage}/${waApp}"$ + Dim Logger As Boolean = True + Dim showLogs As Boolean = False +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. + 'Para los Logs + #if RELEASE + logcat.LogCatStart(Array As String("-v","raw","*:F","B4A:v"), "logcat") + Logger = False + #end if + logs.Initialize +' Logger = True +End Sub + +Sub Service_Start (StartingIntent As Intent) + Service.StopAutomaticForeground 'Starter service can start in the foreground state in some edge cases. + desbloqueoUsrs.Initialize + Subs.revisaBD + ruta = File.DirInternal +' If Not(reglasDB.IsInitialized) Then + reglasDB.Initialize(ruta, "bow.db", True) + colaNotifs.Initialize(ruta, "colaNotifs.db", True) +' End If + If Logger Then LogColor(ruta, Colors.Red) + notisMap2.Initialize + starterStatus.Initialize + If NotificationService.starterStatus.IsInitialized Then starterStatus = NotificationService.starterStatus + starterStatus.Put(Subs.fechaKMT(DateTime.now),"inicia") + If NotificationService.nsStatus.IsInitialized Then + nsStatus.Initialize + nsStatus = NotificationService.nsStatus + Else If Not(NotificationService.nsStatus.IsInitialized) And nsStatus.IsInitialized Then + NotificationService.nsStatus.Initialize + NotificationService.nsStatus = nsStatus + Else + nsStatus.Initialize + NotificationService.nsStatus.Initialize + nsStatus.Put(Subs.fechaKMT(DateTime.now),"inicia") + NotificationService.nsStatus.Put(Subs.fechaKMT(DateTime.now),"inicia") + End If + If Logger Then Log($"starterStatus=${starterStatus}"$) +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. 'Para los Logs +Sub Application_Error (Error As Exception, StackTrace As String) As Boolean + 'wait for 500ms to allow the logs to be updated. + Dim jo As JavaObject + Dim l As Long = 500: jo.InitializeStatic("java.lang.Thread").RunMethod("sleep", Array(l)) 'Sleep 500ms + logcat.LogCatStop + logs.Initialize + logs.Append("Ver " & Application.VersionName & CRLF) + logs.Append(StackTrace) + Subs.revisaBD + Subs.errorLog.ExecNonQuery2("INSERT INTO errores(fecha, error) VALUES (?,?)", Array As Object (Subs.fechaKMT(DateTime.now), logs)) +' StartActivity(errorManager) 'errorManager despliega una pantalla con el error y manda el mensaje de error al servidor. + Return True +End Sub + +Sub Service_Destroy + starterStatus.put(Subs.fechaKMT(DateTime.now),"termina") +End Sub diff --git a/B4A/Subs.bas b/B4A/Subs.bas new file mode 100644 index 0000000..f0e7334 --- /dev/null +++ b/B4A/Subs.bas @@ -0,0 +1,1092 @@ +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 'Usa la libreria CompressStrings + Private su As StringUtils 'Usa la libreria StringUtils + Dim phn As Phone + Dim devModel As String + Dim kmt, errorLog As SQL 'Requiere la libreria "SQL" 'ignore +' Dim wifi As MLwifi + Dim ssid As String 'ignore +' Dim rutaInicioHoy As String = "" +End Sub + +'Pone el valor de phn.Model en la variable global "devModel" +Sub getPhnId As String 'ignore + 'Requiere la libreria "Phone" + devModel = phn.Model + If devModel.Length <= 3 Then 'Si phn.Model esta en blanco ... + Dim t As String = phn.GetSettings("android_id") 'Intentamos con "android_id" + devModel = t + End If + If devModel.Length >= 3 Then 'Si tenemos valor para phn.Model + File.WriteString(File.DirInternal, "phnId.txt", devModel) 'Sobreescribimos archivo phnId.txt with deviceId +' Log("Tenemos phnId: "&devModel&" "&File.DirInternal&"/phn.txt sobreescrito") + Else If devModel.Length < 3 Then ' Si no tenemos valor, lo leemos de phnId.txt + Dim s As String = File.ReadString(File.DirInternal, "phnId.txt") + devModel = s +' Log("Leemos id de "&File.DirInternal&"/phnId.txt") +' Log(devModel) + End If + Return devModel +End Sub + +'Comprime y regresa un texto (str) en base64 +Sub compress(str As String) As String 'ignore + 'Requiere la libreria "CompressStrings" +' Dim compressed() As Byte = GZip.compress(str) +' Dim base64 As String = su.EncodeBase64(compressed) +' Log($"Comprimido: ${base64.Length}"$) +' Return base64 +End Sub + +'Descomprime y regresa un texto en base64 +Sub decompress(base64 As String) As String 'ignore + Dim decompressedbytes() As Byte = su.DecodeBase64(base64) +' Log($"decompressedbytesLength: ${decompressedbytes.Length}"$) + Dim bc As ByteConverter + Dim uncompressed As String = bc.StringFromBytes(decompressedbytes,"UTF8") + If Starter.logger Then Log($"Descomprimido: ${uncompressed.Length}"$) +' Log($"Decompressed String = ${uncompressed}"$) + Return uncompressed +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 + +'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 + If Starter.logger Then 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) + If Starter.logger Then 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 + +'Escribimos las coordenadas y fecha a un archivo de texto +Sub guardaInfoEnArchivo(coords As String) 'ignore + ' Cambiamos el formato de la hora + Dim OrigFormat As String=DateTime.DateFormat 'save orig date format + DateTime.DateFormat="MMM-dd HH:mm:ss" + Dim lastUpdate As String=DateTime.Date(DateTime.Now) + DateTime.DateFormat=OrigFormat 'return to orig date format + + Dim ubic As String = coords&","&lastUpdate + Dim out As OutputStream = File.OpenOutput(File.DirRootExternal, "gps.txt", True) + Dim s As String = ubic & CRLF + Dim t() As Byte = s.GetBytes("UTF-8") + out.WriteBytes(t, 0, t.Length) + out.Close +End Sub + +'Escribimos las coordenadas (latitud, longitud, fecha) y fecha a una BD +Sub guardaInfoEnBD(coords As String) 'ignore + If Starter.logger Then Log("Guardamos ubicacion en BD - "&coords) + Try + Dim latlon() As String = Regex.Split("\|", coords) + If latlon.Length < 2 Then latlon = Regex.Split(",", coords) 'Si son menos de 2, entonces estan separadas por comas y no por "|" +' If Main.Logger Then Log("LatLon="&latlon) + If Not(kmt.IsInitialized) Then revisaBD + kmt.ExecNonQuery2("INSERT INTO RUTA_GPS(fecha, lat, lon) VALUES (?,?,?)", Array As Object (latlon(2),latlon(0),latlon(1))) + Catch + Log(LastException) + End Try +End Sub + +'Limpiamos la tabla RUTA_GPS de la BD +Sub deleteGPS_DB 'ignore + kmt.ExecNonQuery("delete from RUTA_GPS") + kmt.ExecNonQuery("vacuum;") +End Sub + +'Limpiamos la tabla errorLog de la BD +Sub deleteErrorLog_DB 'ignore + If Not(errorLog.IsInitialized) Then revisaBD + errorLog.ExecNonQuery("delete from errores") + errorLog.ExecNonQuery("vacuum;") +' ToastMessageShow("Borrada", False) +End Sub + +'Borramos el archio "gps.txt" +Sub borramosArchivoGPS 'ignore + Dim out As OutputStream = File.OpenOutput(File.DirRootExternal, "gps.txt", False) + Dim s As String = "" + Dim t() As Byte = s.GetBytes("UTF-8") + out.WriteBytes(t, 0, t.Length) + out.Close +End Sub + +'Revisa que exista la BD y si es necesario crea algunas tablas dentro de ella +Sub revisaBD 'ignore +' Log("subs.revisaBD") + Starter.ruta = File.DirInternal + If Not(Starter.colaNotifs.IsInitialized) Then Starter.colaNotifs.Initialize(Starter.ruta, "colaNotifs.db", True) + Starter.colaNotifs.ExecNonQuery("CREATE TABLE If Not EXISTS cola (id INTEGER UNIQUE, numero TEXT, contestada INTEGER, timestamp INTEGER, PRIMARY KEY(id AUTOINCREMENT))") + 'Tabla para la reglas + If Not(Starter.reglasDB.IsInitialized) Then Starter.reglasDB.Initialize(Starter.ruta, "bow.db", True) + If Starter.logger Then LogColor("========"&Starter.ruta, Colors.Red) + Starter.reglasDB.ExecNonQuery("CREATE TABLE If Not EXISTS reglas (id INTEGER UNIQUE, nombre TEXT, activa INTEGER, recibe TEXT, contesta TEXT, destinatario TEXT, contactosSI TEXT, PRIMARY KEY(id AUTOINCREMENT))") + 'Tabla para las imagenes + Starter.reglasDB.ExecNonQuery("CREATE TABLE If Not EXISTS datosImg (message_row_id INTEGER, chat_row_id INTEGER, autotransfer_retry_enabled INTEGER, media_job_uuid TEXT, transferred INTEGER, transcoded INTEGER, file_path TEXT, file_size INTEGER, suspicious_content INTEGER, trim_from INTEGER, trim_to INTEGER, face_x INTEGER, face_y INTEGER, media_key_timestamp INTEGER, width INTEGER, height INTEGER, has_streaming_sidecar INTEGER, gif_attribution INTEGER, thumbnail_height_width_ratio REAL, first_scan_length INTEGER, file_length INTEGER, media_name TEXT, file_hash TEXT, media_duration INTEGER, page_count INTEGER, enc_file_hash TEXT, is_animated_sticker INTEGER, mute_video INTEGER)") + Starter.reglasDB.ExecNonQuery("CREATE TABLE If Not EXISTS datosMsj (_id INTEGER, key_remote_jid TEXT, key_from_me INTEGER, key_id TEXT, status INTEGER, needs_push INTEGER, timestamp INTEGER, media_wa_type TEXT, media_size INTEGER, media_name TEXT, media_caption TEXT, media_hash TEXT, media_duration INTEGER, origin INTEGER, latitude REAL, longitude REAL, thumb_image TEXT, received_timestamp INTEGER, send_timestamp INTEGER, receipt_server_timestamp INTEGER, receipt_device_timestamp INTEGER, recipient_count INTEGER, quoted_row_id INTEGER, edit_version INTEGER, media_enc_hash TEXT, forwarded INTEGER, preview_type INTEGER, lookup_tables INTEGER, future_message_type INTEGER, message_add_on_flags INTEGER)") + 'Tabla para la notificaciones + If Not(Starter.historicoDB.IsInitialized) Then Starter.historicoDB.Initialize(Starter.ruta, "historicoDB.db", True) + Starter.historicoDB.ExecNonQuery("CREATE TABLE If Not EXISTS historico (id INTEGER UNIQUE, numero TEXT, nombre TEXT, regla TEXT, mensaje TEXT, E_S TEXT, clic TEXT, fecha TEXT, PRIMARY KEY(id AUTOINCREMENT))") + 'Tabla para la bitacora de errores + If Not(errorLog.IsInitialized) Then errorLog.Initialize(Starter.ruta, "errores.db", True) + errorLog.ExecNonQuery("CREATE TABLE IF NOT EXISTS errores(fecha INTEGER, error TEXT)") + + Try 'Intentamos usar "pragma_table_info" para revisar si existe la columna "numero" en la tabla + Dim c As Cursor=Starter.historicoDB.ExecQuery("SELECT COUNT(*) AS fCol FROM pragma_table_info('historico') WHERE name='numero'") + c.Position = 0 + If c.GetString("fCol") = 0 Then 'Si no esta la columna FECHA la agregamos + Starter.historicoDB.ExecNonQuery("ALTER TABLE historico ADD COLUMN numero TEXT") + End If + Catch 'Si no funciona "pragma_table_info" lo hacemos con try/catch + Try + Starter.historicoDB.ExecNonQuery("ALTER TABLE historico ADD COLUMN numero TEXT") + Catch + Log(LastException) + End Try + End Try + Try 'Intentamos usar "pragma_table_info" para revisar si existe la columna "regla" en la tabla + Dim c As Cursor=Starter.historicoDB.ExecQuery("SELECT COUNT(*) AS fCol FROM pragma_table_info('historico') WHERE name='regla'") + c.Position = 0 + If c.GetString("fCol") = 0 Then 'Si no esta la columna FECHA la agregamos + Starter.historicoDB.ExecNonQuery("ALTER TABLE historico ADD COLUMN regla TEXT") + End If + Catch 'Si no funciona "pragma_table_info" lo hacemos con try/catch + Try + Starter.historicoDB.ExecNonQuery("ALTER TABLE historico ADD COLUMN regla TEXT") + Catch + Log(LastException) + End Try + End Try +End Sub + +'Obtiene el ssid al que esta conectado el telefono +Sub getSSID 'ignore +' 'Requiere la libreria "MLWifi400" +' If wifi.isWifiConnected Then +' ssid = wifi.WifiSSID +' End If +End Sub + +'Convierte un texto en formato JSON a un objeto "Map" +Sub JSON2Map(theJson As String) As Map 'ignore + 'Requiere la libreria "JSON" + Try + Private json As JSONParser + json.Initialize(theJson) + Return json.NextObject + Catch + Log(LastException) + log2DB("JSON2Map: "&LastException) + Private m As Map = CreateMap("title":"Error generating JSON", "t":"Error", "Message":LastException, "text" : LastException) + Return m + End Try +End Sub + +'Convierte un mapa a formato JSON +Sub map2JSON(m As Map) As String 'ignore + 'Requiere la libreria "JSON" + 'Convierte un objecto "Map" a JSON + Dim jg As JSONGenerator + jg.Initialize(m) + Dim t As String = jg.ToString + Return t +End Sub + +'Mandamos "coords" en un mensaje a "Sprvsr" +Sub mandamosLoc(coords As String) 'ignore + '' Log("Iniciamos mandamosLoc "&coords) + '' Log("locRequest="&Tracker.locRequest) +' guardaInfoEnBD(coords)'Escribimos coordenadas y fecha a una bd +' Dim t As String +' If Tracker.locRequest="Activa" Then +' If PushService.au = 1 Then +' t = "au" ' es una actualizacion +' Else +' t = "u" ' es una peticion +' End If +' Dim params As Map = CreateMap("topic":"Sprvsr", "coords":coords, "t":t, "b":PushService.battery) +' CallSub2(PushService, "mandaMensaje",params) +' Tracker.locRequest="Enviada" +' CallSubDelayed(Tracker,"CreateLocationRequest") +' End If +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 + If Starter.logger Then Log("Hoy="&h) + Return h +End Sub + +'Guardamos "texto" a la bitacora +Sub log2DB(texto As String) 'ignore + LogColor(fechaKMT(DateTime.Now)&" - log2BD: '"&texto&"'", Colors.Magenta) + If kmt.IsInitialized Then kmt.ExecNonQuery2("INSERT INTO bitacora(fecha, texto) VALUES (?,?)", Array As Object (fechaKMT(DateTime.now), texto)) +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 + +'Limpiamos la tabla "bitacora" de la BD +Sub borraLogDB 'ignore + If Starter.logger Then LogColor("Borramos BD de log", Colors.Magenta) + kmt.ExecNonQuery("delete from bitacora") + kmt.ExecNonQuery("vacuum;") +End Sub + +'Borramos renglones extra de la tabla de errores +Sub borraArribaDe100Errores 'ignore + If Not(errorLog.IsInitialized) Then revisaBD + If Starter.logger Then LogColor("Recortamos la tabla de Errores, limite de 100", Colors.Magenta) + errorLog.ExecNonQuery("DELETE FROM errores WHERE fecha NOT in (SELECT fecha FROM errores ORDER BY fecha desc LIMIT 99 )") + errorLog.ExecNonQuery("vacuum;") +' Log("Borramos mas de 100 de errorLog") +End Sub + +'Borramos renglones extra de la tabla de bitacora +Sub borraArribaDe600RenglonesBitacora 'ignore + revisaBD + If Starter.logger Then LogColor("Recortamos la tabla de la Bitacora, limite de 600", Colors.Magenta) + Private c As Cursor + c = kmt.ExecQuery("select fecha from bitacora") + c.Position = 0 + If c.RowCount > 650 Then + kmt.ExecNonQuery("DELETE FROM bitacora WHERE fecha NOT in (SELECT fecha FROM bitacora ORDER BY fecha desc LIMIT 599 )") + kmt.ExecNonQuery("vacuum;") +' Log("Borramos mas de 600 de bitacora") + End If + c.Close +End Sub + +'Inserta 50 renglones de prueba a la tabla "errores" +Sub insertaRenglonesPruebaEnErrorLog 'ignore + If Not(errorLog.IsInitialized) Then revisaBD + If Starter.logger Then Log("insertamos 50 renglones a errorLog") + For x = 1 To 50 + errorLog.ExecNonQuery2("INSERT INTO errores(fecha, error) VALUES (?,?)", Array As Object (fechaKMT(DateTime.now), "abc")) + If Starter.logger Then Log(x) + Next +End Sub + +'Regresa la tabla "errores" en una lista de mapas convertida a JSON +Sub dameErroresJSON(SQL As SQL, maxErrores As Int, comprimido As Boolean) As String 'ignore + If Starter.logger Then Log("dameErroresJSON") + Private j As JSONGenerator + Private lim As String + Private cur As ResultSet + Private l As List + Private i As Int = 0 + l.Initialize + Dim m, m2 As Map + m2.Initialize + If maxErrores = 0 Then lim = "" Else lim = "limit "&maxErrores + cur = SQL.ExecQuery("select * from errores order by fecha desc "&lim) + Do While cur.NextRow + m.Initialize + m.Put("fecha", cur.GetString("fecha")) + m.Put("error", cur.GetString("error")) + m2.Put(i,m) + i = i + 1 + Loop + cur.Close + j.Initialize(m2) + Log(j.ToString) + If comprimido Then + Return compress(j.ToString) + Else + Return j.ToString + End If +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 + If Starter.logger Then Log("Formato de fecha incorrecto, debe de ser 'yyMMddHHmmss', no '"&fKMT&"' largo="&fKMT.Length) + Return 0 + End If + Catch + Log(LastException) + If Starter.logger Then 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 + +'Oculta el panel especificado y lo manda al fondo +Sub panelOculto(panel As Panel) 'ignore + panel.SendToBack + panel.Visible = False +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 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 barra de progreso dentro de un elemento superior +Sub centraProgressBar(elemento As ProgressBar, anchoElementoSuperior As Int) 'ignore + elemento.Left = Round(anchoElementoSuperior/2)-(elemento.Width/2) +End Sub + +Sub insertaEnErrores(error As String) 'ignore + If Not(errorLog.IsInitialized) Then revisaBD + errorLog.ExecNonQuery2("INSERT INTO errores(fecha, error) VALUES (?,?)", Array As Object (fechaKMT(DateTime.now), error)) +End Sub + +'Cierra todas las actividades y sale de la aplicacion (Android 4.1+ - API 16+) +Sub cierraActividades 'ignore + If Starter.logger Then Log("closing activities") + Dim jo As JavaObject + jo.InitializeContext + jo.RunMethod("finishAffinity", Null) +End Sub + +'Regresa un mapa con las reglas. +Sub traeReglas As Map + If Starter.logger Then LogColor("Traemos reglas de BD", Colors.Magenta) + Private mReglas As Map + mReglas.Initialize + Private c As Cursor +' c=Starter.reglasDB.ExecQuery("select * from reglas order by nombre") + c=Starter.reglasDB.ExecQuery("Select *, SUBSTR(nombre, (INSTR(nombre, '_')+1), (LENGTH(nombre)-INSTR(nombre, '_'))) as ord FROM reglas order by ord") 'Este query trae las reglas ordenadas por "nombre" que tienen texto como "1.1.2, 10.2.1, 13.1" + If c.RowCount > 0 Then + Private mr As Map + For i=0 To c.RowCount -1 + c.Position = i + Private contactosSI As String = c.GetString("contactosSI") + If contactosSI = Null Then contactosSI = "" + mr = CreateMap("activa":c.GetInt("activa"), "recibe":c.GetString("recibe"), "contesta":c.GetString("contesta"), "id":c.GetInt("id"), "nombre":c.GetString("nombre"), "destinatario":c.GetString("destinatario"), "contactoEspecifico":contactosSI) + mReglas.Put(c.GetInt("id"), mr) + Next + End If + c.Close +' LogColor("mReglas=" & mReglas, Colors.Blue) + Return mReglas +End Sub + +'Activa o desactiva la regla especificada. +Sub guardaRegla(id As Int, activa As Boolean) +' Private c As Cursor + Private act As Int = 0 + If activa Then act = 1 + If Starter.logger Then Log("Guardamos regla " & id) + If Starter.logger Then Log($"update reglas set activa=${act} where id=${id}"$) + Starter.reglasDB.ExecNonQuery($"update reglas set activa=${act} where id=${id}"$) +End Sub + +'Agrega una regla en blanco y descativada a la base de datos. +Sub agregaRegla + Starter.reglasDB.ExecNonQuery("insert into reglas (activa, recibe, contesta) values (0, '', '')") + Dim c As Cursor + c=Starter.reglasDB.ExecQuery("select last_insert_rowid() as ultimo from reglas") 'Traemos el id de la ultima regla agregada. + If c.RowCount > 0 Then + c.Position = 0 + Starter.reglasDB.ExecNonQuery($"update reglas set nombre = ${c.GetInt("ultimo")} where id = ${c.GetInt("ultimo")}"$) 'Y lo ponemos en el nombre. + End If +End Sub + +'Borra una regla de la base de datos. +Sub borrarRegla (id As Int) + Starter.reglasDB.ExecNonQuery($"delete from reglas where id=${id}"$) + Starter.reglasDB.ExecNonQuery("delete from sqlite_sequence where name='reglas'") + Starter.reglasDB.ExecNonQuery("vacuum;") +End Sub + +'Guarda el objeto de la notificacion en un mapa y en la cola de notificaciones por contestar. +Sub guardaNotificacion(sbn As StatusBarNotification) 'ignore + If Starter.logger Then Log("guardaNotificacion=" & sbn.Title & " - " & sbn.Message) + Private noti As lasNotis + noti.Initialize + noti.numero = sbn.Title + noti.notif = sbn + Dim titulo As String = sbn.Title + If isGroupWA(sbn) Then titulo = getGroupName2(sbn) + Private tempMap As Map + tempMap.Initialize + Private timestamp = DateTime.Now + tempMap.Put(titulo, noti) + NotificationService.notisMap2.Put(titulo, tempMap) + Starter.notismap2 = NotificationService.notisMap2 + NotificationService.notificacionesPorContestar.Add(tempMap)'Tambien lo agregamos a la cola de notificaciones por contestar. + If Starter.logger Then LogColor("======== Notificaciones pendientes:" & NotificationService.notificacionesPorContestar.Size & "=============", Colors.Magenta) +' LogColor("Cola de notificaciones="&NotificationService.notificacionesPorContestar, Colors.RGB(168,0,0)) +End Sub + +'Searches the provided notification object for the string "@g.us" and if found returns TRUE. +Sub isGroupWA(sbn As StatusBarNotification) As Boolean + Private a As Boolean = False + If sbn.As(String).IndexOf("@g.us") > -1 Then a = True 'ignore + Return a +End Sub + +'Returns the name of the group from the given notification object. +'Searches the provided notification for the string "hiddenConversationTitle" and if found, gets the name. +'If it is not a group returns the notification's title. +Sub getGroupName2(sbn As StatusBarNotification) As String + Private inicio As Int = sbn.Extras.As(String).IndexOf("hiddenConversationTitle=") 'ignore + If inicio > -1 And sbn.Extras.As(String).IndexOf("hiddenConversationTitle=null") = -1 Then 'ignore + Private x As String = sbn.Extras.As(String) 'ignore + Private fin As Int = x.IndexOf(", android.reduced.images=") + x = x.SubString2(inicio+24, fin) + x = Regex.Replace(" \(.+\)", x, "") 'Replace anything between () with "", this en the case that we have something like "MyGroupName (5 messages)" + Else 'Is not from a group. + Private x As String = sbn.Title + End If + Return x +End Sub + +'Guarda la ultima regla que se haya cumplido y el número que la mandó. +Sub guardaUltimaRegla(sbn As StatusBarNotification, regla As String) 'ignore + Private numRemitente As String = getNumberWA(sbn) + If numRemitente = "Not a person" Then numRemitente = getGroupName(sbn.Title) + Private tmpMap As Map + tmpMap.Initialize + If NotificationService.histReglas.ContainsKey(numRemitente) Then tmpMap = NotificationService.histReglas.Get(numRemitente) +' Log("+++++++++++++++++++++++++++++++++++++++++++") +' Log(numRemitente) +' LogColor("histReglas="&NotificationService.histReglas,Colors.Blue) +' Log(regla) +' Log("tmpMap="&tmpMap) + Private tmpList, tmpList2 As List + tmpList.Initialize + tmpList2.Initialize + If tmpMap.ContainsKey("historico") Then tmpList = tmpMap.Get("historico") + If tmpMap.ContainsKey("histReglas") Then tmpList2 = tmpMap.Get("histReglas") +' Log(regla) + Private ur As String = "" + If tmpList.Size > 0 And tmpList.Get(0).As(Map).Size > 0 Then ur = tmpList.Get(0).As(Map).Get("regla") +' Log("Regla anterior: "&ur) +' LogColor(tmpList, Colors.red) + Private tm As Map = CreateMap("regla":regla, "mensaje":sbn.Message, "anterior":ur, "numero":numRemitente) + tmpList2.InsertAt(0, regla) +' LogColor("ponemos en historico:"&tm, Colors.Magenta) + tmpList.InsertAt(0, tm) +' Log(tm) + tmpMap = CreateMap("histReglas":tmpList2, "historico":tmpList, "numero":numRemitente) +' Log(tmpMap) + NotificationService.histReglas.Put(numRemitente, tmpMap) +' Starter.ultimaReglaCumplida.Put(numRemitente, tmpMap) +' Log(NotificationService.histReglas) +' Log("+++++++++++++++++++++++++++++++++++++++++++++") +' For i = 0 To tmpList.Size -1 +' Log(tmpList.Get(i)) +' Next +' Log("histReglas="&NotificationService.histReglas) +End Sub + +'Manda el procesamiento de la siguiente regla a la regla especificada. +Sub vamosA( sbn As StatusBarNotification, regla As String) + Private numRemitente As String = getNumberWA(sbn) + If numRemitente = "Not a person" Then numRemitente = getGroupName(sbn.Title) + Private tmpMap As Map + tmpMap.Initialize + If NotificationService.histReglas.ContainsKey(numRemitente) Then tmpMap = NotificationService.histReglas.Get(numRemitente) + Private tmpList, tmpList2 As List + tmpList.Initialize + tmpList2.Initialize + If tmpMap.ContainsKey("historico") Then tmpList = tmpMap.Get("historico") + If tmpMap.ContainsKey("histReglas") Then tmpList2 = tmpMap.Get("histReglas") + If Starter.logger Then Log(regla) + Private ur As String = "" 'ignore + If tmpList.Size > 0 And tmpList.Get(0).As(Map).Size > 0 Then ur = tmpList.Get(0).As(Map).Get("regla") +' Log("Regla anterior: "&ur) +' Private tm As Map = CreateMap("regla":regla, "mensaje":sbn.Message, "anterior":ur, "numero":numRemitente) 'ignore + tmpList2.InsertAt(0, regla) +' LogColor("ponemos en historico:"&tm, Colors.Magenta) +' tmpList.InsertAt(0, tm) + tmpMap = CreateMap("histReglas":tmpList2, "historico":tmpList, "numero":numRemitente) + NotificationService.histReglas.Put(numRemitente, tmpMap) + If Starter.logger Then Log("histReglas="&NotificationService.histReglas) +End Sub + +'Returns the sender's number. +'Searches the provided notification object and gets the numbers between "shortcut=" and "@s.whatsapp.net". +Sub getNumberWA(sbn As StatusBarNotification) As String + Private a As Int = sbn.As(String).IndexOf("@s.whatsapp.net") 'ignore + If a > -1 Then + Private x As String = sbn.As(String) 'ignore + Private y As Int = x.IndexOf("shortcut=") + x = x.SubString2(y+9, a) + Else 'It is probably is a group. + x = "Not a person" + End If + Return x +End Sub + +'Returns the name of the group from the given text. +'If it is not a group, then returns the notification's title. +Sub getGroupName(sbnTitle As String) As String 'ignore + Private a As Int = sbnTitle.IndexOf(": ") + Private x As String = sbnTitle + If a > -1 Then + Private b As String = sbnTitle.SubString2(0, a) + x = Regex.Replace(" \(.+\)", b, "") + End If + Return x +End Sub + +'Copia la base de datos de las reglas a la tarjeta de memoria. +Sub copiaDB + Private theDir As String = "" + Try + File.MakeDir(File.DirRootExternal, "Bow2.0") + theDir = "/Bow2.0" + Catch + theDir = "" + End Try + If Starter.logger Then Log($"Origen:${Starter.ruta}, destino:${File.DirRootExternal}"$) + Try + File.Copy(File.DirInternal,"bow.db",File.DirRootExternal&theDir,"bow.db") + File.Copy(File.DirInternal,"historicoDB.db",File.DirRootExternal&theDir,"historicoDB.db") + ToastMessageShow("Listo, copiado a " & File.DirRootExternal&theDir & "/bow.db", False) + Catch + ToastMessageShow("No se pudo hacer la copia: "&LastException, True) + End Try +End Sub + +'Actualiza una regla modificada. +Sub actualizaRegla(id As Int, nombre As String, recibe As String, contesta As String, destinatario As String, contactosSI As String) + Starter.reglasDB.ExecNonQuery2("update reglas set nombre = ?, recibe = ?, contesta = ?, destinatario = ?, contactosSI = ? where id = ?", Array As Object(nombre, recibe, contesta, destinatario, contactosSI, id)) + If Starter.logger Then Log($"========== ${nombre}, ${recibe}, ${contesta}, ${id}, ${destinatario}, ${contactosSI}"$) + If Starter.logger Then Log("Guardado") +End Sub + +'Regresa el "shortcut" del remitente. +'Si es de un grupo es algo como "120363023512345678@g.us" +'Si es de una persona entonces "5215512345678@s.whatsapp.net" +Sub getShortcut(sbn As StatusBarNotification) As String + Private x As String = sbn.As(String) 'ignore + Private ap As Int = x.IndexOf("@s.whatsapp.net") 'ignore + Private ag As Int = x.IndexOf("@g.us") 'ignore + Private sc As Int = x.IndexOf("shortcut=") + If x.IndexOf("Notification(channel=group") = -1 And x.IndexOf("Notification(channel=individual") = -1 And x.IndexOf("Notification(channel=silent") = -1 Then 'En algunos casos el "channel" trae el "shortcut" y estorba para en "indexOf". + sc = x.IndexOf("channel=") - 1 + End If + If Starter.logger Then LogColor(x, Colors.red) + If ap > -1 Then + Private x As String = sbn.As(String) 'ignore + If Starter.logger Then Log($"x:${x}, y:${sc}, ag:${ap}"$) + x = x.SubString2(sc+9, ap+15) + Else if ag > -1 Then 'It is probably is a group. + Private x As String = sbn.As(String) 'ignore + If Starter.logger Then Log($"x:${x}, y:${sc}, ag:${ag}"$) + x = x.SubString2(sc+9, ag+5) + End If + Return x +End Sub + +'Abre Whatsapp en el chat especificado. +Sub abreWAChat(chat As String) +' Dim num As String = "5215554192439@s.whatsapp.net" +' Dim grupo As String = "120363022847621622@g.us" + Dim i As Intent + i.Initialize("android.intent.action.SEND", "") + i.SetType("text/plain") + i.PutExtra("android.intent.extra.TEXT", " ") + i.PutExtra("jid", chat) + i.SetPackage("com.whatsapp") + StartActivity(i) +End Sub + +'Regresa el numero de veces que aparece un caracter en la cadena dada. +'Esta funcion la ocupo para reconocer las reglas que dependen de otras (Submenus). +Sub CountChars(text As String, substr As String) As Int + Dim t As String = text.Replace(substr, "") + Return text.Length - t.Length +End Sub + +'Change CheckBox colors +Sub SetButtonTintList(View As View, Disabled As Int, Enabled As Int) + Dim States(2,1) As Int + Dim sd As StateListDrawable 'ignore + States(0, 0) = sd.State_Enabled + States(1, 0) = sd.State_Disabled + Dim Color(2) As Int = Array As Int(Enabled, Disabled) + Dim CSL As JavaObject + CSL.InitializeNewInstance("android.content.res.ColorStateList",Array(States,Color)) + Dim jo As JavaObject + jo.InitializeStatic("android.support.v4.widget.CompoundButtonCompat") + jo.RunMethod("setButtonTintList", Array(View, CSL)) +End Sub + +'Regresa una lista con los nombres de los contactos del telefono. +Sub getContactos As List + Dim cr As ContentResolver + cr.Initialize("cr") + Private PeopleProjection() As String = Array As String("display_name") + Private l As List + l.Initialize + Dim u As Uri + u.Parse("content://com.android.contacts/contacts") + Dim c As Cursor = cr.Query(u, PeopleProjection, "", Null, "display_name") + For i = 0 To c.RowCount - 1 + c.Position = i +' Log($"${c.GetString("display_name")}"$) + l.Add(c.GetString("display_name")) + Next + c.Close + Return l +End Sub + +'Remove duplicates from a list. +'Returns the list without duplicates. +Sub removeListDuplicates(pList As List) As List + If pList = Null Or Not(pList.IsInitialized) Then Return pList + If Starter.logger Then Log(pList) + Dim lstNew As List : lstNew.Initialize + Dim objItem As Object + + For i = 0 To pList.Size - 1 + objItem = pList.Get(i) + If lstNew.IndexOf(objItem) = - 1 Then + lstNew.Add(objItem) + End If + Next + If Starter.logger Then Log(lstNew) + Return lstNew +End Sub + +'Manda un mensaje al número especificado (+52 55 XXXX XXXX) mediante un objeto SBN (StatusBarNotification). +'Es necesario que se haya recibido previamente un mensaje del numero especificado. +Sub mandaWAMsjSBN(numero As String, mensaje As String) 'ignore + If numero = Null Then numero = "+52 55 5419 2439" + Dim tempMap As Map = NotificationService.notisMap2.Get(numero) + If tempMap.IsInitialized Then + Dim t1 As lasNotis = tempMap.Get(numero) + Dim t2 As StatusBarNotification = t1.notif + If t2.IsInitialized Then + NotificationService.rp.reply(t2.Notification, t2.PackageName, mensaje) + CallSubDelayed3(NotificationService, "guardaMsjSalida", t2, mensaje) + End If + Else + ToastMessageShow($"No hay notificaciones de ${numero}"$, False) + End If +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 + +'Manda un mensaje al número especificado (52155XXXXXXXX) mediante un script de shell y root. +'El celular necesita estar rooteado. +'El destinatario debe tener la lada completa sin signos de mas, es decir, para mexico 521 + el numero a 10 digitos. +Sub mandaWAMsjRoot(mensaje As String, destinatario As String) 'ignore + Private waPackage As String = "com.whatsapp" + Dim Command, Runner As String + Dim StdOut, StdErr As StringBuilder + StdOut.Initialize + StdErr.Initialize + Dim Result As Int + Dim Ph As Phone + Private jid As String = $"${destinatario}@s.whatsapp.net"$ + Private key_id As String = $"${DateTime.Now}-1"$ + Private mensaje As String = $"/msjTest ${mensaje} ${DateTime.Time(DateTime.Now)}"$ + Private received_timestamp As String = "0" +' Log(key_id) + +' ******************************************************************************************* +' ******************************************************************************************* +' Hay que revisar que el numero del destinatario exista en la tabla "jid.user" y si no existe, entonces agregarlo: +' user server Agent Type raw_string device +' 5215554192439 s.whatsapp.net 0 0 5215554192439@s.whatsapp.net 0 + +' Hay que agregar en la tabla "chat": +' - el renglon correspondiente de la tabla "jid" (_id) en "jid_row_id". +' - el renglon correspondiente de la tabla "messages" (_id) en "display_message_row_id". +' - y mas columnas ... + + 'Revisamos que exista el numero al que vamos a mandar el mensaje en la tabla "jid". + Private jids As String = hazRootQuery($"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'select _id from jid where user = "${destinatario}" limit 1';"$, "getNumber") +' Log($"|${jids.trim}|"$) + If jids.Trim = "" Then 'Si no existe, entonces lo insertamos. + If Starter.logger Then LogColor("No hay JID, lo insertamos", Colors.Red) + Private sqlInsertJid As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'INSERT INTO jid (user, server, Agent, Type, raw_string, device) VALUES ("${destinatario}", "s.whatsapp.net", 0, 0, "${jid}", 0)';"$ + hazRootQuery(sqlInsertJid, "InsertJid") 'Insertamos el numero en la tabla "jid". + End If + 'Traemos el jid insertado. + Private elJid As String = hazRootQuery($"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'SELECT _id FROM jid where user = "${destinatario}" limit 1';"$, "GetJid") + elJid = elJid.trim +' Log("****** "&elJid) + +' ******************************************************************************************* +' Agregamos el mensaje a la tabla "messages". +' ******************************************************************************************* + Private suCmd As String = $"sqlite3 /data/data/com.whatsapp/databases/msgstore.db 'INSERT INTO messages (key_remote_jid,key_from_me,key_id,status,needs_push,data,timestamp,media_url,media_mime_type,media_wa_type,media_size,media_name,media_hash,latitude,longitude,thumb_image,remote_resource,received_timestamp,send_timestamp,receipt_server_timestamp,receipt_device_timestamp,raw_data,recipient_count,media_duration,origin) VALUES ("${jid}", 1, "${key_id}",0,0,"${mensaje}",${key_id},"","",0,0,"","",0,0,"","",${received_timestamp},-1,-1,-1,"",0,0,0)';"$ + +' Private suCmd As String = $"sqlite3 /data/data/com.gbwhatsapp/databases/msgstore.db 'SELECT _id, key_remote_jid, data FROM messages WHERE data like "Test%"';"$ + Runner = File.Combine(File.DirInternalCache, "runner") + Command = File.Combine(File.DirInternalCache, "command") + File.WriteString(File.DirInternalCache, "runner", "su < " & Command) + File.WriteString(File.DirInternalCache, "command", suCmd & CRLF & "exit") 'Any commands via crlf, and exit at end + Result = Ph.Shell("sh", Array As String(Runner), StdOut, StdErr) +' Log(Result) + If Result = 0 Then ToastMessageShow("Mensaje enviado", False) + + 'Traemos el id del ultimo mensaje de la tabla "messages". + Private lastMsgId As Int = hazRootQuery($"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'SELECT max(_id) FROM messages';"$, "GetLastMsgId") +' Log(lastMsgId) + + 'Revisamos si existe el jid en la tabla "chat". + Private chatJid As String = hazRootQuery($"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'select count(jid_row_id) from chat where jid_row_id = "${elJid}"';"$, "getChatJid") +' Log($"|${chatJid.trim}|"$) + + If chatJid.Trim > 0 Then 'Actualizamos los datos necesarios en la tabla "chat". + Private sqlUpdateChat As String = hazRootQuery($"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'update chat set hidden = 0, display_message_row_id = ${lastMsgId}, last_message_row_id = ${lastMsgId}, last_read_message_row_id = ${lastMsgId}, last_read_receipt_sent_message_row_id = ${(lastMsgId-1)}, last_important_message_row_id = 1, archived = 0, sort_timestamp = ${DateTime.Now} where jid_row_id = ${elJid}';"$, "updateChat") +' Log("Actualizamos en CHAT") + Else 'Insertamos los datos necesarios a la tabla "chat" + Private sqlInsertChat As String = hazRootQuery($"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'insert into chat + (jid_row_id, hidden, display_message_row_id, last_message_row_id, last_read_message_row_id, last_read_receipt_sent_message_row_id, last_important_message_row_id, archived, sort_timestamp, mod_tag, spam_detection, unseen_earliest_message_received_time, unseen_message_count, unseen_missed_calls_count, unseen_row_count, plaintext_disabled, vcard_ui_dismissed, change_number_notified_message_row_id, show_group_description, ephemeral_expiration, ephemeral_setting_timestamp, unseen_important_message_count, ephemeral_disappearing_messages_initiator, group_type, last_message_reaction_row_id, last_seen_message_reaction_row_id, unseen_message_reaction_count, last_read_message_sort_id, display_message_sort_id, last_message_sort_id, last_read_receipt_sent_message_sort_id) + values (${elJid}, 0, ${lastMsgId}, ${lastMsgId}, ${lastMsgId}, ${(lastMsgId-1)}, 1, 0, ${DateTime.Now}, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ${lastMsgId}, ${lastMsgId}, ${lastMsgId}, ${(lastMsgId-1)})';"$, "insertChat") +' Log("Insertamos en CHAT") + End If + + 'Obtenemos el id del ultimo mensaje +' Private suCmd1 As String = $"sqlite3 /data/data/com.whatsapp/databases/msgstore.db 'SELECT max(_id) FROM messages';"$ +' Dim nextId As Int = hazRootQuery(suCmd1, "GetId") +' Log("Last ID="&nextId) +' 'Insertamos un boton +' Private suCmd As String = $"sqlite3 /data/data/com.whatsapp/databases/msgstore.db 'INSERT INTO message_template_button (message_row_id, text_data, extra_data, button_type, used) VALUES ("${nextId}", "Boton de Prueba", "Boton de prueba", 0, 1)';"$ +' hazRootQuery(suCmd, "guardaBoton") + + Private suCmd As String = $"killall com.whatsapp"$ + Runner = File.Combine(File.DirInternalCache, "runner") + Command = File.Combine(File.DirInternalCache, "command") + File.WriteString(File.DirInternalCache, "runner", "su < " & Command) + File.WriteString(File.DirInternalCache, "command", suCmd & CRLF & "exit") 'Any commands via crlf, and exit at end + Result = Ph.Shell("sh", Array As String(Runner), StdOut, StdErr) + If Starter.logger Then Log("Kill WA result : " & Result) + If Starter.logger Then LogColor(StdOut.tostring, Colors.red) + +' hazRootQuery("killall com.whatsapp", "Kill_WA") +End Sub + +'Manda un mensaje con imagen al número especificado (52155XXXXXXXX) mediante un script de shell y root. +'El celular necesita estar rooteado. +Sub mandaWAImageRoot_0(m As String) 'ignore + Starter.waDb.Initialize("/sdcard/", "msgstore_no_enviado.db", True) + Dim waPackage, Command, Runner As String + Dim StdOut, StdErr, StdOut2, StdErr2 As StringBuilder + StdOut.Initialize + StdErr.Initialize + StdOut2.Initialize + StdErr2.Initialize + waPackage = Starter.waPackage + Dim Result As Int + Dim Ph As Phone +' Private suCmd As String = $"sqlite3 /data/data/com.whatsapp/databases/msgstore.db 'SELECT _id, key_remote_jid, data FROM messages WHERE data like "Test%"';"$ + Private jid As String = "5215554192439@s.whatsapp.net" + Private key_id As String = $"${DateTime.Now}-1"$ + Private timeStamp As Int = DateTime.Now +' Private mensaje As String = $"/msjTest ${m} ${DateTime.Time(DateTime.Now)}"$ +' Private received_timestamp As String = "0" + Private keyId As String = "" + If Starter.logger Then Log(key_id) + + Private suCmd3 As String = $"killall ${waPackage}"$ + Runner = File.Combine(File.DirInternalCache, "runner") + Command = File.Combine(File.DirInternalCache, "command") + File.WriteString(File.DirInternalCache, "runner", "su < " & Command) + File.WriteString(File.DirInternalCache, "command", suCmd3 & CRLF & "exit") 'Any commands via crlf, and exit at end + Result = Ph.Shell("sh", Array As String(Runner), StdOut2, StdErr2) + If Starter.logger Then Log(Result) + If Result = 0 Then Log("process killed") + If Starter.logger Then LogColor(StdOut2.tostring, Colors.red) + If Starter.logger Then Log(StdOut2) + If Starter.logger Then LogColor(StdErr2, Colors.Magenta) + + Private suCmd1 As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'Select chat._id as chatId FROM chat JOIN jid ON jid._id = chat.jid_row_id where jid.raw_string = "5215554192439@s.whatsapp.net" limit 1';"$ + Private chatId As String = hazRootQuery(suCmd1, "getChatId") + + Private mediaCaption As String = "Alo Papagena … Tore bella com la papaia" + +' suCmd1 = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'Select messages.* from messages join message_media on messages._id = message_media.message_row_id order by _id desc limit 1';"$ +' Log(hazRootQuery(suCmd1, "GetMsj")) + + Dim c As Cursor = Starter.waDb.ExecQuery("Select messages.* from messages join message_media on messages._id = message_media.message_row_id order by _id desc limit 1") 'El ultimo mensaje que tenga imagen + If c.RowCount > 0 Then + c.Position = 0 + keyId = c.GetString("key_id") + Private suCmd1 As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'INSERT INTO messages (key_remote_jid, key_from_me, key_id, status, needs_push, timestamp, media_wa_type, media_size, media_name, media_caption, media_hash, media_duration,origin, latitude, longitude, received_timestamp, send_timestamp, receipt_server_timestamp, receipt_device_timestamp, recipient_count, quoted_row_id, edit_version, media_enc_hash, forwarded, preview_type, lookup_tables, future_message_type, message_add_on_flags) VALUES ("${jid}", ${c.GetInt("key_from_me")}, "${key_id}", 0, ${c.GetInt("needs_push")}, ${timeStamp}, "${c.GetString("media_wa_type")}", ${c.GetInt("media_size")}, "${c.GetString("media_name")}", "${mediaCaption}", "${c.GetString("media_hash")}", ${c.GetInt("media_duration")}, ${c.GetInt("origin")}, ${c.GetDouble("latitude")}, ${c.GetDouble("longitude")}, ${c.GetInt("received_timestamp")}, ${c.GetInt("send_timestamp")}, -1, -1, ${c.GetInt("recipient_count")}, ${c.GetInt("quoted_row_id")}, ${c.GetInt("edit_version")}, "${c.GetString("media_enc_hash")}", ${c.GetInt("forwarded")}, ${c.GetInt("preview_type")}, ${c.GetInt("lookup_tables")}, ${c.GetInt("future_message_type")}, ${c.GetInt("message_add_on_flags")})';"$ + hazRootQuery(suCmd1, "Messages") 'Insertamos los datos en la tabla "messages". + Private msgId As Int = c.GetInt("_id") + End If + c.Close + + Private suCmd1 As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'SELECT max(_id) FROM messages';"$ + Dim nextId As Int = hazRootQuery(suCmd1, "GetId") + + Dim c As Cursor = Starter.waDb.ExecQuery($"select * from message_media where message_row_id = '${msgId}'"$) + If c.RowCount > 0 Then + c.Position = 0 + Private filePath As String = c.GetString("file_path") + Private suCmd2 As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'insert into message_media (message_row_id, chat_row_id, autotransfer_retry_enabled, media_job_uuid, transferred, transcoded, file_path, file_size, suspicious_content, trim_from, trim_to, face_x, face_y, media_key_timestamp, width, height, has_streaming_sidecar, gif_attribution, thumbnail_height_width_ratio, first_scan_length, file_length, media_name, file_hash, media_duration, page_count, enc_file_hash, is_animated_sticker, mute_video) values (${nextId}, ${chatId}, 1, "${c.getString("media_job_uuid")}", 0, ${c.getInt("transcoded")}, "${filePath}", ${c.getInt("file_size")}, ${c.getInt("suspicious_content")}, ${c.getInt("trim_from")}, ${c.getInt("trim_to")}, ${c.getInt("face_x")}, ${c.getInt("face_y")}, ${c.getInt("media_key_timestamp")}, ${c.getInt("width")}, ${c.getInt("height")}, ${c.getInt("has_streaming_sidecar")}, ${c.getInt("gif_attribution")}, ${c.GetDouble("thumbnail_height_width_ratio")}, ${c.getInt("first_scan_length")}, ${c.getInt("file_length")}, "${c.getString("media_name")}", "${c.getString("file_hash")}", ${c.getInt("media_duration")}, ${c.getInt("page_count")}, "${c.getString("enc_file_hash")}", ${c.getInt("is_animated_sticker")}, ${c.getInt("mute_video")})';"$ + If Starter.logger Then Log(hazRootQuery(suCmd2, "MsgMedia")) +' If Result = 0 Then Log("inserted --> message_media") + End If + c.Close + +' Log($"readfile(${filePath}), ${timeStamp}, ${jid}, 1, ${keyId}"$) + Private suCmd2 As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'insert into message_thumbnails (thumbnail, timestamp, key_remote_jid, key_from_me, key_id) values (readfile("${filePath}"), ${timeStamp}, "${jid}", 1, "${key_id}")';"$ + If Starter.logger Then Log(hazRootQuery(suCmd2, "msgThumbnails")) +End Sub + +Sub hazRootQuery(qryStr As String, name As String) As StringBuilder +' Starter.waDb.Initialize("/sdcard/", "msgstore_no_enviado.db", True) + Dim Command, Runner As String + Dim StdOut, StdErr As StringBuilder + StdOut.Initialize + StdErr.Initialize + Dim Result As Int + Dim Ph As Phone + Runner = File.Combine(File.DirInternalCache, "runner") + Command = File.Combine(File.DirInternalCache, "command") + File.WriteString(File.DirInternalCache, "runner", "su < " & Command) + File.WriteString(File.DirInternalCache, "command", qryStr & CRLF & "exit") 'Any commands via crlf, and exit at end + Result = Ph.Shell("sh", Array As String(Runner), StdOut, StdErr) +' Log(name&" "&"Res="&Result) +' Log(StdOut) + If Starter.logger Then LogColor(StdErr, Colors.red) + If StdErr.Length > 1 Then LogColor(qryStr, Colors.Blue) + Return StdOut +End Sub + +Sub copyWADB 'ignore + Dim waPackage, Command, Runner As String + Dim StdOut, StdErr As StringBuilder + StdOut.Initialize + StdErr.Initialize + waPackage = Starter.waPackage + Dim Result As Int + Dim Ph As Phone + + Private suCmd3 As String = $"killall ${waPackage}"$ + Runner = File.Combine(File.DirInternalCache, "runner") + Command = File.Combine(File.DirInternalCache, "command") + File.WriteString(File.DirInternalCache, "runner", "su < " & Command) + File.WriteString(File.DirInternalCache, "command", suCmd3 & CRLF & "exit") 'Any commands via crlf, and exit at end + Result = Ph.Shell("sh", Array As String(Runner), StdOut, StdErr) + If Starter.logger Then Log(Result) + If Result = 0 Then Log("process killed") + If Starter.logger Then LogColor(StdOut.tostring, Colors.red) + If Starter.logger Then Log(StdOut) + If Starter.logger Then LogColor(StdErr, Colors.Magenta) + + Private suCmd As String = $"sqlite3 /data/user/0/${waPackage}/databases/msgstore.db 'PRAGMA wal_checkpoint;' + cp /data/data/${waPackage}/databases/msgstore.db /sdcard/msgstore.db"$ + If Starter.logger Then LogColor(suCmd, Colors.Blue) + Runner = File.Combine(File.DirInternalCache, "runner") + Command = File.Combine(File.DirInternalCache, "command") + File.WriteString(File.DirInternalCache, "runner", "su < " & Command) + File.WriteString(File.DirInternalCache, "command", suCmd & CRLF & "exit") 'Any commands via crlf, and exit at end + Result = Ph.Shell("sh", Array As String(Runner), StdOut, StdErr) + If Starter.logger Then Log(Result) + If Starter.logger Then Log(StdOut) + If Starter.logger Then LogColor(StdErr, Colors.Magenta) + If Result = 0 Then Log("copied db") +End Sub + +'Regresa una lista de mapas con los datos con los ultimos mensajes con imagen enviados. +'Con este mapa se puede generar un nuevo mensaje con imagen. +Sub traeImgMsjData As List + Private regs As List + regs.Initialize + Private sqlSync As String = $"sqlite3 /data/user/0/${Starter.waPackage}/databases/msgstore.db 'PRAGMA wal_checkpoint;'"$ + Private sync As String = hazRootQuery(sqlSync, "syncDB") 'Guardamos los datos en la DB 'ignore +' Private suCmd2 As String = $"sqlite3 /data/data/${Starter.waPackage}/databases/msgstore.db 'select * from messages join message_media on message_row_id = _id limit 20';"$ + Private suCmd2 As String = $"sqlite3 /data/data/${Starter.waPackage}/databases/msgstore.db 'select _id, key_remote_jid, key_from_me, key_id, status, needs_push, timestamp, media_url, media_mime_type, media_wa_type, media_size, messages.media_name, media_caption, media_hash, messages.media_duration, origin, latitude, longitude, remote_resource, received_timestamp, send_timestamp, receipt_server_timestamp, receipt_device_timestamp, read_device_timestamp, played_device_timestamp, raw_data, recipient_count, participant_hash, starred, quoted_row_id, mentioned_jids, messages.multicast_id, edit_version, media_enc_hash, payment_transaction_id, forwarded, preview_type, send_count, lookup_tables, future_message_type, message_add_on_flags, message_row_id, chat_row_id, autotransfer_retry_enabled, message_media.multicast_id, media_job_uuid, transferred, transcoded, file_path, file_size, suspicious_content, trim_from, trim_to, face_x, face_y, media_key_timestamp, width, height, has_streaming_sidecar, gif_attribution, thumbnail_height_width_ratio, direct_path, first_scan_sidecar, first_scan_length, message_url, mime_type, file_length, message_media.media_name, file_hash, message_media.media_duration, page_count, enc_file_hash, partial_media_hash, partial_media_enc_hash, is_animated_sticker, original_file_hash, mute_video from messages join message_media on message_row_id = _id limit 20';"$ + Private tempData As String = hazRootQuery(suCmd2, "traeImgMsjData").As(StringBuilder).ToString + Private renglon() As String = Regex.Split(CRLF, tempData) +' Log("======= _"&renglon.Length&"_|"&tempData) + For i = 0 To renglon.Length -1 +' LogColor($"i=${i}, ${renglon(i)}"$, Colors.Blue) + Private columna() As String = Regex.Split("\|", renglon(i)) +' For col = 0 To columna.Length - 1 +' Log($"col=${col}, ${columna(col)}"$) +' Next + If columna.Length > 47 Then + Private theDir As String = Starter.waDir & "/" &columna(48) +' Log(theDir) + If theDir.EndsWith("jpg") Or theDir.EndsWith("png") Then + If File.Exists(theDir.SubString2(0, theDir.LastIndexOf("/")+1), theDir.SubString(theDir.LastIndexOf("/")+1)) Then + Private msjData As Map = CreateMap("_id":columna(0), "key_remote_jid":columna(1), "key_from_me":columna(2), "key_id":columna(3), "status":columna(4), "needs_push":columna(5), "timestamp":columna(6), "media_url":columna(7), "media_mime_type":columna(8), "media_wa_type":columna(9), "media_size":columna(10), "media_name":columna(11), "media_caption":columna(12), "media_hash":columna(13), "media_duration":columna(14), "origin":columna(15), "latitude":columna(16), "longitude":columna(17), "remote_resource":columna(18), "received_timestamp":columna(19), "send_timestamp":columna(20), "receipt_server_timestamp":columna(21), "receipt_device_timestamp":columna(22), "read_device_timestamp":columna(23), "played_device_timestamp":columna(24), "raw_data":columna(25), "recipient_count":columna(26), "participant_hash":columna(27), "starred":columna(28), "quoted_row_id":columna(29), "mentioned_jids":columna(30), "multicast_id":columna(31), "edit_version":columna(32), "media_enc_hash":columna(33), "payment_transaction_id":columna(34), "forwarded":columna(35), "preview_type":columna(36), "send_count":columna(37), "lookup_tables":columna(38), "future_message_type":columna(39), "message_add_on_flags":columna(40)) + Private imgData As Map = CreateMap("message_row_id":columna(41), "chat_row_id":columna(42), "autotransfer_retry_enabled":columna(43), "multicast_id":columna(44), "media_job_uuid":columna(45), "transferred":columna(46), "transcoded":columna(47), "file_path":columna(48), "file_size":columna(49), "suspicious_content":columna(50), "trim_from":columna(51), "trim_to":columna(52), "face_x":columna(53), "face_y":columna(54), "media_key_timestamp":columna(55), "width":columna(56), "height":columna(57), "has_streaming_sidecar":columna(58), "gif_attribution":columna(59), "thumbnail_height_width_ratio":columna(60), "direct_path":columna(61), "first_scan_sidecar":columna(62), "first_scan_length":columna(63), "message_url":columna(64), "mime_type":columna(65), "file_length":columna(66), "media_name":columna(67), "file_hash":columna(68), "media_duration":columna(69), "page_count":columna(70), "enc_file_hash":columna(71), "partial_media_hash":columna(72), "partial_media_enc_hash":columna(73), "is_animated_sticker":columna(74), "original_file_hash":columna(75), "mute_video":columna(76)) + Private thisReg As Map = CreateMap("msjData":msjData, "imgData":imgData) +' LogColor("Agregamos registro "& i, Colors.Magenta) + regs.Add(thisReg) + End If + End If + End If + Next +' Log(regs) +' Log("Registros="®s.Size) +' For x = 0 To regs.Size-1 +' Log(regs.Get(x)) +' Next + Return regs +End Sub + +'Manda un mensaje con imagen al número especificado (52155XXXXXXXX) mediante un script de shell y root. +'El celular necesita estar rooteado. +Sub mandaWAImageRoot(jid As String, texto As String, msjMap As Map) 'ignore + Starter.waDb.Initialize("/sdcard/", "msgstore_no_enviado.db", True) + jid = "5215554192439@s.whatsapp.net" + Private mediaCaption As String = "Alo Papagena … Tore bella com la papaia" + Private filePath As String = "/storage/F3DF-3FB8/Bow2.0/qr.jpg" + If texto <> "" And texto <> Null Then mediaCaption = texto + Dim waPackage As String = Starter.waPackage + Private key_id As String = $"${DateTime.Now}-1"$ + Private timeStamp As String = DateTime.Now + Private keyId As String = "" + If Starter.logger Then Log($"jid=${jid}, timeStamp=${timeStamp}, key_Id=${key_id}, now=${DateTime.Now}"$) + If Starter.logger Then LogColor(msjMap, Colors.Blue) + '============================== Kill Process ============================== + Private killWA As String = hazRootQuery($"killall ${waPackage}"$, "killWA") 'Matamos el proceso de WA 'ignore + '============================================================ + Private sqlGetChatId As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'Select chat._id as chatId FROM chat JOIN jid ON jid._id = chat.jid_row_id where jid.raw_string = "${jid}" limit 1';"$ + Private chatId As String = hazRootQuery(sqlGetChatId, "getChatId") 'Obtenenos el ID del chat del JID proporcionado. + +' Dim c As Cursor = Starter.waDb.ExecQuery("Select messages.* from messages join message_media on messages._id = message_media.message_row_id order by _id desc limit 1") 'El ultimo mensaje que tenga imagen +' If c.RowCount > 0 Then +' c.Position = 0 + '=============================== Insert into Messages ============================== + Private msjInfo As Map = msjMap.Get("msjData") + keyId = msjInfo.Get("key_id") + Private sqlInsertMsg As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'INSERT INTO messages (key_remote_jid, key_from_me, key_id, status, needs_push, timestamp, media_wa_type, media_size, media_name, media_caption, media_hash, media_duration, origin, latitude, longitude, received_timestamp, send_timestamp, receipt_server_timestamp, receipt_device_timestamp, recipient_count, quoted_row_id, edit_version, media_enc_hash, forwarded, preview_type, lookup_tables, future_message_type, message_add_on_flags) VALUES ("${jid}", ${msjInfo.Get("key_from_me")}, "${key_id}", 0, ${msjInfo.Get("needs_push")}, ${timeStamp}, "${msjInfo.Get("media_wa_type")}", ${msjInfo.Get("media_size")}, "${msjInfo.Get("media_name")}", "${mediaCaption}", "${msjInfo.Get("media_hash")}", ${msjInfo.Get("media_duration")}, ${msjInfo.Get("origin")}, ${msjInfo.Get("latitude")}, ${msjInfo.Get("longitude")}, ${msjInfo.Get("received_timestamp")}, ${msjInfo.Get("send_timestamp")}, -1, -1, ${msjInfo.Get("recipient_count")}, ${msjInfo.Get("quoted_row_id")}, ${msjInfo.Get("edit_version")}, "${msjInfo.Get("media_enc_hash")}", ${msjInfo.Get("forwarded")}, ${msjInfo.Get("preview_type")}, ${msjInfo.Get("lookup_tables")}, ${msjInfo.Get("future_message_type")}, ${msjInfo.Get("message_add_on_flags")})';"$ + If Starter.logger Then LogColor(sqlInsertMsg, Colors.Magenta) + hazRootQuery(sqlInsertMsg, "InsertMessage") 'Insertamos los datos en la tabla "messages". +' Private msgId As Int = msjInfo.Get("_id") +' End If +' c.Close + '=============================== Get last Id ============================= + Private sqlGetLastMsgId As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'SELECT max(_id) FROM messages';"$ + Dim nextId As Int = hazRootQuery(sqlGetLastMsgId, "GetLastId") + Starter.reglasDB.ExecNonQuery($"INSERT INTO datosMsj (_id, key_remote_jid, key_from_me, key_id, status, needs_push, timestamp, media_wa_type, media_size, media_name, media_caption, media_hash, media_duration, origin, latitude, longitude, received_timestamp, send_timestamp, receipt_server_timestamp, receipt_device_timestamp, recipient_count, quoted_row_id, edit_version, media_enc_hash, forwarded, preview_type, lookup_tables, future_message_type, message_add_on_flags) VALUES ("${nextId}", "${jid}", ${msjInfo.Get("key_from_me")}, "${key_id}", 0, ${msjInfo.Get("needs_push")}, ${timeStamp}, "${msjInfo.Get("media_wa_type")}", ${msjInfo.Get("media_size")}, "${msjInfo.Get("media_name")}", "${mediaCaption}", "${msjInfo.Get("media_hash")}", ${msjInfo.Get("media_duration")}, ${msjInfo.Get("origin")}, ${msjInfo.Get("latitude")}, ${msjInfo.Get("longitude")}, ${msjInfo.Get("received_timestamp")}, ${msjInfo.Get("send_timestamp")}, -1, -1, ${msjInfo.Get("recipient_count")}, ${msjInfo.Get("quoted_row_id")}, ${msjInfo.Get("edit_version")}, "${msjInfo.Get("media_enc_hash")}", ${msjInfo.Get("forwarded")}, ${msjInfo.Get("preview_type")}, ${msjInfo.Get("lookup_tables")}, ${msjInfo.Get("future_message_type")}, ${msjInfo.Get("message_add_on_flags")})"$) + +' Dim c As Cursor = Starter.waDb.ExecQuery($"select * from message_media where message_row_id = '${msgId}'"$) +' If c.RowCount > 0 Then +' c.Position = 0 + '=============================== Insert into message_media ============================ + Private imgInfo As Map = msjMap.Get("imgData") + + Private theDir As String = Starter.waDir & "/" & imgInfo.get("file_path") + If Starter.logger Then Log("file_path="&imgInfo.get("file_path")) + If Starter.logger Then Log($"ImgDir=${theDir}"$) + If File.Exists(theDir.SubString2(0, theDir.LastIndexOf("/")+1), theDir.SubString(theDir.LastIndexOf("/")+1)) Then + File.Copy(theDir.SubString2(0, theDir.LastIndexOf("/")+1), theDir.SubString(theDir.LastIndexOf("/")+1), "/sdcard/Bow2.0/", theDir.SubString(theDir.LastIndexOf("/")+1)) + filePath = "/sdcard/Bow2.0/" & theDir.SubString(theDir.LastIndexOf("/")+1) + End If + If Starter.logger Then LogColor($"filePath=${filePath}"$, Colors.Magenta) + Private sqlInsertMedia As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'insert into message_media (message_row_id, chat_row_id, autotransfer_retry_enabled, media_job_uuid, transferred, transcoded, file_path, file_size, suspicious_content, trim_from, trim_to, face_x, face_y, media_key_timestamp, width, height, has_streaming_sidecar, gif_attribution, thumbnail_height_width_ratio, first_scan_length, file_length, media_name, file_hash, media_duration, page_count, enc_file_hash, is_animated_sticker, mute_video) values (${nextId}, ${chatId}, 1, "abcd${imgInfo.get("media_job_uuid").As(String).SubString(4)}", 0, ${imgInfo.get("transcoded")}, "${filePath}", ${imgInfo.get("file_size")}, ${imgInfo.get("suspicious_content")}, ${imgInfo.get("trim_from")}, ${imgInfo.get("trim_to")}, ${imgInfo.get("face_x")}, ${imgInfo.get("face_y")}, ${imgInfo.get("media_key_timestamp")}, ${imgInfo.get("width")}, ${imgInfo.get("height")}, ${imgInfo.get("has_streaming_sidecar")}, ${imgInfo.get("gif_attribution")}, ${imgInfo.get("thumbnail_height_width_ratio")}, ${imgInfo.get("first_scan_length")}, ${imgInfo.get("file_length")}, "${imgInfo.get("media_name")}", "${imgInfo.get("file_hash")}", ${imgInfo.get("media_duration")}, ${imgInfo.get("page_count")}, "${imgInfo.get("enc_file_hash")}", ${imgInfo.get("is_animated_sticker")}, ${imgInfo.get("mute_video")})';"$ + If Starter.logger Then LogColor(sqlInsertMedia, Colors.Magenta) + If Starter.logger Then Log(hazRootQuery(sqlInsertMedia, "MsgMedia")) + Starter.reglasDB.ExecNonQuery($"insert into datosImg (message_row_id, chat_row_id, autotransfer_retry_enabled, media_job_uuid, transferred, transcoded, file_path, file_size, suspicious_content, trim_from, trim_to, face_x, face_y, media_key_timestamp, width, height, has_streaming_sidecar, gif_attribution, thumbnail_height_width_ratio, first_scan_length, file_length, media_name, file_hash, media_duration, page_count, enc_file_hash, is_animated_sticker, mute_video) values (${nextId}, ${chatId}, 1, "abcd${imgInfo.get("media_job_uuid").As(String).SubString(4)}", 0, ${imgInfo.get("transcoded")}, "${filePath}", ${imgInfo.get("file_size")}, ${imgInfo.get("suspicious_content")}, ${imgInfo.get("trim_from")}, ${imgInfo.get("trim_to")}, ${imgInfo.get("face_x")}, ${imgInfo.get("face_y")}, ${imgInfo.get("media_key_timestamp")}, ${imgInfo.get("width")}, ${imgInfo.get("height")}, ${imgInfo.get("has_streaming_sidecar")}, ${imgInfo.get("gif_attribution")}, ${imgInfo.get("thumbnail_height_width_ratio")}, ${imgInfo.get("first_scan_length")}, ${imgInfo.get("file_length")}, "${imgInfo.get("media_name")}", "${imgInfo.get("file_hash")}", ${imgInfo.get("media_duration")}, ${imgInfo.get("page_count")}, "${imgInfo.get("enc_file_hash")}", ${imgInfo.get("is_animated_sticker")}, ${imgInfo.get("mute_video")})"$) +' If Result = 0 Then Log("inserted --> message_media") +' End If +' c.Close + '=============================== Insert into message_thumbnails ============================ + Private sqlInsertThumb As String = $"sqlite3 /data/data/${waPackage}/databases/msgstore.db 'insert into message_thumbnails (thumbnail, timestamp, key_remote_jid, key_from_me, key_id) values (readfile("${filePath}"), ${timeStamp}, "${jid}", 1, "${key_id}")';"$ + If Starter.logger Then LogColor(sqlInsertThumb, Colors.Magenta) + If Starter.logger Then Log(hazRootQuery(sqlInsertThumb, "msgThumbnails")) +End Sub \ No newline at end of file diff --git a/B4A/cvFloatingBtn.bas b/B4A/cvFloatingBtn.bas new file mode 100644 index 0000000..fb1f7be --- /dev/null +++ b/B4A/cvFloatingBtn.bas @@ -0,0 +1,89 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Class +Version=10.5 +@EndOfDesignText@ +'Custom View class +#Event: ExampleEvent (Value As Int) +'#DesignerProperty: Key: Width, DisplayName: Width, FieldType: int, DefaultValue: 55, Description: Width of button. +'#DesignerProperty: Key: Height, DisplayName: Height, FieldType: int, DefaultValue: 55, Description: Height of button. +#DesignerProperty: Key: ImageFile, DisplayName: Image File, FieldType: String, DefaultValue: , Description: Image for button. +'#DesignerProperty: Key: BooleanExample, DisplayName: Boolean Example, FieldType: Boolean, DefaultValue: True, Description: Example of a boolean property. +'#DesignerProperty: Key: IntExample, DisplayName: Int Example, FieldType: Int, DefaultValue: 10, MinRange: 0, MaxRange: 100, Description: Note that MinRange and MaxRange are optional. +'#DesignerProperty: Key: StringWithListExample, DisplayName: String With List, FieldType: String, DefaultValue: Sunday, List: Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday +'#DesignerProperty: Key: StringExample, DisplayName: String Example, FieldType: String, DefaultValue: Text +'#DesignerProperty: Key: ColorExample, DisplayName: Color Example, FieldType: Color, DefaultValue: 0xFFCFDCDC, Description: You can use the built-in color picker to find the color values. +'#DesignerProperty: Key: DefaultColorExample, DisplayName: Default Color Example, FieldType: Color, DefaultValue: Null, Description: Setting the default value to Null means that a nullable field will be displayed. +Sub Class_Globals + Private mEventName As String 'ignore + Private mCallBack As Object 'ignore + Private mBase As Panel + Private Const DefaultColorConstant As Int = -984833 'ignore + Private Const ACTION_DOWN=0,ACTION_UP=1 As Int + Private downx, downy As Float 'ignore + Private S1,S2,Diff As Long +End Sub + +Public Sub Initialize (Callback As Object, EventName As String) + mEventName = EventName + mCallBack = Callback +End Sub + +Public Sub DesignerCreateView (Base As Panel, Lbl As Label, Props As Map) + mBase = Base + Private ImgFl As String + ImgFl = Props.Get("ImageFile") + + If ImgFl <> "" Then mBase.SetBackgroundImage(LoadBitmap(File.DirAssets,ImgFl)) + + SetOnTouchListener(mBase) +End Sub + +Public Sub GetBase As Panel + Return mBase +End Sub + +Public Sub setLeft(Left As Int) + mBase.Left = Left +End Sub + +Public Sub setTop(Top As Int) + mBase.Top = Top +End Sub + +Public Sub setVisible(Flag As Boolean) + mBase.Visible = Flag +End Sub + +Private Sub SetOnTouchListener(MyView As View) + Dim ref As Reflector + ref.Target = MyView + ref.SetOnTouchListener("Panel_Touch") +End Sub + +Private Sub Panel_Touch(ViewTag As Object, Action As Int, X As Float, Y As Float, MotionEvent As Object) As Boolean + If Action = ACTION_DOWN Then + downx = x + downy = y + S1 = DateTime.Now + else If Action = ACTION_UP Then + S2 = DateTime.Now + Diff = S2 - S1 + If Diff <= 199 Then + If SubExists(mCallBack,mEventName.Trim & "_Clicked") Then CallSub3(mCallBack,mEventName.Trim & "_Clicked",X,Y) + End If + Else +' Log(mBase.left& " + " & x & " - " & downx) + If mBase.Left >= 14 And mBase.Left <= 900 Then mBase.Left = mBase.Left + x - downx + If mBase.Left < 14 And (X-downx) > 0 Then mBase.Left = mBase.Left + x - downx +' If mBase.Left < 900 Then mBase.Left = mBase.Left + x - downx + If mBase.Left > 900 And (X-downx) < 0 Then mBase.Left = mBase.Left + x - downx +' mBase.Top = mBase.Top + y - downy + mBase.Left = mBase.Left + If mBase.Left < 10 Then mBase.Left = 14 'ignore + If mBase.Left > 910 Then mBase.Left = 900 'ignore +' mBase.Top = mBase.Top + End If + Return True +End Sub \ No newline at end of file diff --git a/B4A/reglas.bas b/B4A/reglas.bas new file mode 100644 index 0000000..f737359 --- /dev/null +++ b/B4A/reglas.bas @@ -0,0 +1,13 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=StaticCode +Version=11.45 +@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. + +End Sub \ No newline at end of file diff --git a/B4A/startWA.bas b/B4A/startWA.bas new file mode 100644 index 0000000..78e0ab2 --- /dev/null +++ b/B4A/startWA.bas @@ -0,0 +1,44 @@ +B4A=true +Group=Default Group +ModulesStructureVersion=1 +Type=Activity +Version=11.5 +@EndOfDesignText@ +#Region Activity Attributes + #FullScreen: False + #IncludeTitle: 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. + Dim OldIntent As Intent +End Sub + +Sub Globals + 'These global variables will be redeclared each time the activity is created. + 'These variables can only be accessed from this module. + +End Sub + +Sub Activity_Create(FirstTime As Boolean) + 'Do not forget to load the layout file created with the visual designer. For example: + 'Activity.LoadLayout("Layout1") + +End Sub + +Sub Activity_Resume + Dim in As Intent = B4XPages.GetNativeParent(Me).GetStartingIntent + If in.IsInitialized And in <> OldIntent Then + OldIntent = in + If in.HasExtra("Notification_Tag") Then + Log("Activity started from notification. Tag: " & in.GetExtra("Notification_Tag")) + Starter.historicoDB.ExecNonQuery2("update historico set clic = 1 where clic = 0 and nombre = ?", Array As Object(in.GetExtra("Notification_Tag"))) 'Ponemos en 1 las notificacion a las que ya se les dió clic. + Subs.abreWAChat(in.GetExtra("Notification_Tag")) + End If + End If +End Sub + +Sub Activity_Pause (UserClosed As Boolean) + +End Sub diff --git a/B4i/B4iProject.b4i b/B4i/B4iProject.b4i new file mode 100644 index 0000000..89d3164 --- /dev/null +++ b/B4i/B4iProject.b4i @@ -0,0 +1,53 @@ +Build1=Default,b4i.example2 +File1=Login.bil +File2=Page2.bil +File3=Page3.bil +FileGroup1=Default Group +FileGroup2=Default Group +FileGroup3=Default Group +Group=Default Group +Library1=icore +Library2=b4xpages +Library3=xui views +Module1=|relative|..\B4XMainPage +Module2=|relative|..\B4XPage2 +Module3=|relative|..\B4XPage3 +NumberOfFiles=3 +NumberOfLibraries=3 +NumberOfModules=3 +Version=6.5 +@EndOfDesignText@ +'Code module +#Region Project Attributes + #ApplicationLabel: B4i Example + #Version: 1.0.0 + 'Orientation possible values: Portrait, LandscapeLeft, LandscapeRight and PortraitUpsideDown + #iPhoneOrientations: Portrait, LandscapeLeft, LandscapeRight + #iPadOrientations: Portrait, LandscapeLeft, LandscapeRight, PortraitUpsideDown + #Target: iPhone, iPad + #ATSEnabled: True + #MinVersion: 8 +#End Region + +Sub Process_Globals + Public App As Application + Public NavControl As NavigationController + +End Sub + +Private Sub Application_Start (Nav As NavigationController) + NavControl = Nav + Dim PagesManager As B4XPagesManager + PagesManager.Initialize(NavControl) +End Sub + +'Template version: B4i-1.0 +#Region Delegates +Private Sub Application_Background + B4XPages.Delegate.Activity_Pause +End Sub + +Private Sub Application_Foreground + B4XPages.Delegate.Activity_Resume +End Sub +#End Region diff --git a/B4i/B4iProject.b4i.meta b/B4i/B4iProject.b4i.meta new file mode 100644 index 0000000..8e4f7f7 --- /dev/null +++ b/B4i/B4iProject.b4i.meta @@ -0,0 +1,15 @@ +ModuleBookmarks0= +ModuleBookmarks1= +ModuleBookmarks2= +ModuleBookmarks3= +ModuleBreakpoints0= +ModuleBreakpoints1= +ModuleBreakpoints2= +ModuleBreakpoints3= +ModuleClosedNodes0=1 +ModuleClosedNodes1= +ModuleClosedNodes2= +ModuleClosedNodes3= +NavigationStack=B4XPage2,B4XPage_Appear,22,0,B4XMainPage,Class_Globals,0,0,B4XMainPage,txtUser_TextChanged,36,0,B4XMainPage,txtUser_EnterPressed,37,6,B4XPage2,btnSignOut_Click,39,1,Main,Application_Background,25,0,Main,Application_Foreground,34,0,B4XPage3,Class_Globals,0,0,B4XPage3,Panel1_Touch,27,0,Visual Designer,Page3.bil,-100,3,B4XPage3,B4XPage_Created,14,0 +SelectedBuild=0 +VisibleModules=1,2,3 diff --git a/B4i/Files/Special/B4X_FontAwesome.otf b/B4i/Files/Special/B4X_FontAwesome.otf new file mode 100644 index 0000000..401ec0f Binary files /dev/null and b/B4i/Files/Special/B4X_FontAwesome.otf differ diff --git a/B4i/Files/Special/B4X_MaterialIcons.ttf b/B4i/Files/Special/B4X_MaterialIcons.ttf new file mode 100644 index 0000000..7015564 Binary files /dev/null and b/B4i/Files/Special/B4X_MaterialIcons.ttf differ diff --git a/B4i/Files/login.bil b/B4i/Files/login.bil new file mode 100644 index 0000000..17f5d0f Binary files /dev/null and b/B4i/Files/login.bil differ diff --git a/B4i/Files/page2.bil b/B4i/Files/page2.bil new file mode 100644 index 0000000..057f4da Binary files /dev/null and b/B4i/Files/page2.bil differ diff --git a/B4i/Files/page3.bil b/B4i/Files/page3.bil new file mode 100644 index 0000000..f532483 Binary files /dev/null and b/B4i/Files/page3.bil differ diff --git a/ReplyAuto.lnk b/ReplyAuto.lnk new file mode 100644 index 0000000..ec858eb Binary files /dev/null and b/ReplyAuto.lnk differ diff --git a/gitpull.bat b/gitpull.bat new file mode 100644 index 0000000..d0aed61 --- /dev/null +++ b/gitpull.bat @@ -0,0 +1 @@ +git pull