Skip to content

Instantly share code, notes, and snippets.

@ayaysir
Created April 7, 2023 07:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ayaysir/925f2497e33efe252836300c575b334a to your computer and use it in GitHub Desktop.
Save ayaysir/925f2497e33efe252836300c575b334a to your computer and use it in GitHub Desktop.
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)
}
}
//
// 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