RedditWebViewManager.swift 3.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. import AppKit
  2. import WebKit
  3. @MainActor
  4. enum RedditWebViewManager {
  5. private static let processPool = WKProcessPool()
  6. static func makeConfiguration(includeLoginBridge: Bool = true) -> WKWebViewConfiguration {
  7. let configuration = WKWebViewConfiguration()
  8. configuration.processPool = processPool
  9. configuration.websiteDataStore = .default()
  10. configuration.defaultWebpagePreferences.allowsContentJavaScript = true
  11. configuration.preferences.isElementFullscreenEnabled = true
  12. let isDarkMode = AppearanceManager.shared.isDarkMode
  13. let themeScript = WKUserScript(
  14. source: RedditThemeStyle.earlyInjectionScript(isDarkMode: isDarkMode),
  15. injectionTime: .atDocumentStart,
  16. forMainFrameOnly: true
  17. )
  18. configuration.userContentController.addUserScript(themeScript)
  19. let boundaryScript = WKUserScript(
  20. source: RedditPostBoundaryStyle.injectionScript,
  21. injectionTime: .atDocumentEnd,
  22. forMainFrameOnly: true
  23. )
  24. configuration.userContentController.addUserScript(boundaryScript)
  25. let chromeScript = WKUserScript(
  26. source: RedditHomeChromeStyle.injectionScript,
  27. injectionTime: .atDocumentStart,
  28. forMainFrameOnly: true
  29. )
  30. configuration.userContentController.addUserScript(chromeScript)
  31. let authChromeScript = WKUserScript(
  32. source: RedditAuthChromeStyle.injectionScript,
  33. injectionTime: .atDocumentStart,
  34. forMainFrameOnly: false
  35. )
  36. configuration.userContentController.addUserScript(authChromeScript)
  37. let shareBridgeScript = WKUserScript(
  38. source: RedditShareBridgeStyle.injectionScript,
  39. injectionTime: .atDocumentStart,
  40. forMainFrameOnly: true
  41. )
  42. configuration.userContentController.addUserScript(shareBridgeScript)
  43. configuration.userContentController.add(
  44. RedditShareScriptBridge.shared,
  45. name: RedditShareBridgeStyle.messageHandlerName
  46. )
  47. if includeLoginBridge {
  48. let loginBridgeScript = WKUserScript(
  49. source: RedditLoginBridgeStyle.injectionScript,
  50. injectionTime: .atDocumentStart,
  51. forMainFrameOnly: true
  52. )
  53. configuration.userContentController.addUserScript(loginBridgeScript)
  54. configuration.userContentController.add(
  55. RedditLoginScriptBridge.shared,
  56. name: RedditLoginBridgeStyle.messageHandlerName
  57. )
  58. }
  59. return configuration
  60. }
  61. static func makeWebView() -> WKWebView {
  62. let webView = WKWebView(frame: .zero, configuration: makeConfiguration())
  63. webView.allowsBackForwardNavigationGestures = true
  64. webView.allowsMagnification = true
  65. // Use the default WKWebView user agent instead of spoofing Safari.
  66. let isDarkMode = AppearanceManager.shared.isDarkMode
  67. applyTheme(to: webView, isDarkMode: isDarkMode)
  68. return webView
  69. }
  70. static func applyTheme(to webView: WKWebView, isDarkMode: Bool) {
  71. applyAppearance(to: webView, isDarkMode: isDarkMode)
  72. applyUnderPageBackground(to: webView, isDarkMode: isDarkMode)
  73. webView.evaluateJavaScript(
  74. RedditThemeStyle.syncScript(isDarkMode: isDarkMode),
  75. completionHandler: nil
  76. )
  77. }
  78. static func applyAppearance(to webView: WKWebView, isDarkMode: Bool) {
  79. let appearanceName: NSAppearance.Name = isDarkMode ? .darkAqua : .aqua
  80. webView.appearance = NSAppearance(named: appearanceName)
  81. }
  82. static func applyUnderPageBackground(to webView: WKWebView, isDarkMode: Bool) {
  83. webView.underPageBackgroundColor = AppearanceManager.webUnderPageBackgroundColor(isDarkMode: isDarkMode)
  84. }
  85. }