on master help sign in
Refactor chat view to use Grid layout and ItemsRepeater for messages
08721cbiko
.github/workflows/build.yml+2−2
@@ -20,9 +20,9 @@ jobs:
20 - runner: ubuntu-24.04-arm
20 - runner: ubuntu-24.04-arm
21 name: linux-arm64
21 name: linux-arm64
22 musl-target: aarch64-unknown-linux-musl
22 musl-target: aarch64-unknown-linux-musl
23− - runner: macos-latest
23+ - runner: macos-26
24 name: macos-arm64
24 name: macos-arm64
25− - runner: macos-13
25+ - runner: macos-26-intel
26 name: macos-x86_64
26 name: macos-x86_64
27 runs-on: ${{ matrix.runner }}
27 runs-on: ${{ matrix.runner }}
28 steps:
28 steps:
client/Skrepka.fsproj+1
@@ -124,6 +124,7 @@
124 <PackageReference Include="FSharp.Core" Version="11.0.100-preview3.26159.112" />
124 <PackageReference Include="FSharp.Core" Version="11.0.100-preview3.26159.112" />
125 <PackageReference Include="Fabulous" Version="3.0.0-pre22" />
125 <PackageReference Include="Fabulous" Version="3.0.0-pre22" />
126 <PackageReference Include="Fabulous.Avalonia" Version="3.0.0-pre13" />
126 <PackageReference Include="Fabulous.Avalonia" Version="3.0.0-pre13" />
127+ <PackageReference Include="Fabulous.Avalonia.ItemsRepeater" Version="3.0.0-pre13" />
127 <PackageReference Include="Sodium.Core" Version="1.4.0" />
128 <PackageReference Include="Sodium.Core" Version="1.4.0" />
128 <PackageReference Include="Donald" Version="10.0.2" />
129 <PackageReference Include="Donald" Version="10.0.2" />
129 <PackageReference Include="Microsoft.Data.Sqlite" Version="11.0.0-preview.2.26159.112" />
130 <PackageReference Include="Microsoft.Data.Sqlite" Version="11.0.0-preview.2.26159.112" />
client/ViewChat.fs+31−25
@@ -1,5 +1,6 @@
1namespace Skrepka
1namespace Skrepka
2
2
3+open Avalonia.Layout
3open Fabulous.Avalonia
4open Fabulous.Avalonia
4
5
5open type Fabulous.Avalonia.View
6open type Fabulous.Avalonia.View
@@ -14,37 +15,42 @@ module ViewChat =
14 let name = contactName model.Contacts pk
15 let name = contactName model.Contacts pk
15 let msgs = messagesFor pk model.Messages
16 let msgs = messagesFor pk model.Messages
16
17
17− (VStack(8.) {
18+ (Grid([ Dimension.Auto; Dimension.Auto; Dimension.Star; Dimension.Auto ], [ Dimension.Star ]) {
18− HStack(8.) {
19+ (HStack(8.) {
19 backButton (SetPage Conversations)
20 backButton (SetPage Conversations)
20
21
21 TextBlock(name).fontSize(20.).centerVertical ()
22 TextBlock(name).fontSize(20.).centerVertical ()
22− }
23+ })
23−
24+ .gridRow (0)
25+
24− viewErrorBanner model.Error
26+ (viewErrorBanner model.Error).gridRow (1)
25−
27+
26− ScrollViewer(
27− VStack(4.) {
28− if msgs.IsEmpty then
28+ (if msgs.IsEmpty then
29− TextBlock("No messages yet").padding(8.).fontSize (14.)
29+ AnyView(TextBlock("No messages yet").padding(8.).fontSize (14.))
30− else
30+ else
31− for m in msgs do
31+ let reversed = List.rev msgs
32+
33+ AnyView(
34+ ScrollViewer(
35+ ItemsRepeater(reversed, fun m ->
32− let prefix, tick =
36+ let prefix, tick =
33− match m.Direction with
37+ match m.Direction with
34− | Outgoing DeliveryStatus.Delivered -> "You: ", " \u2713"
38+ | Outgoing DeliveryStatus.Delivered -> "You: ", " \u2713"
35− | Outgoing DeliveryStatus.Sent -> "You: ", ""
39+ | Outgoing DeliveryStatus.Sent -> "You: ", ""
36− | Incoming -> "", ""
40+ | Incoming -> "", ""
37−
41+
38− TextBlock($"{prefix}{m.Body}{tick}").padding(8.).fontSize (14.)
42+ TextBlock($"{prefix}{m.Body}{tick}").padding(8.).fontSize (14.))
39− }
43+ )
40− )
44+ ))
41−
45+ .gridRow (2)
46+
42− HStack(8.) {
47+ (HStack(8.) {
43 TextBox(compose, fun text -> SetPage(Chat(pk, text)))
48 TextBox(compose, fun text -> SetPage(Chat(pk, text)))
44 .watermark("Message...")
49 .watermark("Message...")
45− .horizontalAlignment (Avalonia.Layout.HorizontalAlignment.Stretch)
50+ .horizontalAlignment (HorizontalAlignment.Stretch)
46
51
47 Button("Send", DoSend)
52 Button("Send", DoSend)
48− }
53+ })
54+ .gridRow (3)
49 })
55 })
50 .margin (12.)
56 .margin (12.)