on master help sign in
Fix iOS clipboard support and resolve Fabulous.Avalonia version incompatibility

- Add ISingleViewApplicationLifetime case to getClipboard() for iOS clipboard access - Revert Avalonia (12.0.1 → 11.3.0), Fabulous (pre9 → pre22), and Fabulous.Avalonia (pre9 → pre13) to compatible versions - Update Sodium.Core, Dapper.FSharp, and Microsoft.Data.Sqlite to latest compatible versions - Improve iOS build configuration with FixBundlePlist target for launch screen and app icons

commitdb5a27626003727cfaaf358c6a6106c3caee15a2 authoriko <mail@iko.soy> dateTue 14 Apr 2026, 05:30 (6 months ago) parent4faf45f
6 files changed+41−16
client/App.fs+5 client/Platform/iOS/Info.plist−2 client/Skrepka.app/Contents/MacOS/Skrepka+1−1 client/Skrepka.fsproj+31−7 client/msbuild.binlog server.knot+4−6
client/App.fs+5
@@ -529,6 +529,11 @@ module App =
529529 desktop.MainWindow
530530 |> Option.ofObj
531531 |> Option.bind (fun w -> w.Clipboard |> Option.ofObj)
532+ | :? Avalonia.Controls.ApplicationLifetimes.ISingleViewApplicationLifetime as singleView ->
533+ singleView.MainView
534+ |> Option.ofObj
535+ |> Option.bind (fun v -> Avalonia.Controls.TopLevel.GetTopLevel(v) |> Option.ofObj)
536+ |> Option.bind (fun tl -> tl.Clipboard |> Option.ofObj)
532537 | _ -> None
533538
534539 let private getStorageProvider () =
client/Platform/iOS/Info.plist−2
@@ -19,8 +19,6 @@
1919 <integer>1</integer>
2020 <integer>2</integer>
2121 </array>
22− <key>UILaunchStoryboardName</key>
23− <string>LaunchScreen</string>
2422 <key>UILaunchScreen</key>
2523 <dict/>
2624 <key>UIRequiredDeviceCapabilities</key>
client/Skrepka.app/Contents/MacOS/Skrepka+1−1
@@ -1 +1 @@
1−../../../Skrepka.dll
1+../../../Skrepka
client/Skrepka.fsproj+31−7
@@ -63,7 +63,6 @@
6363 <ItemGroup Condition="$(AvaloniaPlatform) == 'iOS'">
6464 <None Include="$(iOSPlatformFolder)Entitlements.plist" />
6565 <None Include="$(iOSPlatformFolder)Info.plist" LogicalName="Info.plist" />
66− <InterfaceDefinition Include="$(iOSPlatformFolder)Resources\LaunchScreen.storyboard" />
6766 <ImageAsset Include="$(iOSPlatformFolder)Resources\Assets.xcassets\Contents.json" />
6867 <ImageAsset Include="$(iOSPlatformFolder)Resources\Assets.xcassets\AppIcon.appiconset\Contents.json" />
6968 <ImageAsset Include="$(iOSPlatformFolder)Resources\Assets.xcassets\AppIcon.appiconset\*.png" />
@@ -71,8 +70,33 @@
7170 <PackageReference Include="Avalonia.iOS" Version="11.3.0" />
7271 </ItemGroup>
7372
74− <Target Name="AddLaunchScreenToPlist" AfterTargets="_CompileAppManifest" Condition="$(AvaloniaPlatform) == 'iOS'">
75− <Exec Command="/usr/libexec/PlistBuddy -c 'Add :UILaunchStoryboardName string LaunchScreen' '$(AppBundleDir)/Info.plist'" ContinueOnError="true" />
73+ <Target Name="FixBundlePlist" AfterTargets="Build" Condition="$(AvaloniaPlatform) == 'iOS'">
74+ <PropertyGroup>
75+ <_Plist>$(AppBundleDir)/Info.plist</_Plist>
76+ <_PB>/usr/libexec/PlistBuddy</_PB>
77+ </PropertyGroup>
78+ <!-- Launch screen (full-screen, no letterboxing) -->
79+ <Exec Command="$(_PB) -c 'Delete :UILaunchStoryboardName' '$(_Plist)'" ContinueOnError="true" />
80+ <Exec Command="$(_PB) -c 'Add :UILaunchScreen dict' '$(_Plist)'" ContinueOnError="true" />
81+ <!-- Privacy descriptions -->
82+ <Exec Command="$(_PB) -c 'Add :NSPhotoLibraryUsageDescription string Skrepka needs access to your photo library to set a profile photo.' '$(_Plist)'" ContinueOnError="true" />
83+ <!-- App icon (fallback when actool produces empty output) -->
84+ <Exec Command="$(_PB) -c 'Add :CFBundleIcons dict' '$(_Plist)'" ContinueOnError="true" />
85+ <Exec Command="$(_PB) -c 'Add :CFBundleIcons:CFBundlePrimaryIcon dict' '$(_Plist)'" ContinueOnError="true" />
86+ <Exec Command="$(_PB) -c 'Add :CFBundleIcons:CFBundlePrimaryIcon:CFBundleIconFiles array' '$(_Plist)'" ContinueOnError="true" />
87+ <Exec Command="$(_PB) -c 'Add :CFBundleIcons:CFBundlePrimaryIcon:CFBundleIconFiles:0 string AppIcon60x60' '$(_Plist)'" ContinueOnError="true" />
88+ <Exec Command="$(_PB) -c 'Add :CFBundleIcons:CFBundlePrimaryIcon:CFBundleIconName string AppIcon' '$(_Plist)'" ContinueOnError="true" />
89+ <Exec Command="$(_PB) -c 'Add :CFBundleIcons~ipad dict' '$(_Plist)'" ContinueOnError="true" />
90+ <Exec Command="$(_PB) -c 'Add :CFBundleIcons~ipad:CFBundlePrimaryIcon dict' '$(_Plist)'" ContinueOnError="true" />
91+ <Exec Command="$(_PB) -c 'Add :CFBundleIcons~ipad:CFBundlePrimaryIcon:CFBundleIconFiles array' '$(_Plist)'" ContinueOnError="true" />
92+ <Exec Command="$(_PB) -c 'Add :CFBundleIcons~ipad:CFBundlePrimaryIcon:CFBundleIconFiles:0 string AppIcon60x60' '$(_Plist)'" ContinueOnError="true" />
93+ <Exec Command="$(_PB) -c 'Add :CFBundleIcons~ipad:CFBundlePrimaryIcon:CFBundleIconFiles:1 string AppIcon76x76' '$(_Plist)'" ContinueOnError="true" />
94+ <Exec Command="$(_PB) -c 'Add :CFBundleIcons~ipad:CFBundlePrimaryIcon:CFBundleIconName string AppIcon' '$(_Plist)'" ContinueOnError="true" />
95+ <!-- Copy icon PNGs to bundle (fallback when actool doesn't produce Assets.car) -->
96+ <Copy SourceFiles="$(iOSPlatformFolder)Resources/Assets.xcassets/AppIcon.appiconset/icon-120.png" DestinationFiles="$(AppBundleDir)/AppIcon60x60@2x.png" SkipUnchangedFiles="true" />
97+ <Copy SourceFiles="$(iOSPlatformFolder)Resources/Assets.xcassets/AppIcon.appiconset/icon-180.png" DestinationFiles="$(AppBundleDir)/AppIcon60x60@3x.png" SkipUnchangedFiles="true" />
98+ <Copy SourceFiles="$(iOSPlatformFolder)Resources/Assets.xcassets/AppIcon.appiconset/icon-152.png" DestinationFiles="$(AppBundleDir)/AppIcon76x76@2x~ipad.png" SkipUnchangedFiles="true" />
99+ <Copy SourceFiles="$(iOSPlatformFolder)Resources/Assets.xcassets/AppIcon.appiconset/icon-167.png" DestinationFiles="$(AppBundleDir)/AppIcon83.5x83.5@2x~ipad.png" SkipUnchangedFiles="true" />
76100 </Target>
77101
78102 <ItemGroup Condition="$(AvaloniaPlatform) == 'iOS' And $(RuntimeIdentifier.StartsWith('iossimulator'))">
@@ -84,12 +108,12 @@
84108
85109 <ItemGroup>
86110 <PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.0" />
87− <PackageReference Include="FSharp.Core" Version="9.0.100" />
111+ <PackageReference Include="FSharp.Core" Version="11.0.100-preview3.26159.112" />
88112 <PackageReference Include="Fabulous" Version="3.0.0-pre22" />
89113 <PackageReference Include="Fabulous.Avalonia" Version="3.0.0-pre13" />
90− <PackageReference Include="Sodium.Core" Version="1.4.0" />
91− <PackageReference Include="Dapper.FSharp" Version="4.5.1" />
92− <PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.5" />
114+ <PackageReference Include="Sodium.Core" Version="1.4.1-preview.1" />
115+ <PackageReference Include="Dapper.FSharp" Version="4.10.0" />
116+ <PackageReference Include="Microsoft.Data.Sqlite" Version="11.0.0-preview.2.26159.112" />
93117 </ItemGroup>
94118
95119</Project>
client/msbuild.binlognew file

Binary file not shown.

server.knot+4−6
@@ -119,7 +119,6 @@ data AckResult = AckUnauthorized {} | AckDone {pendingAcks: [AckedEntry], evicte
119119data PollResult = PollUnauthorized {} | PollOk {events: [PollEvent], cursor: Timestamp}
120120data ForwardResult = ForwardDuplicate {} | ForwardRejected {} | ForwardStored {}
121121
122−
123122-- ============================================
124123-- Persisted State
125124-- ============================================
@@ -566,7 +565,6 @@ countMessagesFor = \messages toKey t ->
566565hasMessage : MessageIdHex -> PubkeyHex -> [{messageId: MessageIdHex, toKey: PubkeyHex | a}] -> Bool
567566hasMessage = \mid toKey items -> any items (\x -> x.messageId == mid && x.toKey == toKey)
568567
569−
570568validGossipEvents : [GossipEvent] -> Timestamp -> {online: [ValidGossipEntry], offline: [ValidGossipEntry]}
571569validGossipEvents = \events t ->
572570 let validate = \e ->
@@ -686,6 +684,10 @@ mergeGossipPresence = \presence deduped trustedOffline fromServer t ->
686684 gossipPeerServers: collectPeerServers capResult.finalPresence (\p -> p.server),
687685 withinCapacity: capResult.withinCapacity}
688686
687+maybePruneAndBroadcast = \t -> do
688+ pruneResult <- atomic do maybePrune t
689+ forkBroadcastOffline t pruneResult
690+
689691withFederationAuth = \authorization t respond precondition action ->
690692 if not (verifyFederationAuth authorization) || not precondition
691693 then do
@@ -693,10 +695,6 @@ withFederationAuth = \authorization t respond precondition action ->
693695 yield (respond {ok: False {}})
694696 else action
695697
696−maybePruneAndBroadcast = \t -> do
697− pruneResult <- atomic do maybePrune t
698− forkBroadcastOffline t pruneResult
699−
700698withSessionAuth = \authorization t onUnauth onAuth -> do
701699 sessions <- *sessions
702700 case extractToken authorization of