ruby-pass-qt 2.0.7 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -0
  3. data/lib/pass-qt/app/views/browsestoresdialog/ui.rb +77 -0
  4. data/lib/pass-qt/app/views/browsestoresdialog.rb +3 -69
  5. data/lib/pass-qt/app/views/mainwindow/components/passinfowidget/helpers.rb +26 -0
  6. data/lib/pass-qt/app/{components/passinfowidget.rb → views/mainwindow/components/passinfowidget/ui.rb} +21 -86
  7. data/lib/pass-qt/app/views/mainwindow/components/passinfowidget.rb +75 -0
  8. data/lib/pass-qt/app/views/mainwindow/components/passlistwidget/treewidget/funcs/filter.rb +45 -0
  9. data/lib/pass-qt/app/views/mainwindow/components/passlistwidget/treewidget/funcs/refresh.rb +58 -0
  10. data/lib/pass-qt/app/views/mainwindow/components/passlistwidget/treewidget/funcs.rb +2 -0
  11. data/lib/pass-qt/app/views/mainwindow/components/passlistwidget/treewidget/helpers.rb +18 -0
  12. data/lib/pass-qt/app/views/mainwindow/components/passlistwidget/treewidget/ui.rb +36 -0
  13. data/lib/pass-qt/app/{components → views/mainwindow/components}/passlistwidget/treewidget.rb +12 -54
  14. data/lib/pass-qt/app/{components/passlistwidget.rb → views/mainwindow/components/passlistwidget/ui.rb} +13 -47
  15. data/lib/pass-qt/app/views/mainwindow/components/passlistwidget.rb +45 -0
  16. data/lib/pass-qt/app/views/mainwindow/ui.rb +39 -0
  17. data/lib/pass-qt/app/views/mainwindow.rb +5 -61
  18. data/lib/pass-qt/app/views/newonetimepassworddialog/ui.rb +90 -0
  19. data/lib/pass-qt/app/views/newonetimepassworddialog.rb +15 -93
  20. data/lib/pass-qt/app/views/newpassworddialog/ui.rb +111 -0
  21. data/lib/pass-qt/app/views/newpassworddialog.rb +18 -117
  22. data/lib/pass-qt/app.rb +2 -2
  23. data/lib/pass-qt/config/initializers/qt6.rb +1 -1
  24. data/lib/pass-qt/lib/{contrib/sighandler.rb → ctrlc/handler.rb} +6 -4
  25. data/lib/pass-qt/lib/ctrlc.rb +1 -0
  26. data/lib/pass-qt/lib/pass/{clients → backend}/gopass.rb +4 -4
  27. data/lib/pass-qt/lib/pass/{clients → backend}/pass.rb +6 -6
  28. data/lib/pass-qt/lib/pass/backend.rb +2 -0
  29. data/lib/pass-qt/lib/{contrib → pass}/process.rb +1 -1
  30. data/lib/pass-qt/lib/pass.rb +13 -11
  31. data/lib/pass-qt/lib.rb +1 -1
  32. data/lib/pass-qt/version.rb +1 -1
  33. metadata +23 -17
  34. data/lib/pass-qt/app/assets/README.md +0 -5
  35. data/lib/pass-qt/app/assets/app.svg +0 -1
  36. data/lib/pass-qt/app/components/passinfowidget/helpers.rb +0 -26
  37. data/lib/pass-qt/app/components/passlistwidget/treewidget/helpers.rb +0 -18
  38. data/lib/pass-qt/app/components/passlistwidget/treewidget/treebuilder.rb +0 -46
  39. data/lib/pass-qt/app/components/passlistwidget/treewidget/treefilter.rb +0 -45
  40. data/lib/pass-qt/lib/contrib.rb +0 -2
  41. data/lib/pass-qt/lib/pass/clients.rb +0 -2
  42. /data/lib/pass-qt/app/{components.rb → views/mainwindow/components.rb} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fe16368263f57aeb0a5f0c094bc01d051bf5130c1b14b21f8bc461f7f2f47102
4
- data.tar.gz: 9a1b4b86470606106e13230bcd143d974c3dfec5ee27960a78785b5bbb0915ca
3
+ metadata.gz: c91b2943a3a656afdaa617f3bc534c2beab4dfeebb86c38f177054a2291cc202
4
+ data.tar.gz: 7d911ca4c201296c9259d755d643e500c15bc95fc2a7f723cef21e68882ed6d1
5
5
  SHA512:
6
- metadata.gz: c0ec8c9abb5390441a8ea5888c7c7ef30f8699506cad1bfccf6d3662a236fb336c5f8ddb40730d273573ec4027254821dae89deb94abe3da69ddaf8bbdfb1ee4
7
- data.tar.gz: 8b3360194e28a221283a42b6d1d87dca2265cbfdbf3dce76dfc9c5f6b49ce929b945f4b8c184351fe0d1ad5022684e09319ccd0189966120787632a9c5a3b8e1
6
+ metadata.gz: 35cb967283aa998c40e766d78e53d909e5f1034005130238608d20f5c2d072839d3dac7a5ac3547da7c6293205768928a0a4d7c750286ed4b2d95777d0101f0c
7
+ data.tar.gz: 7346a3732c5fad0a5c820340a462e2e150f525a15cfb2ab6f2da7d92f0472a8c1a544e16fcec6c84e154d097bc2081f8b7ffc76d667bab97ace3528576007616
data/.rubocop.yml CHANGED
@@ -8,3 +8,7 @@ AllCops:
8
8
  Exclude:
9
9
  - "bin/**/*"
10
10
  - "tmp/**/*"
11
+
12
+ Style/GlobalVars:
13
+ AllowedVariables:
14
+ - '$qApp'
@@ -0,0 +1,77 @@
1
+ class BrowseStoresDialog < RubyQt6::Bando::QDialog
2
+ private
3
+
4
+ def initialize_ui
5
+ initialize_toolbar
6
+ initialize_tablewidget
7
+ initialize_layout
8
+
9
+ set_attribute(Qt::WA_DeleteOnClose)
10
+ set_modal(true)
11
+ end
12
+
13
+ def initialize_toolbar
14
+ @toolbar = QWidget.new
15
+
16
+ btn = QPushButton.new(QIcon.from_theme(QIcon::ThemeIcon::ListAdd), "Add")
17
+ btn.clicked.connect(self, :_on_list_add_button_clicked)
18
+
19
+ qhboxlayout = QHBoxLayout.new(@toolbar)
20
+ qhboxlayout.add_widget(QLabel.new("Password Stores"))
21
+ qhboxlayout.add_stretch
22
+ qhboxlayout.add_widget(btn)
23
+ end
24
+
25
+ def initialize_tablewidget
26
+ @tablewidget = QWidget.new
27
+ @tablewidget.set_object_name("browsestoresdialog_tablewidget")
28
+ @tablewidget.set_style_sheet("
29
+ #browsestoresdialog_tablewidget {
30
+ min-width: 600px;
31
+ background: white;
32
+ }
33
+ ")
34
+
35
+ QVBoxLayout.new(@tablewidget)
36
+ PassQt.settings.GET_stores.each do |store|
37
+ update_tablewidget_addtableitem(store["fullpath"])
38
+ end
39
+ end
40
+
41
+ def initialize_layout
42
+ mainlayout = QVBoxLayout.new(self)
43
+ mainlayout.add_stretch
44
+ mainlayout.add_widget(@toolbar)
45
+ mainlayout.add_widget(@tablewidget)
46
+ mainlayout.add_stretch
47
+ end
48
+
49
+ def update_tablewidget_addtableitem(fullpath)
50
+ tableitem = QWidget.new
51
+ tableitemlayout = QHBoxLayout.new(tableitem)
52
+
53
+ label = QLabel.new(fullpath)
54
+ tableitemlayout.add_widget(label)
55
+ tableitemlayout.add_stretch
56
+
57
+ btn = QPushButton.new(QIcon.from_theme(QIcon::ThemeIcon::ListRemove), "Remove")
58
+ btn.clicked.connect(self, :_on_list_remove_button_clicked)
59
+ tableitemlayout.add_widget(btn)
60
+
61
+ @dataitems[fullpath] = DataItem.new(tableitem)
62
+ @tablewidget.layout.add_widget(tableitem)
63
+ update_settings_stores
64
+ end
65
+
66
+ def update_tablewidget_removetableitem(tableitem)
67
+ @dataitems.delete_if { |_, item| item.tablewidgetitem == tableitem }
68
+ tableitem.delete_now
69
+ update_settings_stores
70
+ end
71
+
72
+ def update_settings_stores
73
+ stores = @dataitems.map { |fullpath, _| {"fullpath" => fullpath} }
74
+ PassQt.settings.PUT_stores(stores)
75
+ stores_changed.emit
76
+ end
77
+ end
@@ -1,3 +1,5 @@
1
+ require_relative "browsestoresdialog/ui"
2
+
1
3
  class BrowseStoresDialog < RubyQt6::Bando::QDialog
2
4
  DataItem = Struct.new(:tablewidgetitem)
3
5
 
@@ -11,77 +13,11 @@ class BrowseStoresDialog < RubyQt6::Bando::QDialog
11
13
  super
12
14
 
13
15
  @dataitems = {}
14
-
15
- initialize_toolbar
16
- initialize_tablewidget
17
-
18
- mainlayout = QVBoxLayout.new(self)
19
- mainlayout.add_stretch
20
- mainlayout.add_widget(@toolbar)
21
- mainlayout.add_widget(@tablewidget)
22
- mainlayout.add_stretch
23
-
24
- set_attribute(Qt::WA_DeleteOnClose)
25
- set_modal(true)
16
+ initialize_ui
26
17
  end
27
18
 
28
19
  private
29
20
 
30
- def initialize_toolbar
31
- @toolbar = QWidget.new
32
-
33
- btn = QPushButton.new(QIcon.from_theme(QIcon::ThemeIcon::ListAdd), "Add")
34
- btn.clicked.connect(self, :_on_list_add_button_clicked)
35
-
36
- qhboxlayout = QHBoxLayout.new(@toolbar)
37
- qhboxlayout.add_widget(QLabel.new("Password Stores"))
38
- qhboxlayout.add_stretch
39
- qhboxlayout.add_widget(btn)
40
- end
41
-
42
- def initialize_tablewidget
43
- @tablewidget = QWidget.new
44
- @tablewidget.set_object_name("browsestoresdialog_tablewidget")
45
- @tablewidget.set_style_sheet("
46
- #browsestoresdialog_tablewidget {
47
- min-width: 600px;
48
- background: white;
49
- }
50
- ")
51
-
52
- QVBoxLayout.new(@tablewidget)
53
- PassQt.settings.GET_stores.each do |store|
54
- update_tablewidget_addtableitem(store["fullpath"])
55
- end
56
- end
57
-
58
- def update_tablewidget_addtableitem(fullpath)
59
- tableitem = QWidget.new
60
- tableitemlayout = QHBoxLayout.new(tableitem)
61
-
62
- label = QLabel.new(fullpath)
63
- tableitemlayout.add_widget(label)
64
- tableitemlayout.add_stretch
65
-
66
- btn = QPushButton.new(QIcon.from_theme(QIcon::ThemeIcon::ListRemove), "Remove")
67
- btn.clicked.connect(self, :_on_list_remove_button_clicked)
68
- tableitemlayout.add_widget(btn)
69
-
70
- @dataitems[fullpath] = DataItem.new(tableitem)
71
- @tablewidget.layout.add_widget(tableitem)
72
- end
73
-
74
- def update_tablewidget_removetableitem(tableitem)
75
- @dataitems.delete_if { |_, item| item.tablewidgetitem == tableitem }
76
- tableitem.delete_now
77
- end
78
-
79
- def update_settings_stores
80
- stores = @dataitems.map { |fullpath, _| {"fullpath" => fullpath} }
81
- PassQt.settings.PUT_stores(stores)
82
- stores_changed.emit
83
- end
84
-
85
21
  def _on_list_add_button_clicked
86
22
  dir = QFileDialog.get_existing_directory(self, "", QDir.home_path)
87
23
  return if dir.empty?
@@ -99,11 +35,9 @@ class BrowseStoresDialog < RubyQt6::Bando::QDialog
99
35
  end
100
36
 
101
37
  update_tablewidget_addtableitem(dir)
102
- update_settings_stores
103
38
  end
104
39
 
105
40
  def _on_list_remove_button_clicked
106
41
  update_tablewidget_removetableitem(sender.parent)
107
- update_settings_stores
108
42
  end
109
43
  end
@@ -0,0 +1,26 @@
1
+ class MainWindowPassInfoWidget < RubyQt6::Bando::QWidget
2
+ private
3
+
4
+ def hlpr_parse_passfile(data)
5
+ lines = data["stdout"].lines
6
+ password = lines[0][..-2]
7
+
8
+ username = ""
9
+ website = ""
10
+ lines.each do |line|
11
+ matched = line.match(/\A(\w+:\s*)?(.*)\n/)
12
+ next if matched.nil?
13
+
14
+ case matched[1]&.rstrip&.downcase
15
+ when "username:" then username = matched[2]
16
+ when "website:" then website = matched[2]
17
+ end
18
+ end
19
+
20
+ {
21
+ "password" => password,
22
+ "username" => username,
23
+ "website" => website
24
+ }
25
+ end
26
+ end
@@ -1,69 +1,14 @@
1
- require_relative "passinfowidget/helpers"
2
-
3
- class PassInfoWidget < RubyQt6::Bando::QWidget
4
- q_object do
5
- slot "_on_copy_action_triggered()"
6
- slot "_on_copy_action_triggered_otpcode()"
7
- slot "_on_view_action_triggered()"
8
- end
9
-
10
- def initialize
11
- super
12
-
13
- @store = QString.new
14
- @passname = QString.new
1
+ class MainWindowPassInfoWidget < RubyQt6::Bando::QWidget
2
+ private
15
3
 
4
+ def initialize_ui
16
5
  initialize_form
17
6
  initialize_otpform
18
7
  initialize_folderform
19
8
  initialize_infoframe
20
-
21
- @stackedlayout = QStackedLayout.new
22
- @stackedlayout.add_widget(@form)
23
- @stackedlayout.add_widget(@otpform)
24
- @stackedlayout.add_widget(@folderform)
25
- @stackedlayout.add_widget(@infoframe)
26
-
27
- mainlayout = QVBoxLayout.new(self)
28
- mainlayout.add_spacing(76)
29
- mainlayout.add_layout(@stackedlayout)
30
-
31
- use_infoframe
32
- end
33
-
34
- def use_passfilecard(store, passname)
35
- @store = store
36
- @passname = passname
37
- use_infoframe
38
-
39
- Pass.show(@store, @passname, on_success: ->(data) {
40
- formdata = Helpers.parse_passfile(data)
41
- if formdata["password"].start_with?("otpauth:")
42
- use_otpform(formdata)
43
- else
44
- use_form(formdata)
45
- end
46
- }, on_failure: ->(data) {
47
- errinfo = data["stderr"]
48
- use_infoframe_err(errinfo)
49
- })
9
+ initialize_layout
50
10
  end
51
11
 
52
- def use_passfoldercard(store, passname)
53
- @store = store
54
- @passname = passname
55
- use_infoframe
56
- use_folderform
57
- end
58
-
59
- def use_infocard
60
- @store = QString.new
61
- @passname = QString.new
62
- use_infoframe
63
- end
64
-
65
- private
66
-
67
12
  def initialize_form
68
13
  @passnameinput = initialize_form_inputfield
69
14
  initialize_form_inputfield_copyaction(@passnameinput)
@@ -150,7 +95,19 @@ class PassInfoWidget < RubyQt6::Bando::QWidget
150
95
  infoframelayout.add_stretch
151
96
  end
152
97
 
153
- def use_form(formdata)
98
+ def initialize_layout
99
+ @stackedlayout = QStackedLayout.new
100
+ @stackedlayout.add_widget(@form)
101
+ @stackedlayout.add_widget(@otpform)
102
+ @stackedlayout.add_widget(@folderform)
103
+ @stackedlayout.add_widget(@infoframe)
104
+
105
+ mainlayout = QVBoxLayout.new(self)
106
+ mainlayout.add_spacing(76)
107
+ mainlayout.add_layout(@stackedlayout)
108
+ end
109
+
110
+ def activate_form(formdata)
154
111
  @passnameinput.set_text(@passname)
155
112
  @passwordinput.set_text(formdata["password"])
156
113
  @passwordinput.set_echo_mode(QLineEdit::Password)
@@ -160,7 +117,7 @@ class PassInfoWidget < RubyQt6::Bando::QWidget
160
117
  @stackedlayout.set_current_widget(@form)
161
118
  end
162
119
 
163
- def use_otpform(formdata)
120
+ def activate_otpform(formdata)
164
121
  @otppassnameinput.set_text(@passname)
165
122
  @otppasswordinput.set_text(formdata["password"])
166
123
  @otppasswordinput.set_cursor_position(0)
@@ -179,42 +136,20 @@ class PassInfoWidget < RubyQt6::Bando::QWidget
179
136
  }, on_failure: ->(_) {})
180
137
  end
181
138
 
182
- def use_folderform
139
+ def activate_folderform
183
140
  @folderpassnameinput.set_text(@passname)
184
141
  @stackedlayout.set_current_widget(@folderform)
185
142
  end
186
143
 
187
- def use_infoframe(info = "")
144
+ def activate_infoframe(info = "")
188
145
  @infolabel.set_style_sheet("color: black;")
189
146
  @infolabel.set_text(info)
190
147
  @stackedlayout.set_current_widget(@infoframe)
191
148
  end
192
149
 
193
- def use_infoframe_err(info)
150
+ def activate_infoframe_err(info)
194
151
  @infolabel.set_style_sheet("color: red;")
195
152
  @infolabel.set_text(info)
196
153
  @stackedlayout.set_current_widget(@infoframe)
197
154
  end
198
-
199
- def _on_copy_action_triggered
200
- input = sender.parent
201
- QApplication.clipboard.set_text(input.text)
202
- end
203
-
204
- def _on_copy_action_triggered_otpcode
205
- Pass.otp(@store, @passname, on_success: ->(data) {
206
- otpcode = data["stdout"].rstrip
207
- @otpcodeinput.set_text(otpcode)
208
- QApplication.clipboard.set_text(otpcode)
209
- }, on_failure: ->(_) {})
210
- end
211
-
212
- def _on_view_action_triggered
213
- input = sender.parent
214
- case input.echo_mode
215
- when QLineEdit::Normal then input.set_echo_mode(QLineEdit::Password)
216
- when QLineEdit::Password then input.set_echo_mode(QLineEdit::Normal)
217
- else raise "unreachable!"
218
- end
219
- end
220
155
  end
@@ -0,0 +1,75 @@
1
+ require_relative "passinfowidget/helpers"
2
+ require_relative "passinfowidget/ui"
3
+
4
+ class MainWindowPassInfoWidget < RubyQt6::Bando::QWidget
5
+ q_object do
6
+ slot "activate_passfilecard(QString,QString)"
7
+ slot "activate_passfoldercard(QString,QString)"
8
+ slot "activate_infocard()"
9
+ slot "_on_copy_action_triggered()"
10
+ slot "_on_copy_action_triggered_otpcode()"
11
+ slot "_on_view_action_triggered()"
12
+ end
13
+
14
+ def initialize
15
+ super
16
+
17
+ initialize_ui
18
+ activate_infocard
19
+ end
20
+
21
+ private
22
+
23
+ def activate_passfilecard(store, passname)
24
+ @store = store
25
+ @passname = passname
26
+ activate_infoframe
27
+
28
+ Pass.show(@store, @passname, on_success: ->(data) {
29
+ formdata = hlpr_parse_passfile(data)
30
+ if formdata["password"].start_with?("otpauth:")
31
+ activate_otpform(formdata)
32
+ else
33
+ activate_form(formdata)
34
+ end
35
+ }, on_failure: ->(data) {
36
+ errinfo = data["stderr"]
37
+ activate_infoframe_err(errinfo)
38
+ })
39
+ end
40
+
41
+ def activate_passfoldercard(store, passname)
42
+ @store = store
43
+ @passname = passname
44
+ activate_infoframe
45
+ activate_folderform
46
+ end
47
+
48
+ def activate_infocard
49
+ @store = QString.new
50
+ @passname = QString.new
51
+ activate_infoframe
52
+ end
53
+
54
+ def _on_copy_action_triggered
55
+ input = sender.parent
56
+ QApplication.clipboard.set_text(input.text)
57
+ end
58
+
59
+ def _on_copy_action_triggered_otpcode
60
+ Pass.otp(@store, @passname, on_success: ->(data) {
61
+ otpcode = data["stdout"].rstrip
62
+ @otpcodeinput.set_text(otpcode)
63
+ QApplication.clipboard.set_text(otpcode)
64
+ }, on_failure: ->(_) {})
65
+ end
66
+
67
+ def _on_view_action_triggered
68
+ input = sender.parent
69
+ case input.echo_mode
70
+ when QLineEdit::Normal then input.set_echo_mode(QLineEdit::Password)
71
+ when QLineEdit::Password then input.set_echo_mode(QLineEdit::Normal)
72
+ else raise "unreachable!"
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,45 @@
1
+ class MainWindowPassListWidget < RubyQt6::Bando::QWidget
2
+ class TreeWidget < RubyQt6::Bando::QTreeWidget
3
+ private
4
+
5
+ def filter_imp(text)
6
+ set_current_item(nil)
7
+
8
+ if text.empty?
9
+ @dataitems.each do |_, item|
10
+ item.treewidgetitem.set_hidden(false)
11
+ item.treewidgetitem.set_selected(false)
12
+ end
13
+ return
14
+ end
15
+
16
+ re_options = QRegularExpression::UnanchoredWildcardConversion | QRegularExpression::NonPathWildcardConversion
17
+ re = QRegularExpression.from_wildcard(text, nil, re_options)
18
+
19
+ filepath_matched = Set.new
20
+ filepath_matched_1st = nil
21
+ @dataitems.each do |filepath, item|
22
+ has_match = re.match(item.passname).has_match
23
+ next unless has_match
24
+
25
+ if filepath_matched_1st.nil?
26
+ filepath_matched_1st = filepath if hlpr_passfile?(filepath)
27
+ end
28
+
29
+ loop do
30
+ filepath_matched << filepath
31
+ filepath = QFileInfo.new(filepath).absolute_path
32
+ break unless @dataitems.key?(filepath)
33
+ end
34
+ end
35
+
36
+ @dataitems.each do |filepath, item|
37
+ visible = filepath_matched.include?(filepath)
38
+ item.treewidgetitem.set_hidden(!visible)
39
+
40
+ selected = filepath_matched_1st == filepath
41
+ item.treewidgetitem.set_selected(selected)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,58 @@
1
+ class MainWindowPassListWidget < RubyQt6::Bando::QWidget
2
+ class TreeWidget < RubyQt6::Bando::QTreeWidget
3
+ private
4
+
5
+ def refresh_imp(store, selected_passname:)
6
+ @store = store
7
+ @dataitems = {}
8
+
9
+ clear
10
+ refresh_imp_rebuild_tree
11
+ expand_all
12
+
13
+ if selected_passname.nil?
14
+ set_current_item(nil)
15
+ else
16
+ @dataitems.each do |_, item|
17
+ next if item.passname != selected_passname
18
+ set_current_item(item.treewidgetitem)
19
+ break
20
+ end
21
+ end
22
+ end
23
+
24
+ def refresh_imp_rebuild_tree
25
+ file_icon_provider = QFileIconProvider.new
26
+ store_root_path = QDir.new(@store)
27
+ dirs = [@store]
28
+ until dirs.empty?
29
+ dir = dirs.shift
30
+ diritem = @dataitems[dir]&.treewidgetitem || invisible_root_item
31
+
32
+ entry_list = QDir.new(dir).entry_info_list(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)
33
+ entry_list.each do |entry|
34
+ next if entry.hidden?
35
+ next if entry.file_name.starts_with(".")
36
+
37
+ filepath = entry.absolute_file_path
38
+ next if @dataitems.key?(filepath)
39
+
40
+ if entry.dir?
41
+ dirs << filepath
42
+ passname = store_root_path.relative_file_path(filepath)
43
+ elsif entry.file?
44
+ next unless hlpr_passfile?(entry)
45
+ passname = store_root_path.relative_file_path(filepath)
46
+ passname = passname[0, passname.size - entry.suffix.size - 1]
47
+ else
48
+ next
49
+ end
50
+
51
+ item = QTreeWidgetItem.new(diritem, QStringList.new << entry.complete_base_name << filepath)
52
+ item.set_icon(0, file_icon_provider.icon(entry))
53
+ @dataitems[filepath] = DataItem.new(passname, item)
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,2 @@
1
+ require_relative "funcs/filter"
2
+ require_relative "funcs/refresh"
@@ -0,0 +1,18 @@
1
+ class MainWindowPassListWidget < RubyQt6::Bando::QWidget
2
+ class TreeWidget < RubyQt6::Bando::QTreeWidget
3
+ private
4
+
5
+ def hlpr_passfile?(fileinfo)
6
+ case fileinfo
7
+ when QFileInfo then fileinfo.suffix.downcase == "gpg"
8
+ when QString then fileinfo.ends_with(".gpg", Qt::CaseInsensitive)
9
+ else raise "unreachable!"
10
+ end
11
+ end
12
+
13
+ def hlpr_folderpath(store, fileinfo)
14
+ folder = fileinfo.dir? ? fileinfo.absolute_file_path : fileinfo.absolute_path
15
+ QDir.new(store).relative_file_path(folder)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,36 @@
1
+ class MainWindowPassListWidget < RubyQt6::Bando::QWidget
2
+ class TreeWidget < RubyQt6::Bando::QTreeWidget
3
+ private
4
+
5
+ def initialize_actions
6
+ @new_password_action = initialize_actions_act(QIcon::ThemeIcon::DocumentNew, "New Password", :_on_new_password_action_triggered)
7
+ @new_otp_action = initialize_actions_act(QIcon::ThemeIcon::DocumentNew, "New OTP", :_on_new_otp_action_triggered)
8
+ @delete_action = initialize_actions_act(QIcon::ThemeIcon::EditDelete, "Delete", :_on_delete_action_triggered)
9
+ @refresh_action = initialize_actions_act(QIcon::ThemeIcon::ViewRefresh, "Refresh", :_on_refresh_action_triggered)
10
+ @open_action = initialize_actions_act(QIcon::ThemeIcon::FolderVisiting, "Open Store With File Explorer", :_on_open_action_triggered)
11
+ end
12
+
13
+ def initialize_actions_act(icon, text, slot)
14
+ action = QAction.new(QIcon.from_theme(icon), text, self)
15
+ action.triggered.connect(self, slot)
16
+ action
17
+ end
18
+
19
+ def initialize_context_menu
20
+ menu = QMenu.new("", self)
21
+ menu.set_attribute(Qt::WA_DeleteOnClose)
22
+
23
+ menu.add_action(@new_password_action)
24
+ menu.add_action(@new_otp_action)
25
+ menu.add_action(@delete_action)
26
+ menu.add_separator
27
+ menu.add_action(@refresh_action)
28
+ menu.add_action(@open_action)
29
+
30
+ enabled = !selected_items.empty?
31
+ @delete_action.set_enabled(enabled)
32
+
33
+ menu
34
+ end
35
+ end
36
+ end