# 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

    }