Android Question MQTT Chat with Auto Discovery, rewrittn for [B4XPages] , works ok , but questions


Licensed User
Longtime User
[B4XPages] MQTT Chat with Auto Discovery, only one "XPage" , need improvement

I have rewritten the (2017) example: MQTT Chat with Auto Discovery:

for B4XPages ;

In B4XMainPage it only needs 4 lines to be inserted. Code is in one module PageMqtt , plus Layouts ; So I can easily use it in other projects

zip: [B4XPages] MQTT Chat with Auto Discovery

Client and server can be started, message ok.
But there are Activity Sub s , from 2017 example, that probably do not fit [B4XPages]

So I have a couple of toDo and questions, how to improve that for B4XPages:

in my [PageMqtt]

1. Sub client_MessageArrived
line: 250
line: 267
'this will start the chat activity if it wasn't started yet.

- how I change Layout? for that I added a ALL layout with Layout 1 and 2 in it

2. Sub Activity_KeyPress
line: 133

- do not work?

3. Sub s
98: Activity_Resume
145: Activity_Pause

- need to rewrite?

4. Disconnect
line 150: StartActivity(Main)

- and change Layout - but I do not have Activities

5. Disconnected
line 179: Activity.Finish

- no have - need to rewrite?

Sub Class_Globals
    Private Root As B4XView 'ignore
    Private xui As XUI 'ignore

    Private btnClient As Button
    Private btnStartServer As Button
    Private txtName As FloatLabeledEditText

    'copy from Chat Activity
    Private txtMessage As EditText
    Private lstUsers As ListView
    Private txtLogs As EditText
    Private ime As IME
    Private users As List

    'copy from Starter
    Private broker As MqttBroker
    Private client As MqttClient
    Private const port As Int = 51042
    'Private const port As Int = 9001
    Private const discoverPort As Int = 51049
    Private serializator As B4XSerializator
    Public connected As Boolean
    Private brokerStarted As Boolean
    Private users As List
    Public isServer As Boolean
    Public Name As String  'original:  Starter.Name
    Public DiscoveredServer As String
    Private autodiscover As UDPSocket
    Private BroadcastTimer As Timer
    Private server As ServerSocket 'ignore
End Sub

Sub Globals

End Sub

'You can add more parameters here.
Public Sub Initialize As Object
    'from Starter
    broker.Initialize("", port)
    broker.DebugLog = False
    autodiscover.Initialize("autodiscover",discoverPort , 8192)

    'B4XPages default
    BroadcastTimer.Initialize("BroadcastTimer", 1000)
    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

    'from Chat
    If users.IsInitialized Then NewUsers(users)
    lstUsers.SingleLineLayout.Label.TextSize = 12
    'B4XPage_Created is called once 'If FirstTime Then
    txtLogs.Text = "" 'don't restore old logs
    'End If
End Sub

'You can see the list of page related events in the B4XPagesManager object.
'The event name is B4XPage.

'copy from Main Activity
Sub Activity_Resume
    Log(" Sub Activity_Resume")

End Sub

Sub btnStartServer_Click
    '''here in Page'  CallSub2(Starter, "Connect", True)
    Connect( True)
End Sub

Sub btnClient_Click
    '''CallSub2(Starter, "Connect", False)
    Connect( False)
End Sub

Private Sub UpdateState
    btnStartServer.Enabled =  Name <> ""
    btnClient.Enabled =  Name <> "" And  DiscoveredServer <> ""
End Sub

Sub txtName_TextChanged (Old As String, New As String)
    '''original:  Starter.Name = New
    Name = New
End Sub

'copy from Activity Chat
Sub ime_HeightChanged (NewHeight As Int, OldHeight As Int)
    lstUsers.Height = NewHeight - lstUsers.Top
    txtLogs.Height = NewHeight - txtLogs.Top
End Sub

''''do not work???
Sub Activity_KeyPress (KeyCode As Int) As Boolean 'Return True to consume the event
    If KeyCode = KeyCodes.KEYCODE_BACK Then
        If isServer Then
            If Msgbox2("The broker will be closed. Continue?", "", "Yes", "Cancel", "No", Null) <> DialogResponse.POSITIVE Then
                Return True
            End If
        End If
    End If
    Return False
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    Log("PageMqtt Activity_Pause")
    If UserClosed Then
        '''CallSubDelayed(Starter, "Disconnect")
        ''''what to do???  StartActivity(Main)  ''''changeLayout  qq66yy
    End If
End Sub

Sub ime_HandleAction As Boolean
    Return True 'leave the keyboard open
End Sub

Public Sub NewMessage(msg As Message)
    txtLogs.Text = $"${msg.From}: ${msg.Body}"$ & CRLF & txtLogs.Text
End Sub

Public Sub NewUsers(Users1 As List)
    users = Users1
    For Each u As String In users
End Sub

Sub btnSend_Click
    'original:  If txtMessage.Text <> "" Then CallSub2(Starter, "SendMessage", txtMessage.Text)
    If txtMessage.Text <> "" Then SendMessage(txtMessage.Text)
End Sub

Public Sub Disconnected
    ''''what to do???  Activity.Finish
End Sub

'copy from Starter
Private Sub BroadcastTimer_Tick
    Dim address As String = GetBroadcastAddress
    If address <> "" Then
        Dim up As UDPPacket
        up.Initialize(serializator.ConvertObjectToBytes(server.GetMyWifiIP), address, discoverPort)
    End If
End Sub

Private Sub AutoDiscover_PacketArrived (Packet As UDPPacket)
        Dim bc As ByteConverter
        Dim data(Packet.Length) As Byte
        bc.ArrayCopy(Packet.Data, Packet.Offset, data, 0, Packet.Length)
        Dim ds As String = serializator.ConvertBytesToObject(data)
        If ds <> DiscoveredServer Then
            DiscoveredServer = ds
            Log("Discovered server: " & DiscoveredServer)
            '''original:  CallSub(Main, "UpdateState")
        End If
    End Try
End Sub

Sub Service_Start (StartingIntent As Intent)

End Sub

Public Sub Connect (AsServer As Boolean)
    Dim host As String = DiscoveredServer
    isServer = AsServer
    If isServer Then
        If brokerStarted = False Then
            brokerStarted = True
        End If
        host = ""
    End If
    BroadcastTimer.Enabled = isServer
    If connected Then client.Close

    client.Initialize("client", $"tcp://${host}:${port}"$, "android" & Rnd(1, 10000000))
    Dim mo As MqttConnectOptions
    mo.Initialize("", "")
    'this message will be sent if the client is disconnected unexpectedly.
    mo.SetLastWill("all/disconnect", serializator.ConvertObjectToBytes(Name), 0, False)
End Sub

Private Sub client_Connected (Success As Boolean)
    Log($"Connected: ${Success}"$)
    If Success Then
        connected = True
        client.Subscribe("all/#", 0)
        client.Publish2("all/connect", serializator.ConvertObjectToBytes(Name), 0, False)
        ToastMessageShow("Error connecting: " & LastException, True)
    End If
End Sub

Private Sub client_MessageArrived (Topic As String, Payload() As Byte)
    Dim receivedObject As Object = serializator.ConvertBytesToObject(Payload)
    If Topic = "all/connect" Or Topic = "all/disconnect" Then
        'new client has connected or disconnected
        Dim newUser As String = receivedObject
        If isServer Then
            Log($"${Topic}: ${newUser}"$)
            Dim index As Int = users.IndexOf(newUser)
            If Topic.EndsWith("connect") And index = -1 Then users.Add(newUser)
            If Topic.EndsWith("disconnect") And index >= 0 Then users.RemoveAt(index)
            client.Publish2("all/users", serializator.ConvertObjectToBytes(users), 0, False)
        End If
    Else if Topic = "all/users" Then
        Dim NewUsers2 As List = receivedObject   '''change (NewUsers) to (NewUsers2)
        'is here in Page, original:      CallSubDelayed2(Chat, "NewUsers", NewUsers)
        ''''qq66yy here change Layout
        'this will start the chat activity if it wasn't started yet.  qq66yy
        'Log("bak from chat new usr")
        Dim m As Message = receivedObject
        'is here in Page,  Original:  CallSub2(Chat, "NewMessage", m)
    End If
End Sub

Public Sub SendMessage(Body As String)
    If connected Then
        client.Publish2("all", CreateMessage(Body), 0, False)
    End If
End Sub

Public Sub Disconnect
    BroadcastTimer.Enabled = False
    DiscoveredServer = ""
    '''original:  CallSub(Main, "UpdateState")

    If connected Then
        client.Publish2("all/disconnect", serializator.ConvertObjectToBytes(Name), 0, False)
    End If
End Sub

'copy from Starter:
Private Sub CreateMessage(Body As String) As Byte()
    Dim m As Message
    m.Body = Body
    m.From = Name
    Return serializator.ConvertObjectToBytes(m)
End Sub

Private Sub client_Disconnected
    connected = False
    '''original:  CallSub(Chat, "Disconnected")

    If isServer Then
        brokerStarted = False
    End If
End Sub

'Returns the UDP broadcast address.
'Returns an empty string if not available.
Private Sub GetBroadcastAddress As String
   Dim niIterator As JavaObject
   niIterator = niIterator.InitializeStatic("").RunMethod("getNetworkInterfaces", Null)
   Do While niIterator.RunMethod("hasMoreElements", Null)
     Dim ni As JavaObject = niIterator.RunMethod("nextElement", Null)
     If ni.RunMethod("isLoopback", Null) = False Then
       Dim addresses As List = ni.RunMethod("getInterfaceAddresses", Null)
       For Each ia As JavaObject In addresses
         Dim broadcast As Object = ia.RunMethod("getBroadcast", Null)
         If broadcast <> Null Then
           Dim b As String = broadcast
           Return b.SubString(1)
         End If
     End If
   Return ""
End Sub

Sub Application_Error (Error As Exception, StackTrace As String) As Boolean
    Return True
End Sub

Sub Service_Destroy

End Sub

'''all code for MQTT Chat with Auto Discovery
'''is in this Page and plus 8 lines in B4XMainPage plus Layout Files :-)

'''toDo: qq66yy change Layout in Sub client_MessageArrived in Else if Topic = "all/users" Then
'''toDo: Sub Activity_KeyPress  do not work
'''toDo: Layout: minimal Line Hight, Don't use ListView. Use xCustomListView - it is more powerful,
   'easier to work with and cross platform
'''toDo: Sub s : Activity_Resume  Activity_KeyPress   Activity_Pause
    '''     Disconnect
    ''''what to do???  StartActivity(Main)
    ''''    Disconnected
    ''''what to do???  Activity.Finish
''''toDo:  check what is toDo  in B4XPages with Activity


#Region Shared Files
#CustomBuildAction: folders ready, %WINDIR%\System32\Robocopy.exe,"..\..\Shared Files" "..\Files"
'Ctrl + click to sync files: ide://run?file=%WINDIR%\System32\Robocopy.exe&args=..\..\Shared+Files&args=..\Files&FilesSync=True
#End Region

'Ctrl + click to export as zip: ide://run?File=%B4X%\Zipper.jar&

Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI

    '''in this page B4XMainPage add 8 Lines:
    '''add 2 lines 1, 2
    Private ButtonMainPage As Button
    Public MqttObj As PageMqtt
End Sub

Sub Globals

End Sub

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

    '''add 3 lines 3, 4, 5
    B4XPages.AddPageAndCreate("Mqttid", MqttObj)
    B4XPages.SetTitle(MqttObj, "MqttTitle")

End Sub

    '''add 3 lines 6, 7, 8
Sub ButtonMainPage_Click
End Sub

'You can see the list of page related events in the B4XPagesManager object.
'The event name is B4XPage.

Last edited: