Created
April 7, 2023 07:01
-
-
Save ayaysir/925f2497e33efe252836300c575b334a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
import WebKit | |
import Combine | |
/* | |
https://stackoverflow.com/questions/66581811/call-evaluatejavascript-from-a-swiftui-button | |
*/ | |
class WebViewData: ObservableObject { | |
var functionCaller = PassthroughSubject<String, Never>() | |
var shouldUpdateView = true | |
} | |
struct WebView: UIViewRepresentable { | |
typealias UIViewType = WKWebView | |
var url: URL? | |
@StateObject var data: WebViewData | |
func makeUIView(context: Context) -> UIViewType { | |
let preferences = WKPreferences() | |
preferences.javaScriptCanOpenWindowsAutomatically = false // JavaScript가 사용자 상호 작용없이 창을 열 수 있는지 여부 | |
let configuration = WKWebViewConfiguration() | |
configuration.preferences = preferences | |
let webView = WKWebView(frame: CGRect.zero, configuration: configuration) | |
webView.allowsBackForwardNavigationGestures = true // 가로로 스와이프 동작이 페이지 탐색을 앞뒤로 트리거하는지 여부 | |
webView.scrollView.isScrollEnabled = true // 웹보기와 관련된 스크롤보기에서 스크롤 가능 여부 | |
if let url = url { | |
webView.load(URLRequest(url: url)) // 지정된 URL 요청 개체에서 참조하는 웹 콘텐츠를 로드하고 탐색 | |
} | |
return webView | |
} | |
func updateUIView(_ uiView: UIViewType, context: Context) { | |
guard data.shouldUpdateView else { | |
data.shouldUpdateView = false | |
return | |
} | |
context.coordinator.tieFunctionCaller(data: data) | |
context.coordinator.webView = uiView | |
} | |
func makeCoordinator() -> Coordinator { | |
return Coordinator(self) | |
} | |
class Coordinator: NSObject, WKNavigationDelegate { | |
/// WebView Representable | |
var parentWebView: WebView | |
var webView: WKWebView? = nil | |
private var cancellable: AnyCancellable? | |
init(_ parentWebView: WebView) { | |
self.parentWebView = parentWebView | |
super.init() | |
} | |
func tieFunctionCaller(data: WebViewData) { | |
cancellable = data.functionCaller.sink(receiveValue: { js in | |
self.webView?.evaluateJavaScript(js) | |
}) | |
} | |
} | |
} | |
struct WebView_Previews: PreviewProvider { | |
static var previews: some View { | |
let url = URL(string: "https://google.com") | |
let webViewData = WebViewData() | |
WebView(url: url, data: webViewData) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// BodyView.swift | |
// Story One | |
// | |
// Created by 윤범태 on 2023/03/25. | |
// | |
import SwiftUI | |
struct BodyView: View { | |
@Binding var isTodoStateChanged: Bool | |
@State var chordTodo: ChordTodo | |
@State var showRemoveAlert = false | |
@State var showUpdateForm = false | |
@StateObject var webViewData = WebViewData() | |
@Environment(\.dismiss) var dismiss | |
var body: some View { | |
VStack { | |
Text(chordTodo.title) | |
.font(.largeTitle) | |
Divider() | |
Text("코드") | |
.font(.largeTitle) | |
HStack { | |
Text(chordTodo.chord) | |
.font(.title2) | |
Button { | |
webViewData.functionCaller.send( | |
""" | |
// document.querySelector("h1").textContent = "JS Evaluated" | |
document.querySelector("button[id^='playbut']").click() | |
""" | |
) | |
} label: { | |
Image(systemName: "play.fill") | |
} | |
} | |
// 웹뷰 버그: https://developer.apple.com/forums/thread/714467?answerId=734799022#734799022 | |
WebView(url: URL(string: "https://www.scales-chords.com/chord/piano/\(chordTodo.chord.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? chordTodo.chord)"), data: webViewData) | |
Divider() | |
Text(chordTodo.comment.isEmpty ? "No Comment..." : chordTodo.comment) | |
Divider() | |
HStack { | |
Button { | |
if var list = try? UserDefaults.standard.getObject(forKey: .cfgTodoList, castTo: [ChordTodo].self) { | |
list.removeAll { $0.id == self.chordTodo.id } | |
print("deleted list", self.chordTodo.id, list) | |
try? UserDefaults.standard.setObject(list, forKey: .cfgTodoList) | |
isTodoStateChanged = true | |
dismiss() | |
} | |
} label: { | |
Text("삭제") | |
.foregroundColor(.red) | |
} | |
Spacer() | |
Button("업데이트") { | |
showUpdateForm = true | |
}.sheet(isPresented: $showUpdateForm, onDismiss: { | |
if isTodoStateChanged { | |
print("Todo on bodyView: updated") | |
// TODO: - 업데이트 완료하면 BodyView에 내용 반영되게 하기 | |
dismiss() | |
} else { | |
print("Todo on bodyView: not updated") | |
} | |
}) { | |
WriteView(isWriteSuccess: $isTodoStateChanged, mode: .update, todoTitle: chordTodo.title, chordText: chordTodo.chord, comment: chordTodo.comment, id: chordTodo.id) | |
} | |
Spacer() | |
Button("닫기") { | |
dismiss() | |
} | |
}.padding(sides: [.left, .right], value: 20) | |
} | |
} | |
} | |
struct BodyView_Previews: PreviewProvider { | |
static var previews: some View { | |
StatefulPreviewWrapper(false) { | |
BodyView(isTodoStateChanged: $0, chordTodo: ChordTodo(title: "불안하다", chord: "Cdim7", comment: "comment....")) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment