CutBox.app

Coverage Report

Created: 2024-03-12 03:40

.../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
}