@@ -46,7 +46,8 @@ module App =
46 ComposeText: string
46 ComposeText: string
47 NewPubkey: string
47 NewPubkey: string
48 NewNickname: string
48 NewNickname: string
49− Error: string option }
49+ Error: string option
51 // ── Msg ──
52 // ── Msg ──
@@ -66,7 +67,7 @@ module App =
66 | SetNewNickname of string
67 | SetNewNickname of string
67 | DoSaveContact
68 | DoSaveContact
68 | DoDeleteContact of string
69 | DoDeleteContact of string
69− | PollResult of (string * string * int64 * string) list * string
70+ | PollResult of (string * string * int64 * string) list * string * int64
71 | CopyPubKey
72 | CopyPubKey
72 | DismissError
73 | DismissError
@@ -84,7 +85,7 @@ module App =
84 pubKeyHex: string *
85 pubKeyHex: string *
85 recipPubHex: string *
86 recipPubHex: string *
86 text: string
87 text: string
87− | CmdPoll of url: string * token: string * privKey: byte[]
88+ | CmdPoll of url: string * token: string * privKey: byte[] * cursor: int64
88 | CmdCopyToClipboard of string
89 | CmdCopyToClipboard of string
90 // ── Helpers ──
91 // ── Helpers ──
@@ -112,7 +113,8 @@ module App =
112 ComposeText = ""
113 ComposeText = ""
113 NewPubkey = ""
114 NewPubkey = ""
114 NewNickname = ""
115 NewNickname = ""
115− Error = None },
116+ Error = None
118 // ── Update ──
120 // ── Update ──
@@ -143,7 +145,7 @@ module App =
143 Conn = Online token
145 Conn = Online token
144 Page = Conversations
146 Page = Conversations
145 Error = None },
147 Error = None },
146− [ CmdPoll(model.ServerUrl, token, model.PrivKey.Value) ]
148+ [ CmdPoll(model.ServerUrl, token, model.PrivKey.Value, model.PollCursor) ]
148 | AuthErr err -> { model with Conn = Offline; Error = Some err }, []
150 | AuthErr err -> { model with Conn = Offline; Error = Some err }, []
@@ -170,7 +172,7 @@ module App =
171 | Sent _ -> model, []
173 | Sent _ -> model, []
173− | PollResult(incoming, status) ->
175+ | PollResult(incoming, status, newCursor) ->
174 let model' =
176 let model' =
176 |> List.fold
178 |> List.fold
@@ -195,15 +197,15 @@ module App =
196 Contacts = contacts
198 Contacts = contacts
197 Messages = m.Messages |> Map.add fromPk (msgs @ [ newMsg ]) })
199 Messages = m.Messages |> Map.add fromPk (msgs @ [ newMsg ]) })
198− { model with PollStatus = status }
200+ { model with PollStatus = status; PollCursor = newCursor }
200 match model'.Conn with
202 match model'.Conn with
201− | Online token -> model', [ CmdPoll(model'.ServerUrl, token, model'.PrivKey.Value) ]
203+ | Online token -> model', [ CmdPoll(model'.ServerUrl, token, model'.PrivKey.Value, model'.PollCursor) ]
202 | _ -> model', []
204 | _ -> model', []
204 | DoPoll ->
206 | DoPoll ->
205 match model.Conn, model.PrivKey with
207 match model.Conn, model.PrivKey with
206− | Online token, Some priv -> model, [ CmdPoll(model.ServerUrl, token, priv) ]
208+ | Online token, Some priv -> model, [ CmdPoll(model.ServerUrl, token, priv, model.PollCursor) ]
207 | _ -> model, []
209 | _ -> model, []
209 | SetNewPubkey pk -> { model with NewPubkey = pk }, []
211 | SetNewPubkey pk -> { model with NewPubkey = pk }, []
@@ -294,10 +296,10 @@ module App =
294 return DismissError // TODO: show send errors properly
296 return DismissError // TODO: show send errors properly
297− | CmdPoll(url, token, privKey) ->
299+ | CmdPoll(url, token, privKey, cursor) ->
298 asyncCmd (async {
300 asyncCmd (async {
300− let! (events, _) = ApiClient.poll url token
302+ let! (events, newCursor) = ApiClient.poll url token cursor
301 let messages = ResizeArray()
303 let messages = ResizeArray()
302 let ackIds = ResizeArray()
304 let ackIds = ResizeArray()
303 let errors = ResizeArray()
305 let errors = ResizeArray()
@@ -335,15 +337,15 @@ module App =
335 $"[{now}] evts:{events.Length} msgs:{messages.Count} errs:{errors.Count}"
337 $"[{now}] evts:{events.Length} msgs:{messages.Count} errs:{errors.Count}"
336 + (if errors.Count > 0 then $" [{errors.[0]}]" else "")
338 + (if errors.Count > 0 then $" [{errors.[0]}]" else "")
338− return PollResult(Seq.toList messages, status)
340+ return PollResult(Seq.toList messages, status, newCursor)
340 | :? System.Threading.Tasks.TaskCanceledException ->
342 | :? System.Threading.Tasks.TaskCanceledException ->
341 // Normal timeout from long poll — just retry
343 // Normal timeout from long poll — just retry
342− return PollResult([], "polling...")
344+ return PollResult([], "polling...", cursor)
344 let now = DateTimeOffset.UtcNow.ToString("HH:mm:ss")
346 let now = DateTimeOffset.UtcNow.ToString("HH:mm:ss")
345 do! Async.Sleep 3000
347 do! Async.Sleep 3000
346− return PollResult([], $"[{now}] poll error: {ex.Message}")
348+ return PollResult([], $"[{now}] poll error: {ex.Message}", cursor)
349 | CmdCopyToClipboard text ->
351 | CmdCopyToClipboard text ->