HomeContentView.swift 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. // LoopFollow
  2. // HomeContentView.swift
  3. import SwiftUI
  4. import UIKit
  5. /// A SwiftUI wrapper around MainViewController that displays the full Home screen.
  6. /// This can be used both in the tab bar and as a modal from the Menu.
  7. struct HomeContentView: View {
  8. let isModal: Bool
  9. init(isModal: Bool = false) {
  10. self.isModal = isModal
  11. }
  12. var body: some View {
  13. MainViewControllerRepresentable()
  14. // Home has no text input, yet iOS sometimes replays a stale keyboard
  15. // frame when the app returns to the foreground, which squeezes the
  16. // whole screen up by a keyboard's height until a rotation forces the
  17. // safe area to recompute. Opting out of keyboard avoidance prevents it.
  18. .ignoresSafeArea(.keyboard)
  19. }
  20. }
  21. private struct MainViewControllerRepresentable: UIViewControllerRepresentable {
  22. func makeUIViewController(context _: Context) -> UIViewController {
  23. // Reuse the single long-lived instance rather than creating a new one,
  24. // so there is exactly one data pipeline and MainViewController.shared is
  25. // never displaced. bootstrap() is a no-op if it already exists.
  26. MainViewController.bootstrap()
  27. let mainVC = MainViewController.shared!
  28. // Detach from any previous SwiftUI host (e.g. after a Menu push was
  29. // popped and is now being re-pushed) before this representable embeds it.
  30. mainVC.willMove(toParent: nil)
  31. mainVC.removeFromParent()
  32. mainVC.view.removeFromSuperview()
  33. mainVC.overrideUserInterfaceStyle = Storage.shared.appearanceMode.value.userInterfaceStyle
  34. return mainVC
  35. }
  36. func updateUIViewController(_ uiViewController: UIViewController, context _: Context) {
  37. uiViewController.overrideUserInterfaceStyle = Storage.shared.appearanceMode.value.userInterfaceStyle
  38. }
  39. }
  40. // MARK: - Modal wrapper with navigation bar
  41. struct HomeModalView: View {
  42. @Environment(\.dismiss) private var dismiss
  43. var body: some View {
  44. NavigationStack {
  45. HomeContentView(isModal: true)
  46. .navigationTitle("Home")
  47. .navigationBarTitleDisplayMode(.inline)
  48. .toolbar {
  49. ToolbarItem(placement: .cancellationAction) {
  50. Button {
  51. dismiss()
  52. } label: {
  53. Image(systemName: "xmark")
  54. }
  55. }
  56. }
  57. }
  58. .preferredColorScheme(Storage.shared.appearanceMode.value.colorScheme)
  59. }
  60. }
  61. // MARK: - Preview
  62. #Preview {
  63. HomeModalView()
  64. }