CutBox.app

Coverage Report

Created: 2024-03-12 03:40

.../Source/App/SearchAndPreview/SearchAndPreviewView.swift
Line
Count
Source (jump to first uncovered line)
1
//
2
//  SearchView.swift
3
//  CutBox
4
//
5
//  Created by Jason Milkins on 24/3/18.
6
//  Copyright © 2018-2023 ocodo. All rights reserved.
7
//
8
9
import Foundation
10
import Cocoa
11
import RxSwift
12
import RxCocoa
13
import Carbon
14
15
/// Main view of CutBox, displayed via `PopupController`
16
/// communicates with the `CutBoxController` via events<`SearchViewEvents`>
17
/// Extends `SearchAndPreviewViewBase`
18
class SearchAndPreviewView: SearchAndPreviewViewBase {
19
20
    @IBOutlet weak var searchModeToggle: CutBoxBaseButton!
21
    @IBOutlet weak var jsIconButton: CutBoxBaseButton!
22
    @IBOutlet weak var timeFilterText: ValidIndicatorTextField!
23
    @IBOutlet weak var timeFilterLabel: CutBoxBaseTextField!
24
    @IBOutlet weak var historyScopeImageButton: CutBoxBaseButton!
25
26
79
    var events = PublishSubject<SearchViewEvents>()
27
28
48
    override func awakeFromNib() {
29
48
        self.setAccessibilityIdentifier("searchAndPreviewView")
30
48
        setupSearchText()
31
48
        setupSearchModeToggle()
32
48
        setupSearchScopeToggle()
33
48
        setupHistoryScopeButton()
34
48
        setupTimeFilter()
35
48
        setupJSIconButton()
36
48
        super.awakeFromNib()
37
48
        applyTheme()
38
48
    }
39
40
48
    func setupJSIconButton() {
41
48
        jsIconButton.setAccessibilityIdentifier("jsIconButton")
42
48
        jsIconButton.rx.tap
43
48
            .map { .selectJavascriptFunction }
44
48
            .bind(to: self.events)
45
48
            .disposed(by: disposeBag)
46
48
    }
47
48
102
    func setSearchModeButton(mode: HistorySearchMode) {
49
102
        let color = [NSAttributedString.Key.foregroundColor: prefs.currentTheme.clip.textColor]
50
102
        let titleString = NSAttributedString(string: mode.name, attributes: color)
51
102
52
102
        self.searchModeToggle?.attributedTitle = titleString
53
102
        self.searchModeToggle?.toolTip = mode.toolTip
54
102
    }
55
56
48
    private func setupHistoryScopeButton() {
57
48
        colorizeHistoryScopeIcon(alpha: 0.4,
58
48
                                 color: prefs.currentTheme.searchText.placeholderTextColor)
59
48
60
48
        self.historyScopeImageButton.rx.tap
61
48
            .bind(onNext: historyScopeClicked)
$s15CutBoxUnitTests20SearchAndPreviewViewC23setupHistoryScopeButton33_B55705268F368941FE232CCBCA4658DDLLyyFyycACcfu_
Line
Count
Source
61
48
            .bind(onNext: historyScopeClicked)
Unexecuted instantiation: $s15CutBoxUnitTests20SearchAndPreviewViewC23setupHistoryScopeButton33_B55705268F368941FE232CCBCA4658DDLLyyFyycACcfu_yycfu0_
62
48
            .disposed(by: disposeBag)
63
48
    }
64
65
    private func colorizeHistoryScopeIcon(image: NSImage = CutBoxImageRef.historyClockFaceWhite.image(true),
66
                                          tooltip: String = "search_time_filter_label_hint".l7n,
67
                                          alpha: Double = 0.75,
68
98
                                          color: NSColor = NSColor.white) {
69
98
        let image = image
70
98
        let blended = image.tint(color: color)
71
98
72
98
        self.historyScopeImageButton?.alphaValue = alpha
73
98
        self.historyScopeImageButton?.image = blended
74
98
        self.historyScopeImageButton?.toolTip = tooltip
75
98
    }
76
77
0
    private func historyScopeClicked() {
78
0
        self.events.onNext(.toggleTimeFilter)
79
0
    }
80
81
48
    private func setupSearchModeToggle() {
82
48
        let mode = HistoryService.shared.searchMode
83
48
        setSearchModeButton(mode: mode)
84
48
85
48
        self.searchModeToggle.rx.tap
86
48
            .map { .toggleSearchMode }
87
48
            .bind(to: self.events)
88
48
            .disposed(by: disposeBag)
89
48
    }
90
91
99
    func setSearchScopeButton(favoritesOnly: Bool) {
92
99
        if favoritesOnly {
93
1
            colorizeMagnifier(
94
1
                image: CutBoxImageRef.star.image(),
95
1
                tooltip: "search_scope_tooltip_favorites".l7n,
96
1
                color: prefs.currentTheme.searchText.placeholderTextColor
97
1
            )
98
99
        } else {
99
98
            colorizeMagnifier(color: prefs.currentTheme.searchText.placeholderTextColor)
100
99
        }
101
99
    }
102
103
4
    override func setTextScale() {
104
4
        super.setTextScale()
105
4
    }
106
107
48
    private func setupSearchScopeToggle() {
108
48
        let favoritesOnly = HistoryService.shared.favoritesOnly
109
48
        setSearchScopeButton(favoritesOnly: favoritesOnly)
110
48
111
48
        self.searchScopeImageButton.rx.tap
112
48
            .map { .toggleSearchScope }
113
48
            .bind(to: self.events)
114
48
            .disposed(by: disposeBag)
115
48
    }
116
117
48
    private func setupSearchText() {
118
48
        self.searchText.delegate = self
119
48
        self.searchText.isFieldEditor = true
120
48
    }
121
122
48
    private func setupTimeFilter() {
123
48
         self.timeFilterText.rx.text
124
48
            .compactMap { $0 }
125
48
            .subscribe { self.onTimeFilterTextChanged(text: $0) }
126
48
            .disposed(by: disposeBag)
127
48
128
48
        self.timeFilterText.keyUp
129
48
            .subscribe(onNext: { (event: NSEvent) in
130
0
                if event.keyCode == 36 {
131
0
                    self.window?.makeFirstResponder(self.searchText)
132
0
                }
133
0
            })
134
48
            .disposed(by: disposeBag)
135
48
136
48
        self.timeFilterLabel.isHidden = true
137
48
        self.timeFilterText.isHidden = true
138
48
        self.timeFilterText.placeholderString = "...".l7n
139
48
        self.timeFilterText.isValid = false
140
48
    }
141
142
1
    func toggleTimeFilter() {
143
1
        self.timeFilterLabel.isHidden.toggle()
144
1
        self.timeFilterText.isHidden.toggle()
145
1
146
1
        if self.timeFilterText.isHidden {
147
1
            self.window?.makeFirstResponder(self.searchText)
148
1
            self.prefs.savedTimeFilterValue = self.timeFilterText.stringValue
149
1
            self.timeFilterText.stringValue = ""
150
1
        } else {
151
0
            let newText: String = self.prefs.savedTimeFilterValue
152
0
            self.window?.makeFirstResponder(self.timeFilterText)
153
0
            self.timeFilterText.stringValue = newText
154
0
            DispatchQueue.main.async { self.onTimeFilterTextChanged(text: newText) }
155
1
        }
156
1
    }
157
158
48
    func onTimeFilterTextChanged(text: String) {
159
48
        let filter = TimeFilterValidator(value: text)
160
48
        self.timeFilterText?.isValid = filter.isValid
161
48
162
48
        if let seconds = filter.seconds {
163
0
            let formatted = TimeFilterValidator.secondsToTime(seconds: Int(seconds))
164
0
            self.timeFilterLabel?.stringValue = String(format: "search_time_filter_label_active".l7n, formatted)
165
0
            self.events.onNext(.setTimeFilter(seconds: seconds))
166
48
        } else {
167
48
            self.timeFilterLabel?.stringValue = "search_time_filter_label_hint".l7n
168
48
            self.events.onNext(.setTimeFilter(seconds: nil))
169
48
        }
170
48
    }
171
172
0
    @objc func removeSelectedItems() {
173
0
        self.events.onNext(.removeSelected)
174
0
    }
175
176
0
    @objc func toggleFavoriteItems() {
177
0
        self.events.onNext(.toggleFavorite)
178
0
    }
179
180
75
    func setupClipItemsContextMenu() {
181
75
        let removeItem = CutBoxBaseMenuItem(title: "context_menu_remove_selected".l7n,
182
75
                                action: #selector(removeSelectedItems),
183
75
                                keyEquivalent: "")
184
75
185
75
        let favoriteItem = CutBoxBaseMenuItem(title: "context_menu_favorite".l7n,
186
75
                                  action: #selector(toggleFavoriteItems),
187
75
                                  keyEquivalent: "")
188
75
189
75
        let contextMenu = CutBoxBaseMenu()
190
75
        contextMenu.addItem(removeItem)
191
75
        contextMenu.addItem(favoriteItem)
192
75
193
75
        self.itemsList?.menu = contextMenu
194
75
    }
195
196
50
    override func applyTheme() {
197
50
        super.applyTheme()
198
50
199
50
        let theme = prefs.currentTheme
200
50
201
50
        timeFilterLabel?.textColor = theme.searchText.placeholderTextColor
202
50
203
50
        colorizeHistoryScopeIcon(alpha: 0.6,
204
50
                                 color: theme.searchText.placeholderTextColor)
205
50
        setSearchModeButton(mode: HistoryService.shared.searchMode)
206
50
        setSearchScopeButton(favoritesOnly: HistoryService.shared.favoritesOnly)
207
50
    }
208
}