.../Source/App/JSFuncSearchPreview/JSFuncSearchViewController.swift
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // JSFuncSearchViewController.swift |
3 | | // CutBox |
4 | | // |
5 | | // Created by Jason Milkins on 17/5/18. |
6 | | // Copyright © 2018-2023 ocodo. All rights reserved. |
7 | | // |
8 | | |
9 | | import RxSwift |
10 | | |
11 | | class JSFuncSearchViewController: NSObject { |
12 | | |
13 | | var js: JSFuncService |
14 | 66 | var selectedClips: [String] = [] |
15 | | var jsFuncView: JSFuncSearchAndPreviewView |
16 | | var prefs: CutBoxPreferencesService |
17 | | var fakeKey: FakeKey |
18 | | var jsFuncPopup: PopupController |
19 | | var pasteboard: PasteboardWrapperType |
20 | | |
21 | 1 | var hasFuncs: Bool { |
22 | 1 | return !self.js.isEmpty |
23 | 1 | } |
24 | | |
25 | 1 | var count: Int { |
26 | 1 | return self.js.count |
27 | 1 | } |
28 | | |
29 | 1 | var funcList: [String] { |
30 | 1 | return self.js.funcList |
31 | 1 | } |
32 | | |
33 | 70 | var events: PublishSubject<SearchJSFuncViewEvents> { |
34 | 70 | return self.jsFuncView.events |
35 | 70 | } |
36 | | |
37 | 66 | let disposeBag = DisposeBag() |
38 | | |
39 | | init(js: JSFuncService = JSFuncService(), |
40 | | cutBoxPreferences: CutBoxPreferencesService = CutBoxPreferencesService.shared, |
41 | | fakeKey: FakeKey = FakeKey(), |
42 | | jsFuncView: JSFuncSearchAndPreviewView = JSFuncSearchAndPreviewView.fromNib()!, |
43 | 66 | pasteboard: PasteboardWrapperType = PasteboardWrapper()) { |
44 | 66 | |
45 | 66 | self.js = js |
46 | 66 | self.prefs = cutBoxPreferences |
47 | 66 | self.fakeKey = fakeKey |
48 | 66 | self.jsFuncView = jsFuncView |
49 | 66 | self.jsFuncPopup = PopupController(content: self.jsFuncView) |
50 | 66 | self.pasteboard = pasteboard |
51 | 66 | super.init() |
52 | 66 | self.setup() |
53 | 66 | } |
54 | | |
55 | 66 | func setup() { |
56 | 66 | self.configureJSPopupAndView() |
57 | 66 | self.setupSearchTextEventBindings() |
58 | 66 | self.setupSearchViewAndFilterBinding() |
59 | 66 | } |
60 | | |
61 | 66 | private func setupSearchViewAndFilterBinding() { |
62 | 66 | self.jsFuncView.itemsList?.dataSource = self |
63 | 66 | self.jsFuncView.itemsList?.delegate = self |
64 | 66 | |
65 | 66 | self.jsFuncView.filterTextPublisher |
66 | 66 | .subscribe(onNext: { |
67 | 2 | self.js.filterText = $0 |
68 | 2 | self.jsFuncView.itemsList?.reloadData() |
69 | 2 | }) |
70 | 66 | .disposed(by: self.disposeBag) |
71 | 66 | } |
72 | | |
73 | 66 | private func setupSearchTextEventBindings() { |
74 | 66 | self.events |
75 | 66 | .subscribe(onNext: { event in |
76 | 3 | switch event { |
77 | 3 | case .closeAndPaste: |
78 | 1 | self.closeAndPaste() |
79 | 3 | |
80 | 3 | case .justClose: |
81 | 1 | self.justClose() |
82 | 3 | |
83 | 3 | default: |
84 | 1 | break |
85 | 3 | } |
86 | 3 | }) |
87 | 66 | .disposed(by: disposeBag) |
88 | 66 | } |
89 | | |
90 | 2 | private func resetJSFuncSearchText() { |
91 | 2 | self.jsFuncView.searchText?.string = "" |
92 | 2 | self.jsFuncView.filterTextPublisher.onNext("") |
93 | 2 | self.jsFuncView.itemsList?.reloadData() |
94 | 2 | } |
95 | | |
96 | 1 | @objc func fakePaste() { |
97 | 1 | fakeKey.send(fakeKey: "V", useCommandFlag: true) |
98 | 1 | } |
99 | | |
100 | 2 | @objc func hideApp() { |
101 | 2 | NSApp.hide(self) |
102 | 2 | } |
103 | | |
104 | 1 | private func justClose() { |
105 | 1 | self.jsFuncPopup.closePopup() |
106 | 1 | perform(#selector(hideApp), with: self, afterDelay: 0.1) |
107 | 1 | } |
108 | | |
109 | 1 | private func closeAndPaste() { |
110 | 1 | self.pasteSelectedClips() |
111 | 1 | self.jsFuncPopup.closePopup() |
112 | 1 | perform(#selector(hideApp), with: self, afterDelay: 0.1) |
113 | 1 | perform(#selector(fakePaste), with: self, afterDelay: 0.25) |
114 | 1 | } |
115 | | |
116 | 3 | func pasteSelectedClips() { |
117 | 3 | guard !self.selectedClips.isEmpty else { |
118 | 1 | return |
119 | 2 | } |
120 | 2 | |
121 | 2 | let row = self.jsFuncView.itemsList.selectedRow |
122 | 2 | var clip: String |
123 | 2 | |
124 | 2 | if let name = js.funcList[safe: row] { |
125 | 1 | clip = js.process(name, items: self.selectedClips) |
126 | 2 | } else { |
127 | 1 | clip = prefs.prepareClips(self.selectedClips) |
128 | 2 | } |
129 | 2 | |
130 | 2 | pasteboard.clearContents() |
131 | 2 | pasteboard.setString(string: clip) |
132 | 2 | } |
133 | | |
134 | 66 | private func configureJSPopupAndView() { |
135 | 66 | self.jsFuncView.placeHolderTextString = "js_func_search_placeholder".l7n |
136 | 66 | self.jsFuncPopup.proportionalTopPadding = 0.15 |
137 | 66 | self.jsFuncPopup.proportionalWidth = 0.6 |
138 | 66 | self.jsFuncPopup.proportionalHeight = 0.6 |
139 | 66 | self.jsFuncPopup.willOpenPopup = self.jsFuncPopup.proportionalResizePopup $s15CutBoxUnitTests26JSFuncSearchViewControllerC019configureJSPopupAndG0018_ED20B3A220ACEF2F7P13E1A95413B84ECLLyyFyycAA05PopupH0Ccfu_ Line | Count | Source | 139 | 66 | self.jsFuncPopup.willOpenPopup = self.jsFuncPopup.proportionalResizePopup |
Unexecuted instantiation: $s15CutBoxUnitTests26JSFuncSearchViewControllerC019configureJSPopupAndG0018_ED20B3A220ACEF2F7P13E1A95413B84ECLLyyFyycAA05PopupH0Ccfu_yycfu0_ |
140 | 66 | self.jsFuncPopup.didOpenPopup = { |
141 | 0 | guard let window = self.jsFuncView.window |
142 | 0 | else { fatalError("No window found for popup") } |
143 | 0 |
|
144 | 0 | self.resetJSFuncSearchText() |
145 | 0 | // Focus search text |
146 | 0 | window.makeFirstResponder(self.jsFuncView.searchText) |
147 | 0 | } |
148 | 66 | |
149 | 68 | self.jsFuncPopup.willClosePopup = self.resetJSFuncSearchText $s15CutBoxUnitTests26JSFuncSearchViewControllerC019configureJSPopupAndG0018_ED20B3A220ACEF2F7P13E1A95413B84ECLLyyFyycACcfu1_ Line | Count | Source | 149 | 66 | self.jsFuncPopup.willClosePopup = self.resetJSFuncSearchText |
$s15CutBoxUnitTests26JSFuncSearchViewControllerC019configureJSPopupAndG0018_ED20B3A220ACEF2F7P13E1A95413B84ECLLyyFyycACcfu1_yycfu2_ Line | Count | Source | 149 | 2 | self.jsFuncPopup.willClosePopup = self.resetJSFuncSearchText |
|
150 | 66 | self.jsFuncView.setupClipItemsContextMenu() |
151 | 66 | } |
152 | | } |