@@ -3,7 +3,6 @@ namespace Skrepka
4open System.IO
4open System.IO
5open System.Text.Json
5open System.Text.Json
6−open System.Text.Json.Serialization
7open Fabulous
6open Fabulous
8open Fabulous.Maui
7open Fabulous.Maui
9open Microsoft.Maui.Graphics
8open Microsoft.Maui.Graphics
@@ -66,8 +65,7 @@ module App =
66 // ── Msg ──
65 // ── Msg ──
68 type StateLoadResult =
67 type StateLoadResult =
69− | IdentityAndData of Identity * Data * Profile option
68+ | Loaded of Identity * Data option * Profile option
70− | IdentityOnly of Identity * Profile option
71 | NothingSaved
69 | NothingSaved
73 type Msg =
71 type Msg =
@@ -340,7 +338,7 @@ module App =
340 | None -> () ]
338 | None -> () ]
341 | _ -> model, []
339 | _ -> model, []
343− | StateLoaded(IdentityAndData(identity, data, profile)) ->
341+ | StateLoaded(Loaded(identity, Some data, profile)) ->
344 let model' =
342 let model' =
345 { model with
343 { model with
346 Auth = Identified(identity, Connecting)
344 Auth = Identified(identity, Connecting)
@@ -351,7 +349,7 @@ module App =
351 Profile = profile
349 Profile = profile
352 Page = Conversations }
350 Page = Conversations }
353 model', [ CmdConnect(model'.ServerUrl, identity) ]
351 model', [ CmdConnect(model'.ServerUrl, identity) ]
354− | StateLoaded(IdentityOnly(identity, profile)) ->
352+ | StateLoaded(Loaded(identity, None, profile)) ->
355 { model with Auth = Identified(identity, Offline); Profile = profile; Page = Settings }, []
353 { model with Auth = Identified(identity, Offline); Profile = profile; Page = Settings }, []
356 | StateLoaded NothingSaved -> model, []
354 | StateLoaded NothingSaved -> model, []
@@ -367,16 +365,16 @@ module App =
368 type private Envelope =
366 type private Envelope =
369 | TextMessage of id: string * body: string
367 | TextMessage of id: string * body: string
370− | DeliveryAck of id: string * ackIds: string list
368+ | DeliveryAck of ackIds: string list
371− | ProfileMessage of id: string * profile: Profile
369+ | ProfileMessage of profile: Profile
373 let private serializeEnvelope = function
371 let private serializeEnvelope = function
374 | TextMessage(id, body) ->
372 | TextMessage(id, body) ->
375 JsonSerializer.Serialize({| ``type`` = "text"; id = id; body = body |})
373 JsonSerializer.Serialize({| ``type`` = "text"; id = id; body = body |})
376− | DeliveryAck(id, ackIds) ->
374+ | DeliveryAck ackIds ->
377− JsonSerializer.Serialize({| ``type`` = "delivery.ack"; id = id; ack_ids = ackIds |})
375+ JsonSerializer.Serialize({| ``type`` = "delivery.ack"; id = Guid.NewGuid().ToString(); ack_ids = ackIds |})
378− | ProfileMessage(id, profile) ->
376+ | ProfileMessage profile ->
379− JsonSerializer.Serialize({| ``type`` = "profile"; id = id; timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); display_name = profile.DisplayName; bio = profile.Bio; photo = profile.PhotoBase64 |})
377+ JsonSerializer.Serialize({| ``type`` = "profile"; id = Guid.NewGuid().ToString(); timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds(); display_name = profile.DisplayName; bio = profile.Bio; photo = profile.PhotoBase64 |})
381 let private sendEnvelope (session: Session) (recipientHex: string) (envelope: Envelope) =
379 let private sendEnvelope (session: Session) (recipientHex: string) (envelope: Envelope) =
@@ -399,12 +397,12 @@ module App =
399 Some(TextMessage(root.GetProperty("id").GetString(), root.GetProperty("body").GetString()))
397 Some(TextMessage(root.GetProperty("id").GetString(), root.GetProperty("body").GetString()))
400 | "delivery.ack" ->
398 | "delivery.ack" ->
401 let ackIds = root.GetProperty("ack_ids").EnumerateArray() |> Seq.map _.GetString() |> Seq.toList
399 let ackIds = root.GetProperty("ack_ids").EnumerateArray() |> Seq.map _.GetString() |> Seq.toList
402− Some(DeliveryAck(root.GetProperty("id").GetString(), ackIds))
400+ Some(DeliveryAck ackIds)
403 | "profile" ->
401 | "profile" ->
404 let displayName = root.GetProperty("display_name").GetString()
402 let displayName = root.GetProperty("display_name").GetString()
405 let bio = tryGetJsonString root "bio" |> Option.defaultValue ""
403 let bio = tryGetJsonString root "bio" |> Option.defaultValue ""
406 let photo = tryGetJsonString root "photo" |> Option.defaultValue ""
404 let photo = tryGetJsonString root "photo" |> Option.defaultValue ""
407− Some(ProfileMessage(root.GetProperty("id").GetString(), { DisplayName = displayName; Bio = bio; PhotoBase64 = photo }))
405+ Some(ProfileMessage { DisplayName = displayName; Bio = bio; PhotoBase64 = photo })
408 | _ -> None
406 | _ -> None
410 let private decryptEvent (privKey: byte[]) (payload: EventPayload) =
408 let private decryptEvent (privKey: byte[]) (payload: EventPayload) =
@@ -420,9 +418,9 @@ module App =
420 Timestamp = DateTimeOffset.FromUnixTimeSeconds(payload.Timestamp)
418 Timestamp = DateTimeOffset.FromUnixTimeSeconds(payload.Timestamp)
421 IsOutgoing = false
419 IsOutgoing = false
422 Status = DeliveryStatus.Delivered }))
420 Status = DeliveryStatus.Delivered }))
423− | Some(DeliveryAck(_, ackIds)) ->
421+ | Some(DeliveryAck ackIds) ->
424 Ok(IncomingDeliveryAck(senderHex, ackIds))
422 Ok(IncomingDeliveryAck(senderHex, ackIds))
425− | Some(ProfileMessage(_, profile)) ->
423+ | Some(ProfileMessage profile) ->
426 Ok(IncomingProfile(senderHex, profile))
424 Ok(IncomingProfile(senderHex, profile))
427 | None -> Error "unknown envelope type"
425 | None -> Error "unknown envelope type"
428 | None -> Error "decrypt failed"
426 | None -> Error "decrypt failed"
@@ -438,7 +436,7 @@ module App =
438 |> List.map (fun (sender, pairs) -> sender, List.map snd pairs)
436 |> List.map (fun (sender, pairs) -> sender, List.map snd pairs)
440 for sender, msgIds in chatsBySender do
438 for sender, msgIds in chatsBySender do
441− try do! sendEnvelope session sender (DeliveryAck(Guid.NewGuid().ToString(), msgIds)) |> Async.Ignore
439+ try do! sendEnvelope session sender (DeliveryAck msgIds) |> Async.Ignore
442 with _ -> ()
440 with _ -> ()
@@ -506,11 +504,7 @@ module App =
506 asyncCmd (async {
504 asyncCmd (async {
507 match! Store.loadIdentity () with
505 match! Store.loadIdentity () with
508 | Some id ->
506 | Some id ->
509− let profile = Store.loadProfile ()
510− return StateLoaded(
507+ return StateLoaded(Loaded(id, Store.loadData (), Store.loadProfile ()))
511− match Store.loadData () with
512− | Some data -> IdentityAndData(id, data, profile)
513− | None -> IdentityOnly(id, profile))
514 | None -> return StateLoaded NothingSaved
508 | None -> return StateLoaded NothingSaved
@@ -542,7 +536,7 @@ module App =
542 Cmd.ofEffect (fun _ ->
536 Cmd.ofEffect (fun _ ->
544 for recipientHex in recipientHexes do
538 for recipientHex in recipientHexes do
545− try do! sendEnvelope session recipientHex (ProfileMessage(Guid.NewGuid().ToString(), profile)) |> Async.Ignore
539+ try do! sendEnvelope session recipientHex (ProfileMessage profile) |> Async.Ignore
546 with _ -> ()
540 with _ -> ()
547 } |> Async.Start)
541 } |> Async.Start)