Skip to content

Commit

Permalink
Fix layout issues in timeline poll cells (PSB-125)
Browse files Browse the repository at this point in the history
Fixes: #5326
Signed-off-by: Johannes Marbach <johannesm@element.io>
  • Loading branch information
Johennes committed Jul 5, 2022
1 parent 67249ac commit 62033f0
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 1 deletion.
91 changes: 91 additions & 0 deletions Riot/Modules/Common/SwiftUI/VectorHostingController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ class VectorHostingController: UIHostingController<AnyView> {

var isNavigationBarHidden: Bool = false
var hidesBackTitleWhenPushed: Bool = false

var forceZeroSafeAreaInsets: Bool {
get {
self.view.forceZeroSafeAreaInsets
}
set {
self.view.forceZeroSafeAreaInsets = newValue
}
}

private var theme: Theme

// MARK: Public
Expand All @@ -43,6 +53,7 @@ class VectorHostingController: UIHostingController<AnyView> {
init<Content>(rootView: Content) where Content: View {
self.theme = ThemeService.shared().theme
super.init(rootView: AnyView(rootView.vectorContent()))
self.view.swizzleSafeAreaMethodsIfNeeded()
}

required init?(coder aDecoder: NSCoder) {
Expand Down Expand Up @@ -103,3 +114,83 @@ class VectorHostingController: UIHostingController<AnyView> {
}
}
}

// Hack for forcing zero safe area insets on hosting views. This problem occurs when the hosting view is embedded
// in a table view. See https://stackoverflow.com/questions/61552497 for further info.

private var hasSwizzledSafeAreaMethods = false
private var forceZeroSafeAreaInsetsKey: Void?

private extension UIView {

var forceZeroSafeAreaInsets: Bool {
get {
return objc_getAssociatedObject(self, &forceZeroSafeAreaInsetsKey) as? Bool == true
}
set {
objc_setAssociatedObject(self, &forceZeroSafeAreaInsetsKey, newValue, .OBJC_ASSOCIATION_RETAIN)
}
}

@objc private var _safeAreaInsets: UIEdgeInsets {
return forceZeroSafeAreaInsets ? .zero : self._safeAreaInsets
}

@objc private var _safeAreaLayoutGuide: UILayoutGuide? {
return forceZeroSafeAreaInsets ? nil : self._safeAreaLayoutGuide
}

func swizzleSafeAreaMethodsIfNeeded() {
guard !hasSwizzledSafeAreaMethods else {
return
}
hasSwizzledSafeAreaMethods = true

guard let getSafeAreaInsets = class_getInstanceMethod(classForCoder.self, #selector(getter: UIView.safeAreaInsets)) else {
return
}

guard let _getSafeAreaInsets = class_getInstanceMethod(classForCoder.self, #selector(getter: UIView._safeAreaInsets)) else {
return
}

let getSafeAreaInsetsImplementation = method_getImplementation(getSafeAreaInsets)
let _getSafeAreaInsetsImplementation = method_getImplementation(_getSafeAreaInsets)

class_replaceMethod(
classForCoder,
#selector(getter: UIView.safeAreaInsets),
_getSafeAreaInsetsImplementation,
method_getTypeEncoding(getSafeAreaInsets))

class_replaceMethod(
classForCoder,
#selector(getter: UIView._safeAreaInsets),
getSafeAreaInsetsImplementation,
method_getTypeEncoding(_getSafeAreaInsets))

guard let getSafeAreaLayoutGuide = class_getInstanceMethod(classForCoder.self, #selector(getter: UIView.safeAreaLayoutGuide)) else {
return
}

guard let _getSafeAreaLayoutGuide = class_getInstanceMethod(classForCoder.self, #selector(getter: UIView._safeAreaLayoutGuide)) else {
return
}

let getSafeAreaLayoutGuideImplementation = method_getImplementation(getSafeAreaLayoutGuide)
let _getSafeAreaLayoutGuideImplementation = method_getImplementation(_getSafeAreaLayoutGuide)

class_replaceMethod(
classForCoder,
#selector(getter: UIView.safeAreaLayoutGuide),
_getSafeAreaLayoutGuideImplementation,
method_getTypeEncoding(getSafeAreaLayoutGuide))

class_replaceMethod(
classForCoder,
#selector(getter: UIView._safeAreaLayoutGuide),
getSafeAreaLayoutGuideImplementation,
method_getTypeEncoding(_getSafeAreaLayoutGuide))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,9 @@ final class TimelinePollCoordinator: Coordinator, Presentable, PollAggregatorDel
}

func toPresentable() -> UIViewController {
return VectorHostingController(rootView: TimelinePollView(viewModel: viewModel.context))
let controller = VectorHostingController(rootView: TimelinePollView(viewModel: viewModel.context))
controller.forceZeroSafeAreaInsets = true
return controller
}

func canEndPoll() -> Bool {
Expand Down
1 change: 1 addition & 0 deletions changelog.d/5326.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix layout issues in timeline poll cells (PSB-125)

0 comments on commit 62033f0

Please sign in to comment.