Skip to content

Commit c87eb06

Browse files
committed
code preview
1 parent 59ef714 commit c87eb06

904 files changed

Lines changed: 107047 additions & 25 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

ZLGitHubClient/ZLGitHubClient.xcodeproj/project.pbxproj

Lines changed: 2225 additions & 21 deletions
Large diffs are not rendered by default.
Lines changed: 376 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,376 @@
1+
//
2+
// ZLRepoCodePreview4Controller.swift
3+
// ZLGitHubClient
4+
//
5+
// Created by 朱猛 on 2020/7/14.
6+
// Copyright © 2020 ZM. All rights reserved.
7+
//
8+
9+
import UIKit
10+
import WebKit
11+
import ZLUIUtilities
12+
import ZLBaseExtension
13+
import ZLGitRemoteService
14+
import ZLUtilities
15+
import ZMMVVM
16+
17+
/**
18+
* 利用 REST API 获取 md 内容 ; 代码使用markdown接口渲染
19+
*/
20+
21+
class ZLRepoCodePreview4Controller: ZMViewController {
22+
23+
// model
24+
let contentModel: ZLGithubContentModel
25+
let repoFullName: String
26+
let branch: String
27+
28+
var htmlStr: String?
29+
var rawContent: String?
30+
31+
var theme: String = "vs"
32+
33+
34+
init(repoFullName: String, contentModel: ZLGithubContentModel, branch: String) {
35+
self.repoFullName = repoFullName
36+
self.contentModel = contentModel
37+
self.branch = branch
38+
super.init(nibName: nil, bundle: nil)
39+
}
40+
41+
required init?(coder: NSCoder) {
42+
fatalError("init(coder:) has not been implemented")
43+
}
44+
45+
deinit {
46+
NotificationCenter.default.removeObserver(self, name: ZLUserInterfaceStyleChange_Notification, object: nil)
47+
}
48+
49+
override func viewDidLoad() {
50+
super.viewDidLoad()
51+
requestRawFileContent()
52+
}
53+
54+
override func viewDidAppear(_ animated: Bool) {
55+
super.viewDidAppear(animated)
56+
57+
if ZLDeviceInfo.isIPhone() {
58+
guard let appdelegate: AppDelegate = UIApplication.shared.delegate as? AppDelegate else {
59+
return
60+
}
61+
appdelegate.allowRotation = true
62+
}
63+
}
64+
65+
override func viewWillDisappear(_ animated: Bool) {
66+
super.viewWillDisappear(animated)
67+
68+
if ZLDeviceInfo.isIPhone() {
69+
guard let appdelegate: AppDelegate = UIApplication.shared.delegate as? AppDelegate else {
70+
return
71+
}
72+
appdelegate.allowRotation = false
73+
}
74+
}
75+
76+
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
77+
78+
super.viewWillTransition(to: size, with: coordinator)
79+
80+
if ZLDeviceInfo.isIPhone() {
81+
guard let navigationVC: ZMNavigationController = self.navigationController as? ZMNavigationController else {
82+
return
83+
}
84+
if size.height > size.width {
85+
// 横屏变竖屏
86+
self.isZmNavigationBarHidden = false
87+
navigationVC.forbidGestureBack = false
88+
} else {
89+
self.isZmNavigationBarHidden = true
90+
navigationVC.forbidGestureBack = true
91+
}
92+
}
93+
}
94+
95+
override func setupUI() {
96+
super.setupUI()
97+
self.title = self.contentModel.path
98+
99+
self.zmNavigationBar.backButton.isHidden = false
100+
self.zmNavigationBar.addRightView(moreButton)
101+
102+
self.contentView.addSubview(webView)
103+
webView.snp.makeConstraints({(make) in
104+
make.edges.equalToSuperview()
105+
})
106+
107+
self.contentView.addSubview(switchButton)
108+
109+
switchButton.snp.makeConstraints { make in
110+
make.left.equalTo(20)
111+
make.top.equalTo(20)
112+
make.width.equalTo(60)
113+
make.height.equalTo(30)
114+
}
115+
}
116+
117+
// view
118+
lazy var webView: WKWebView = {
119+
let wv = WKWebView(frame: CGRect.init())
120+
wv.backgroundColor = UIColor.clear
121+
wv.scrollView.backgroundColor = UIColor.clear
122+
wv.scrollView.bounces = false
123+
wv.uiDelegate = self
124+
wv.navigationDelegate = self
125+
return wv
126+
}()
127+
128+
lazy var moreButton: UIButton = {
129+
let button = UIButton.init(type: .custom)
130+
button.setAttributedTitle(NSAttributedString(string: ZLIconFont.More.rawValue,
131+
attributes: [.font: UIFont.zlIconFont(withSize: 30),
132+
.foregroundColor: UIColor.label(withName: "ICON_Common")]),
133+
for: .normal)
134+
button.snp.makeConstraints({ make in
135+
make.size.equalTo(60)
136+
})
137+
button.addTarget(self, action: #selector(onMoreButtonClick(button:)), for: .touchUpInside)
138+
return button
139+
}()
140+
141+
lazy var switchButton: UIButton = {
142+
let button = ZMButton()
143+
button.setTitle("切换主题", for: .normal)
144+
button.addTarget(self, action: #selector(onSwitchButtonClick(button:)), for: .touchUpInside)
145+
return button
146+
}()
147+
}
148+
149+
extension ZLRepoCodePreview4Controller {
150+
151+
static func getThemeSelectView() -> ZMSingleSelectTitlePopView {
152+
/// 开发语言选择
153+
let dateRangeSelectView = ZMSingleSelectTitlePopView()
154+
dateRangeSelectView.frame = UIScreen.main.bounds
155+
let title = "主题"
156+
dateRangeSelectView.titleLabel.text = title
157+
let placeHolder = "筛选主题"
158+
.asMutableAttributedString()
159+
.font(.zlRegularFont(withSize: 12))
160+
.foregroundColor(ZLRGBValue_H(colorValue: 0xCED1D6))
161+
dateRangeSelectView.textField.attributedPlaceholder = placeHolder
162+
dateRangeSelectView.contentWidth = 280
163+
dateRangeSelectView.contentHeight = 500
164+
dateRangeSelectView.collectionView.lineSpacing = .leastNonzeroMagnitude
165+
dateRangeSelectView.collectionView.interitemSpacing = .leastNonzeroMagnitude
166+
dateRangeSelectView.collectionView.itemSize = CGSize(width: 280, height: 50)
167+
dateRangeSelectView.popDelegate = ZMLanguageSelectView.popDelegate
168+
return dateRangeSelectView
169+
}
170+
171+
/// 弹出开发语言选择框
172+
static func showThemeSelectView(to: UIView,
173+
theme: String?,
174+
resultBlock : @escaping ((String?) -> Void)) {
175+
176+
177+
let themes = [
178+
"1c-light",
179+
"a11y-dark",
180+
"a11y-light",
181+
"agate",
182+
"an-old-hope",
183+
"androidstudio",
184+
"arduino-light",
185+
"arta",
186+
"ascetic",
187+
"atom-one-dark-reasonable",
188+
"atom-one-dark",
189+
"atom-one-light",
190+
"brown-paper",
191+
"codepen-embed",
192+
"color-brewer",
193+
"cybertopia-cherry",
194+
"cybertopia-dimmer",
195+
"cybertopia-icecap",
196+
"cybertopia-saturated",
197+
"dark",
198+
"default",
199+
"devibeans",
200+
"docco",
201+
"far",
202+
"felipec",
203+
"foundation",
204+
"github-dark-dimmed",
205+
"github-dark",
206+
"github",
207+
"gml",
208+
"googlecode",
209+
"gradient-dark",
210+
"gradient-light",
211+
"grayscale",
212+
"hybrid",
213+
"idea",
214+
"intellij-light",
215+
"ir-black",
216+
"isbl-editor-dark",
217+
"isbl-editor-light",
218+
"kimbie-dark",
219+
"kimbie-light",
220+
"lightfair",
221+
"lioshi",
222+
"magula",
223+
"mono-blue",
224+
"monokai-sublime",
225+
"monokai",
226+
"night-owl",
227+
"nnfx-dark",
228+
"nnfx-light",
229+
"nord",
230+
"obsidian",
231+
"panda-syntax-dark",
232+
"panda-syntax-light",
233+
"paraiso-dark",
234+
"paraiso-light",
235+
"pojoaque",
236+
"purebasic",
237+
"qtcreator-dark",
238+
"qtcreator-light",
239+
"rainbow",
240+
"rose-pine-dawn",
241+
"rose-pine-moon",
242+
"rose-pine",
243+
"routeros",
244+
"school-book",
245+
"shades-of-purple",
246+
"srcery",
247+
"stackoverflow-dark",
248+
"stackoverflow-light",
249+
"sunburst",
250+
"tokyo-night-dark",
251+
"tokyo-night-light",
252+
"tomorrow-night-blue",
253+
"tomorrow-night-bright",
254+
"vs",
255+
"vs2015",
256+
"xcode",
257+
"xt256"
258+
]
259+
var selectedIndex = themes.firstIndex(of: theme ?? "") ?? 0
260+
261+
262+
Self.getThemeSelectView()
263+
.showSingleSelectTitleBox(to,
264+
contentPoition: .center,
265+
animationDuration: 0.1,
266+
titles: themes,
267+
selectedIndex: selectedIndex,
268+
cellType: ZMDevelopmentLanguageSelectTickCell.self)
269+
{ index, title in
270+
resultBlock(title)
271+
}
272+
273+
}
274+
275+
}
276+
277+
// MARK: - Action
278+
extension ZLRepoCodePreview4Controller {
279+
280+
@objc func onMoreButtonClick(button: UIButton) {
281+
282+
guard let url = URL(string: self.contentModel.html_url) else {
283+
return
284+
}
285+
button.showShareMenu(title: url.absoluteString, url: url, sourceViewController: self )
286+
}
287+
288+
@objc func onSwitchButtonClick(button: UIButton) {
289+
Self.showThemeSelectView(to: self.view, theme: self.theme) { [weak self] theme in
290+
guard let self else { return }
291+
self.theme = theme ?? ""
292+
self.generateHTML(rawContent: self.rawContent ?? "")
293+
self.startLoadCode()
294+
295+
}
296+
}
297+
}
298+
299+
// MARK: - Request
300+
extension ZLRepoCodePreview4Controller {
301+
302+
func generateHTML(rawContent: String) {
303+
let htmlURL: URL? = Bundle.main.url(forResource: "highlight", withExtension: "html")
304+
305+
if let url = htmlURL {
306+
307+
do {
308+
let htmlStr = try String.init(contentsOf: url)
309+
let newHtmlStr = NSMutableString.init(string: htmlStr)
310+
311+
let headRange = (newHtmlStr as NSString).range(of: "</head>")
312+
if headRange.location != NSNotFound {
313+
newHtmlStr.insert("<link rel=\"stylesheet\" href=\"./\(self.theme).min.css\">", at: headRange.location)
314+
}
315+
316+
let codeRange = (newHtmlStr as NSString).range(of: "</code>")
317+
if codeRange.location != NSNotFound {
318+
newHtmlStr.insert(rawContent.htmlEscaped(), at: codeRange.location)
319+
}
320+
321+
self.htmlStr = newHtmlStr as String
322+
323+
} catch {
324+
ZLToastView.showMessage("load Code index html failed")
325+
}
326+
}
327+
}
328+
329+
func startLoadCode() {
330+
webView.loadHTMLString(self.htmlStr ?? "", baseURL: Bundle.main.bundleURL)
331+
}
332+
}
333+
334+
// MARK: - Request
335+
extension ZLRepoCodePreview4Controller {
336+
func requestRawFileContent() {
337+
338+
self.view.showProgressHUD()
339+
ZLRepoServiceShared()?.getRepositoryFileRawInfo(withFullName: self.repoFullName,
340+
path: self.contentModel.path,
341+
branch: self.branch,
342+
serialNumber: NSString.generateSerialNumber())
343+
{[weak self] (resultModel: ZLOperationResultModel) in
344+
345+
guard let self = self else { return }
346+
self.view.dismissProgressHUD()
347+
348+
if resultModel.result,
349+
let data: String = resultModel.data as? String {
350+
self.rawContent = data
351+
self.generateHTML(rawContent: data)
352+
self.startLoadCode()
353+
} else {
354+
if let errorModel = resultModel.data as? ZLGithubRequestErrorModel {
355+
ZLToastView.showMessage(errorModel.message)
356+
}
357+
}
358+
}
359+
}
360+
}
361+
362+
extension ZLRepoCodePreview4Controller: WKUIDelegate, WKNavigationDelegate {
363+
364+
}
365+
366+
367+
extension String {
368+
func htmlEscaped() -> String {
369+
return self
370+
.replacingOccurrences(of: "&", with: "&amp;")
371+
.replacingOccurrences(of: "<", with: "&lt;")
372+
.replacingOccurrences(of: ">", with: "&gt;")
373+
.replacingOccurrences(of: "\"", with: "&quot;")
374+
.replacingOccurrences(of: "'", with: "&#39;")
375+
}
376+
}

ZLGitHubClient/ZLGitHubClient/Class/UI/repo/ZLRepoContentController/viewcontroller/ZLRepoContentController.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,9 @@ extension ZLRepoContentController: UITableViewDelegate, UITableViewDataSource {
271271
self.currentContentNode = self.currentContentNode?.subNodes?[indexPath.row]
272272
self.reloadData()
273273
} else if "file" == contentModel.type {
274-
let controller = ZLRepoCodePreview3Controller()
275-
controller.repoFullName = repoFullName ?? ""
276-
controller.path = contentModel.path
277-
controller.branch = branch ?? ""
274+
let controller = ZLRepoCodePreview4Controller(repoFullName: repoFullName ?? "",
275+
contentModel: contentModel,
276+
branch: branch ?? "")
278277
self.navigationController?.pushViewController(controller, animated: true)
279278
}
280279
}
Binary file not shown.

0 commit comments

Comments
 (0)