193 lines
7.8 KiB
Swift
193 lines
7.8 KiB
Swift
@preconcurrency import SwiftUI
|
|
@preconcurrency import WebKit
|
|
|
|
struct BulletinView: View {
|
|
@State private var isLoading = true
|
|
@Environment(\.dismiss) private var dismiss
|
|
|
|
var body: some View {
|
|
WebViewWithRefresh(url: URL(string: "https://rtsda.updates.church")!, isLoading: $isLoading)
|
|
.navigationTitle("Bulletin")
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.background(Color(uiColor: .systemBackground))
|
|
.toolbar {
|
|
ToolbarItem(placement: .navigationBarLeading) {
|
|
if isLoading {
|
|
ProgressView()
|
|
.progressViewStyle(.circular)
|
|
}
|
|
}
|
|
ToolbarItem(placement: .navigationBarTrailing) {
|
|
Button(action: {
|
|
dismiss()
|
|
}) {
|
|
Image(systemName: "xmark")
|
|
.foregroundColor(.primary)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
struct WebViewWithRefresh: UIViewRepresentable {
|
|
let url: URL
|
|
@Binding var isLoading: Bool
|
|
|
|
func makeCoordinator() -> Coordinator {
|
|
Coordinator(self)
|
|
}
|
|
|
|
func makeUIView(context: Context) -> WKWebView {
|
|
let configuration = WKWebViewConfiguration()
|
|
let webView = WKWebView(frame: .zero, configuration: configuration)
|
|
webView.navigationDelegate = context.coordinator
|
|
|
|
// Add swipe gesture recognizer
|
|
let swipeGesture = UISwipeGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleSwipe(_:)))
|
|
swipeGesture.direction = .right
|
|
webView.addGestureRecognizer(swipeGesture)
|
|
|
|
// Configure refresh control with custom appearance
|
|
let refreshControl = UIRefreshControl()
|
|
refreshControl.addTarget(context.coordinator,
|
|
action: #selector(Coordinator.handleRefresh),
|
|
for: .valueChanged)
|
|
// Set the refresh control's background color
|
|
refreshControl.backgroundColor = .clear
|
|
webView.scrollView.refreshControl = refreshControl
|
|
|
|
// Set background colors
|
|
webView.isOpaque = false
|
|
webView.backgroundColor = .clear
|
|
webView.scrollView.backgroundColor = .clear
|
|
|
|
let request = URLRequest(url: url)
|
|
webView.load(request)
|
|
return webView
|
|
}
|
|
|
|
func updateUIView(_ webView: WKWebView, context: Context) {
|
|
// No updates needed
|
|
}
|
|
|
|
class Coordinator: NSObject, WKNavigationDelegate {
|
|
var parent: WebViewWithRefresh
|
|
|
|
init(_ parent: WebViewWithRefresh) {
|
|
self.parent = parent
|
|
}
|
|
|
|
@objc func handleSwipe(_ gesture: UISwipeGestureRecognizer) {
|
|
print("🔄 Swipe detected")
|
|
if gesture.state == .ended {
|
|
if let webView = gesture.view as? WKWebView {
|
|
print("📱 Attempting to trigger back action")
|
|
|
|
// JavaScript to click the Chakra UI back button
|
|
let script = """
|
|
function findBackButton() {
|
|
// Common back button selectors
|
|
var selectors = [
|
|
'button[aria-label="Go back"]',
|
|
'button.chakra-button[aria-label*="back"]',
|
|
'button.chakra-button svg[aria-label*="back"]',
|
|
'button.chakra-button span svg[aria-hidden="true"]',
|
|
'button svg[data-icon="arrow-left"]',
|
|
'button.chakra-button svg',
|
|
'button.chakra-button'
|
|
];
|
|
|
|
for (var i = 0; i < selectors.length; i++) {
|
|
var buttons = document.querySelectorAll(selectors[i]);
|
|
for (var j = 0; j < buttons.length; j++) {
|
|
var button = buttons[j];
|
|
// Check if it looks like a back button
|
|
if (button.textContent.toLowerCase().includes('back') ||
|
|
button.getAttribute('aria-label')?.toLowerCase().includes('back') ||
|
|
button.innerHTML.toLowerCase().includes('back')) {
|
|
console.log('Found back button:', button.outerHTML);
|
|
return button;
|
|
}
|
|
}
|
|
}
|
|
console.log('No back button found');
|
|
return null;
|
|
}
|
|
|
|
var backButton = findBackButton();
|
|
if (backButton) {
|
|
backButton.click();
|
|
true;
|
|
} else {
|
|
false;
|
|
}
|
|
"""
|
|
|
|
webView.evaluateJavaScript(script) { result, error in
|
|
if let error = error {
|
|
print("❌ JavaScript error: \(error.localizedDescription)")
|
|
} else if let success = result as? Bool {
|
|
print(success ? "✅ Back button clicked" : "❌ No back button found")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@objc func handleRefresh(sender: UIRefreshControl) {
|
|
parent.isLoading = true
|
|
if let webView = sender.superview?.superview as? WKWebView {
|
|
// Clear all website data
|
|
WKWebsiteDataStore.default().removeData(
|
|
ofTypes: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache],
|
|
modifiedSince: Date(timeIntervalSince1970: 0)
|
|
) {
|
|
DispatchQueue.main.async {
|
|
// Create a fresh request
|
|
if let url = webView.url {
|
|
let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData)
|
|
webView.load(request)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Navigation delegate methods
|
|
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
|
|
parent.isLoading = true
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
|
parent.isLoading = false
|
|
webView.scrollView.refreshControl?.endRefreshing()
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
|
|
parent.isLoading = false
|
|
webView.scrollView.refreshControl?.endRefreshing()
|
|
}
|
|
|
|
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
|
parent.isLoading = false
|
|
webView.scrollView.refreshControl?.endRefreshing()
|
|
}
|
|
|
|
// Handle back navigation
|
|
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
|
if navigationAction.navigationType == .backForward {
|
|
decisionHandler(.cancel)
|
|
parent.isLoading = false
|
|
return
|
|
}
|
|
decisionHandler(.allow)
|
|
}
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
NavigationStack {
|
|
BulletinView()
|
|
}
|
|
}
|