on master help sign in
Plumb safe area insets to model and extend bottom bar into inset padding
c8bf966iko
client/App.fs+9−3
@@ -135,8 +135,10 @@ module App =
135 Profile = None
135 Profile = None
136 FlushingOutbox = false
136 FlushingOutbox = false
137 PollRetries = 0
137 PollRetries = 0
138− KeyboardHeight = 0. },
138+ KeyboardHeight = 0.
139+ SafeAreaTop = 0.
140+ SafeAreaBottom = 0. },
139− [ CmdLoadState; CmdSubscribeKeyboard ]
141+ [ CmdLoadState; CmdSubscribeKeyboard; CmdSubscribeSafeArea ]
140
142
141 // ── Update ──
143 // ── Update ──
142
144
@@ -367,6 +369,7 @@ module App =
367 | Search _ -> model, []
369 | Search _ -> model, []
368
370
369 | KeyboardHeightChanged h -> { model with KeyboardHeight = h }, []
371 | KeyboardHeightChanged h -> { model with KeyboardHeight = h }, []
372+ | SafeAreaChanged(top, bottom) -> { model with SafeAreaTop = top; SafeAreaBottom = bottom }, []
370
373
371 | DoScanQR -> model, [ CmdScanQR ]
374 | DoScanQR -> model, [ CmdScanQR ]
372
375
@@ -698,6 +701,9 @@ module App =
698 | CmdSubscribeKeyboard ->
701 | CmdSubscribeKeyboard ->
699 Cmd.ofEffect (fun dispatch -> Keyboard.heightChanged.Add(fun h -> dispatch (KeyboardHeightChanged h)))
702 Cmd.ofEffect (fun dispatch -> Keyboard.heightChanged.Add(fun h -> dispatch (KeyboardHeightChanged h)))
700
703
704+ | CmdSubscribeSafeArea ->
705+ Cmd.ofEffect (fun dispatch -> SafeArea.insetsChanged.Add(fun (t, b) -> dispatch (SafeAreaChanged(t, b))))
706+
701 // ── View ──
707 // ── View ──
702
708
703 let private pageContent model =
709 let private pageContent model =
@@ -712,7 +718,7 @@ module App =
712
718
713 Border(page)
719 Border(page)
714 .background(SolidColorBrush(Colors.White))
720 .background(SolidColorBrush(Colors.White))
715− .padding (Avalonia.Thickness(0., 0., 0., model.KeyboardHeight))
721+ .padding (Avalonia.Thickness(0., model.SafeAreaTop, 0., model.KeyboardHeight))
716
722
717 let view model =
723 let view model =
718#if MOBILE
724#if MOBILE
client/AppTypes.fs+5−1
@@ -60,7 +60,9 @@ module AppTypes =
60 Profile: Profile option
60 Profile: Profile option
61 FlushingOutbox: bool
61 FlushingOutbox: bool
62 PollRetries: int
62 PollRetries: int
63− KeyboardHeight: float }
63+ KeyboardHeight: float
64+ SafeAreaTop: float
65+ SafeAreaBottom: float }
64
66
65 // ── Msg ──
67 // ── Msg ──
66
68
@@ -86,6 +88,7 @@ module AppTypes =
86 | Search of string
88 | Search of string
87 | TokenExpired
89 | TokenExpired
88 | KeyboardHeightChanged of float
90 | KeyboardHeightChanged of float
91+ | SafeAreaChanged of top: float * bottom: float
89 | DoScanQR
92 | DoScanQR
90 | QRScanned of string option
93 | QRScanned of string option
91
94
@@ -103,6 +106,7 @@ module AppTypes =
103 | CmdPickPhoto
106 | CmdPickPhoto
104 | CmdSaveProfile of Profile
107 | CmdSaveProfile of Profile
105 | CmdSubscribeKeyboard
108 | CmdSubscribeKeyboard
109+ | CmdSubscribeSafeArea
106 | CmdScanQR
110 | CmdScanQR
107
111
108 // ── Shared Helpers ──
112 // ── Shared Helpers ──
client/Keyboard.fs+5
@@ -4,3 +4,8 @@ module Keyboard =
4 let private evt = Event<float>()
4 let private evt = Event<float>()
5 let heightChanged = evt.Publish
5 let heightChanged = evt.Publish
6 let triggerHeightChanged h = evt.Trigger h
6 let triggerHeightChanged h = evt.Trigger h
7+
8+module SafeArea =
9+ let private evt = Event<float * float>()
10+ let insetsChanged = evt.Publish
11+ let triggerInsetsChanged (top, bottom) = evt.Trigger(top, bottom)
client/Platform/iOS/AppDelegate.fs+15−2
@@ -12,10 +12,23 @@ open Skrepka
12type AppDelegate() =
12type AppDelegate() =
13 inherit AvaloniaAppDelegate<FabApplication>()
13 inherit AvaloniaAppDelegate<FabApplication>()
14
14
15+ let readSafeArea () =
16+ let w = UIApplication.SharedApplication.KeyWindow
17+ if not (isNull w) then
18+ SafeArea.triggerInsetsChanged(float w.SafeAreaInsets.Top, float w.SafeAreaInsets.Bottom)
19+
15 override this.CreateAppBuilder() =
20 override this.CreateAppBuilder() =
16− NSTimer.CreateScheduledTimer(0.0, false, fun _ ->
21+ NSTimer.CreateScheduledTimer(0.1, false, fun _ ->
17 if this.Window <> null then
22 if this.Window <> null then
18− this.Window.BackgroundColor <- UIColor.White)
23+ this.Window.BackgroundColor <- UIColor.White
24+ readSafeArea())
25+ |> ignore
26+
27+ UIDevice.CurrentDevice.BeginGeneratingDeviceOrientationNotifications()
28+ NSNotificationCenter.DefaultCenter.AddObserver(
29+ UIDevice.OrientationDidChangeNotification,
30+ Action<NSNotification>(fun _ ->
31+ NSTimer.CreateScheduledTimer(0.1, false, fun _ -> readSafeArea()) |> ignore))
19 |> ignore
32 |> ignore
20
33
21 NSNotificationCenter.DefaultCenter.AddObserver(
34 NSNotificationCenter.DefaultCenter.AddObserver(
client/Styles.fs+2−1
@@ -20,7 +20,7 @@ module Styles =
20
20
21 s :> IStyle
21 s :> IStyle
22
22
23− let withBottomBar (bar: WidgetBuilder<'msg, 'a>) (content: WidgetBuilder<'msg, 'b>) =
23+ let withBottomBar safeAreaBottom (bar: WidgetBuilder<'msg, 'a>) (content: WidgetBuilder<'msg, 'b>) =
24 Grid([], [ Dimension.Star; Dimension.Auto ]) {
24 Grid([], [ Dimension.Star; Dimension.Auto ]) {
25 AnyView(content).gridRow (0)
25 AnyView(content).gridRow (0)
26
26
@@ -28,6 +28,7 @@ module Styles =
28 .borderThickness(Avalonia.Thickness(0., 4., 0., 0.))
28 .borderThickness(Avalonia.Thickness(0., 4., 0., 0.))
29 .borderBrush(SolidColorBrush(Colors.Black))
29 .borderBrush(SolidColorBrush(Colors.Black))
30 .background(Constants.accentColor)
30 .background(Constants.accentColor)
31+ .padding(Avalonia.Thickness(0., 0., 0., safeAreaBottom))
31 .gridRow (1)
32 .gridRow (1)
32 }
33 }
33
34
client/ViewAddContact.fs+1−1
@@ -67,4 +67,4 @@ module ViewAddContact =
67
67
68 let bar = HStack(8.) { backButton (SetPage Conversations) }
68 let bar = HStack(8.) { backButton (SetPage Conversations) }
69
69
70− withBottomBar bar content
70+ withBottomBar model.SafeAreaBottom bar content
client/ViewChat.fs+2−1
@@ -168,4 +168,5 @@ module ViewChat =
168 msgView).gridRow (2)
168 msgView).gridRow (2)
169 })
169 })
170
170
171+ let barInset = if model.KeyboardHeight > 0. then 0. else model.SafeAreaBottom
171− Styles.withBottomBar bar content
172+ Styles.withBottomBar barInset bar content
client/ViewConversations.fs+1−1
@@ -98,4 +98,4 @@ module ViewConversations =
98 .horizontalAlignment (HorizontalAlignment.Stretch)
98 .horizontalAlignment (HorizontalAlignment.Stretch)
99 }
99 }
100
100
101− withBottomBar bar content
101+ withBottomBar model.SafeAreaBottom bar content
client/ViewEditProfile.fs+1−1
@@ -38,4 +38,4 @@ module ViewEditProfile =
38 (button Secondary "save" DoSaveProfile).margin (8.)
38 (button Secondary "save" DoSaveProfile).margin (8.)
39 }
39 }
40
40
41− withBottomBar bar content
41+ withBottomBar model.SafeAreaBottom bar content