on master help sign in
Fix button disabled state display and simplify contact naming logic
commitd6c4b4ef2ade7e40b955f57c6a25129766ba296e authoriko <mail@iko.soy> dateSun 19 Apr 2026, 14:41 (6 months ago) parentebc16eb
4 files changed+88−87
client/App.fs+74−68 client/AppTypes.fs+2−3 client/Buttons.fs+2−10 client/Store.fs+10−6
client/App.fs+74−68
@@ -171,7 +171,10 @@ module App =
171171
172172 { model with
173173 Auth = Identified(id, Online token)
174− Page = match model.Page with Setup -> Conversations | p -> p
174+ Page =
175+ match model.Page with
176+ | Setup -> Conversations
177+ | p -> p
175178 Error = None
176179 PollStatus = "polling..."
177180 FlushingOutbox = true },
@@ -189,7 +192,10 @@ module App =
189192 match model.Auth with
190193 | Identified(id, Online _) ->
191194 let m = setConn Connecting model
192− { m with FlushingOutbox = false; PollRetries = 0 },
195+
196+ { m with
197+ FlushingOutbox = false
198+ PollRetries = 0 },
193199 [ CmdConnect(model.ServerUrl, id) ]
194200 | _ -> model, []
195201
@@ -273,17 +279,17 @@ module App =
273279 | Some bytes ->
274280 let hex = Crypto.toHex bytes
275281
276− let contact =
277− match Map.tryFind hex model.Contacts with
278− | Some e -> { e with Nickname = cpk }
279− | None -> newContact hex cpk
282+ match Map.tryFind hex model.Contacts with
283+ | Some e -> model, []
284+ | None ->
285+ let contact = newContact hex cpk
280286
281− let model' =
282− { model with
283− Contacts = Map.add hex contact model.Contacts
284− Page = Conversations }
287+ let model' =
288+ { model with
289+ Contacts = Map.add hex contact model.Contacts
290+ Page = Conversations }
285291
286− model', [ saveCmdMsg model' ]
292+ model', [ saveCmdMsg model' ]
287293 | None ->
288294 { model with
289295 Error = Some "Invalid public key" },
@@ -519,68 +525,68 @@ module App =
519525 dispatch TokenExpired
520526 else
521527
522− let ackIds = response.Events |> Array.map _.Id |> Array.toList
523−
524− let results =
525− response.Events
526− |> Array.choose (fun evt ->
527− match evt.EventType with
528− | Message -> Some(decryptEvent session.Identity.PrivKey evt.Payload)
529− | UnknownEvent s ->
530− log $"unknown event type: {s}"
531− None)
532−
533− let events = results |> Array.choose Result.toOption |> Array.toList
534−
535− let errors =
536− results
537− |> Array.choose (function
538− | Error e -> Some e
539− | _ -> None)
540− |> Array.toList
541−
542− for e in errors do
543− log $"decrypt error: {e}"
544−
545− if not ackIds.IsEmpty then
546− try
547− do! ackMessages session.Url session.Token ackIds
548− with ex ->
549− log $"ack error: {ex.Message}"
550−
551− if not events.IsEmpty then
552− let acksBySender =
553− events
554− |> List.choose (fun evt ->
555− match evt.Envelope with
556− | Envelope.TextMessage(id, _) -> Some(evt.Sender, id)
557− | _ -> None)
558− |> List.groupBy fst
559− |> List.map (fun (sender, pairs) -> sender, List.map snd pairs)
528+ let ackIds = response.Events |> Array.map _.Id |> Array.toList
560529
561− for sender, msgIds in acksBySender do
562− try
563− do! sendEnvelope session sender (Envelope.DeliveryAck msgIds)
564− with ex ->
565− log $"delivery ack error: {ex.Message}"
530+ let results =
531+ response.Events
532+ |> Array.choose (fun evt ->
533+ match evt.EventType with
534+ | Message -> Some(decryptEvent session.Identity.PrivKey evt.Payload)
535+ | UnknownEvent s ->
536+ log $"unknown event type: {s}"
537+ None)
566538
567− if response.Events.Length = 0 then
568− do! Async.Sleep Constants.pollEmptyDelayMs
539+ let events = results |> Array.choose Result.toOption |> Array.toList
569540
570− let chatCount =
571− events
572− |> List.sumBy (fun e ->
573− match e.Envelope with
574− | Envelope.TextMessage _ -> 1
575− | _ -> 0)
541+ let errors =
542+ results
543+ |> Array.choose (function
544+ | Error e -> Some e
545+ | _ -> None)
546+ |> Array.toList
576547
577− let status =
578− $"evts:{response.Events.Length} msgs:{chatCount} errs:{errors.Length}"
579− + (match List.tryHead errors with
580− | Some e -> $" [{e}]"
581− | None -> "")
548+ for e in errors do
549+ log $"decrypt error: {e}"
582550
583− dispatch (PollResult(events, status, response.Cursor))
551+ if not ackIds.IsEmpty then
552+ try
553+ do! ackMessages session.Url session.Token ackIds
554+ with ex ->
555+ log $"ack error: {ex.Message}"
556+
557+ if not events.IsEmpty then
558+ let acksBySender =
559+ events
560+ |> List.choose (fun evt ->
561+ match evt.Envelope with
562+ | Envelope.TextMessage(id, _) -> Some(evt.Sender, id)
563+ | _ -> None)
564+ |> List.groupBy fst
565+ |> List.map (fun (sender, pairs) -> sender, List.map snd pairs)
566+
567+ for sender, msgIds in acksBySender do
568+ try
569+ do! sendEnvelope session sender (Envelope.DeliveryAck msgIds)
570+ with ex ->
571+ log $"delivery ack error: {ex.Message}"
572+
573+ if response.Events.Length = 0 then
574+ do! Async.Sleep Constants.pollEmptyDelayMs
575+
576+ let chatCount =
577+ events
578+ |> List.sumBy (fun e ->
579+ match e.Envelope with
580+ | Envelope.TextMessage _ -> 1
581+ | _ -> 0)
582+
583+ let status =
584+ $"evts:{response.Events.Length} msgs:{chatCount} errs:{errors.Length}"
585+ + (match List.tryHead errors with
586+ | Some e -> $" [{e}]"
587+ | None -> "")
588+
589+ dispatch (PollResult(events, status, response.Cursor))
584590 with
585591 | :? TimeoutException ->
586592 log "poll timeout"
client/AppTypes.fs+2−3
@@ -117,9 +117,8 @@ module AppTypes =
117117
118118 let contactName (contacts: Map<string, Contact>) (pk: string) =
119119 match Map.tryFind pk contacts with
120− | Some c when c.Nickname <> "" -> c.Nickname
121− | Some c when c.DisplayName <> "" -> c.DisplayName
122− | _ -> truncKey pk
120+ | Some c -> c.DisplayName
121+ | _ -> pk
123122
124123 let messagesFor (pk: string) (messages: Map<string, ChatMessage list>) =
125124 messages |> Map.tryFind pk |> Option.defaultValue []
client/Buttons.fs+2−10
@@ -35,24 +35,16 @@ module Buttons =
3535 Rectangle().stroke(Colors.Black).strokeThickness (4.)
3636
3737 let private textButton fontSize pressOffset restOffset margin priority (text: string) (msg: 'msg) disabled =
38− // Start from the opposite state's offset so the transition animates
39− let initialOffset = if disabled then restOffset else 0.
40−
4138 Component($"{text}-{disabled}") {
4239 let! pressed = Context.State(false)
43− let! animOffset = Context.State(initialOffset)
4440
45− let target =
41+ let offset =
4642 if disabled then 0.
4743 elif pressed.Current then pressOffset
4844 else restOffset
4945
50− do
51− if animOffset.Current <> target then
52− Avalonia.Threading.Dispatcher.UIThread.Post(fun () -> animOffset.Set target)
53−
5446 (Grid() {
55− shadowRect animOffset.Current
47+ shadowRect offset
5648
5749 Rectangle()
5850 .fill (
client/Store.fs+10−6
@@ -88,7 +88,12 @@ module Store =
8888 if not isOutgoing then
8989 Incoming
9090 else
91− Outgoing(if status = 1 then DeliveryStatus.Delivered else DeliveryStatus.Sent) }
91+ Outgoing(
92+ if status = 1 then
93+ DeliveryStatus.Delivered
94+ else
95+ DeliveryStatus.Sent
96+ ) }
9297
9398 // ── Schema ──
9499
@@ -142,7 +147,9 @@ module Store =
142147
143148 conn
144149 |> Db.newCommand "INSERT OR REPLACE INTO schema_meta (key, value) VALUES (@key, @value)"
145− |> Db.setParams [ "key", SqlType.String "schema_version"; "value", SqlType.String(string Constants.schemaVersion) ]
150+ |> Db.setParams
151+ [ "key", SqlType.String "schema_version"
152+ "value", SqlType.String(string Constants.schemaVersion) ]
146153 |> Db.exec
147154
148155 // ── Identity ──
@@ -203,10 +210,7 @@ module Store =
203210 [ "Id", SqlType.String Constants.profileId
204211 "DisplayName", SqlType.String profile.DisplayName
205212 "Bio", SqlType.String profile.Bio
206− "Photo",
207− (match profile.Photo with
208− | Some bytes -> SqlType.Bytes bytes
209− | None -> SqlType.Null) ]
213+ "Photo", SqlType.sqlBytesOrNull profile.Photo ]
210214 |> Db.exec
211215 with ex ->
212216 log $"saveProfile error: {ex.Message}"