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
@@ -1,3 +1,5 @@
1
+ require_relative "newpassworddialog/ui"
2
+
1
3
  class NewPasswordDialog < RubyQt6::Bando::QDialog
2
4
  q_object do
3
5
  slot "_on_okbutton_clicked()"
@@ -12,113 +14,29 @@ class NewPasswordDialog < RubyQt6::Bando::QDialog
12
14
  @folder = folder
13
15
  @on_success = on_success
14
16
 
15
- initialize_form
16
- initialize_btngroup
17
-
18
- mainlayout = QVBoxLayout.new(self)
19
- mainlayout.add_widget(@form)
20
- mainlayout.add_widget(@btngroup)
21
-
22
- set_attribute(Qt::WA_DeleteOnClose)
23
- set_modal(true)
17
+ initialize_ui
24
18
  end
25
19
 
26
20
  private
27
21
 
28
- def initialize_form
29
- titlelabel = QLabel.new("<center><b>Insert New Password</b></center>")
30
-
31
- @errinfolabel = QLabel.new("")
32
- @errinfolabel.set_style_sheet("background: white; color: red; padding: 8px; margin: 4px;")
33
- @errinfolabel.set_hidden(true)
34
-
35
- placeholder = (@folder == "") ? "example.com" : "#{@folder}/example.com"
36
- @passnamelabel = initialize_form_label("File")
37
- @passnameinput = initialize_form_inputfield(placeholder)
38
- @passnameinput.set_text(placeholder)
39
- set_focus_proxy(@passnameinput)
40
-
41
- @passwordlabel = initialize_form_label("Password")
42
- @passwordinput = initialize_form_inputfield("")
43
- initialize_form_inputfield_viewaction(@passwordinput)
44
-
45
- @passwordinput.set_echo_mode(QLineEdit::Password)
46
- Pass.pwgen(16, on_success: ->(data) {
47
- @passwordinput.set_text(data["stdout"].lines[0].strip)
48
- }, on_failure: ->(_) {})
49
-
50
- @usernamelabel = initialize_form_label("Username")
51
- @usernameinput = initialize_form_inputfield("johndoe")
52
-
53
- @websitelabel = initialize_form_label("Website")
54
- @websiteinput = initialize_form_inputfield("https://github.com/login")
55
-
56
- @form = QWidget.new
57
- @form.set_object_name("newpassworddialog_form")
58
- @form.set_style_sheet("
59
- #newpassworddialog_form {
60
- min-width: 600px;
61
- }
62
- ")
63
-
64
- layout = QGridLayout.new(@form)
65
- layout.add_widget(titlelabel, 0, 0, 1, 2)
66
- layout.set_row_minimum_height(1, 10)
67
- layout.add_widget(@errinfolabel, 2, 0, 1, 2)
68
- layout.add_widget(@passnamelabel, 3, 0)
69
- layout.add_widget(@passnameinput, 3, 1)
70
- layout.add_widget(@usernamelabel, 4, 0)
71
- layout.add_widget(@usernameinput, 4, 1)
72
- layout.add_widget(@passwordlabel, 5, 0)
73
- layout.add_widget(@passwordinput, 5, 1)
74
- layout.add_widget(@websitelabel, 6, 0)
75
- layout.add_widget(@websiteinput, 6, 1)
76
- end
77
-
78
- def initialize_form_label(text)
79
- label = QLabel.new(text)
80
- label.set_alignment(Qt::AlignRight)
81
- label.set_style_sheet("min-width: 80px; padding-right: 4px;")
82
- label
83
- end
84
-
85
- def initialize_form_inputfield(placeholder)
86
- input = QLineEdit.new
87
- input.set_placeholder_text(placeholder)
88
- input
89
- end
90
-
91
- def initialize_form_inputfield_viewaction(input)
92
- action = input.add_action(QIcon.from_theme(QIcon::ThemeIcon::DocumentPrintPreview), QLineEdit::TrailingPosition)
93
- action.triggered.connect(self, :_on_view_action_triggered)
94
- end
95
-
96
- def initialize_btngroup
97
- @btngroup = QDialogButtonBox.new(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal)
98
- @btngroup.accepted.connect(self, :_on_okbutton_clicked)
99
- @btngroup.rejected.connect(self, :_on_cancelbutton_clicked)
100
-
101
- okbutton = @btngroup.button(QDialogButtonBox::Ok)
102
- okbutton.set_text("Create")
103
- okbutton.set_default(true)
104
- okbutton.set_auto_default(true)
105
-
106
- cancelbutton = @btngroup.button(QDialogButtonBox::Cancel)
107
- cancelbutton.set_auto_default(true)
108
- end
109
-
110
- def update_form_errinfo(info)
111
- if info.empty?
112
- @errinfolabel.set_text("")
113
- @errinfolabel.set_hidden(true)
114
- return
115
- end
22
+ def _on_okbutton_clicked
23
+ return unless _on_okbutton_clicked_validate_form
116
24
 
117
- @errinfolabel.set_text(info)
118
- @errinfolabel.set_hidden(false)
25
+ store = @store
26
+ passname = @passnameinput.text
27
+ password = @passwordinput.text
28
+ username = @usernameinput.text
29
+ website = @websiteinput.text
30
+ extra = "Username: #{username}\nWebsite: #{website}\n"
31
+ Pass.insert(store, passname, password, extra, on_success: ->(_) {
32
+ @on_success.call(passname)
33
+ close
34
+ }, on_failure: ->(data) {
35
+ update_form_errinfo(data["stderr"].strip)
36
+ })
119
37
  end
120
38
 
121
- def validate_form
39
+ def _on_okbutton_clicked_validate_form
122
40
  update_form_errinfo("")
123
41
 
124
42
  {
@@ -136,23 +54,6 @@ class NewPasswordDialog < RubyQt6::Bando::QDialog
136
54
  true
137
55
  end
138
56
 
139
- def _on_okbutton_clicked
140
- return unless validate_form
141
-
142
- store = @store
143
- passname = @passnameinput.text
144
- password = @passwordinput.text
145
- username = @usernameinput.text
146
- website = @websiteinput.text
147
- extra = "Username: #{username}\nWebsite: #{website}\n"
148
- Pass.insert(store, passname, password, extra, on_success: ->(_) {
149
- @on_success.call(passname)
150
- close
151
- }, on_failure: ->(data) {
152
- update_form_errinfo(data["stderr"].strip)
153
- })
154
- end
155
-
156
57
  def _on_cancelbutton_clicked
157
58
  close
158
59
  end
data/lib/pass-qt/app.rb CHANGED
@@ -1,7 +1,6 @@
1
1
  require_relative "config"
2
2
  require_relative "lib"
3
3
 
4
- require_relative "app/components"
5
4
  require_relative "app/views"
6
5
 
7
6
  module PassQt
@@ -16,7 +15,8 @@ module PassQt
16
15
  end
17
16
 
18
17
  def exec
19
- Contrib::SigHandler.new(@app)
18
+ handler = Ctrlc::Handler.new
19
+ handler.exec
20
20
 
21
21
  @mainwindow.show
22
22
  @app.exec
@@ -4,5 +4,5 @@ QApplication.set_application_name("PassQt")
4
4
  root_path = File.expand_path("../..", __dir__)
5
5
  QDir.add_search_path("assets", File.join(root_path, "app/assets"))
6
6
 
7
- icon = QIcon.new("assets:/app.svg")
7
+ icon = QIcon.from_theme("enpass")
8
8
  QApplication.set_window_icon(icon)
@@ -1,12 +1,14 @@
1
- module Contrib
2
- class SigHandler < RubyQt6::Bando::QObject
1
+ module Ctrlc
2
+ class Handler < RubyQt6::Bando::QObject
3
3
  q_object do
4
4
  slot "_noop()"
5
5
  end
6
6
 
7
- def initialize(parent)
8
- super
7
+ def initialize
8
+ super($qApp)
9
+ end
9
10
 
11
+ def exec
10
12
  ["INT", "TERM"].each do |sig|
11
13
  Signal.trap(sig) { |_| QApplication.quit }
12
14
  end
@@ -0,0 +1 @@
1
+ require_relative "ctrlc/handler"
@@ -1,6 +1,6 @@
1
1
  module Pass
2
- module Clients
3
- class GoPass < ::Pass::Clients::Pass
2
+ module Backend
3
+ class GoPass < ::Pass::Backend::Pass
4
4
  def initialize
5
5
  @program = "gopass"
6
6
  end
@@ -9,12 +9,12 @@ module Pass
9
9
  arguments = QStringList.new << "insert" << passname
10
10
  stdin = password
11
11
  envs = {PASSWORD_STORE_DIR: store}
12
- Contrib::Process.execute(@program, arguments, stdin:, envs:, on_success:, on_failure:)
12
+ Process.execute(@program, arguments, stdin:, envs:, on_success:, on_failure:)
13
13
  end
14
14
 
15
15
  def pwgen(pw_length, on_success:, on_failure:)
16
16
  arguments = QStringList.new << "pwgen" << "-By1" << pw_length.to_s
17
- Contrib::Process.execute(@program, arguments, on_success:, on_failure:)
17
+ Process.execute(@program, arguments, on_success:, on_failure:)
18
18
  end
19
19
  end
20
20
  end
@@ -1,5 +1,5 @@
1
1
  module Pass
2
- module Clients
2
+ module Backend
3
3
  class Pass
4
4
  def initialize
5
5
  @program = "pass"
@@ -8,32 +8,32 @@ module Pass
8
8
  def show(store, passname, on_success:, on_failure:)
9
9
  arguments = QStringList.new << "show" << passname
10
10
  envs = {PASSWORD_STORE_DIR: store}
11
- Contrib::Process.execute(@program, arguments, envs:, on_success:, on_failure:)
11
+ Process.execute(@program, arguments, envs:, on_success:, on_failure:)
12
12
  end
13
13
 
14
14
  def insert(store, passname, password, extra, on_success:, on_failure:)
15
15
  arguments = QStringList.new << "insert" << "-m" << passname
16
16
  stdin = "#{password}\n#{extra}"
17
17
  envs = {PASSWORD_STORE_DIR: store}
18
- Contrib::Process.execute(@program, arguments, stdin:, envs:, on_success:, on_failure:)
18
+ Process.execute(@program, arguments, stdin:, envs:, on_success:, on_failure:)
19
19
  end
20
20
 
21
21
  def otp(store, passname, on_success:, on_failure:)
22
22
  arguments = QStringList.new << "otp" << passname
23
23
  envs = {PASSWORD_STORE_DIR: store}
24
- Contrib::Process.execute(@program, arguments, envs:, on_success:, on_failure:)
24
+ Process.execute(@program, arguments, envs:, on_success:, on_failure:)
25
25
  end
26
26
 
27
27
  def otp_insert(store, passname, password, on_success:, on_failure:)
28
28
  arguments = QStringList.new << "otp" << "insert" << passname
29
29
  stdin = password
30
30
  envs = {PASSWORD_STORE_DIR: store}
31
- Contrib::Process.execute(@program, arguments, stdin:, envs:, on_success:, on_failure:)
31
+ Process.execute(@program, arguments, stdin:, envs:, on_success:, on_failure:)
32
32
  end
33
33
 
34
34
  def pwgen(pw_length, on_success:, on_failure:)
35
35
  arguments = QStringList.new << "-cnysB" << pw_length.to_s << "1"
36
- Contrib::Process.execute("pwgen", arguments, on_success:, on_failure:)
36
+ Process.execute("pwgen", arguments, on_success:, on_failure:)
37
37
  end
38
38
  end
39
39
  end
@@ -0,0 +1,2 @@
1
+ require_relative "backend/pass"
2
+ require_relative "backend/gopass"
@@ -1,4 +1,4 @@
1
- module Contrib
1
+ module Pass
2
2
  class Process < RubyQt6::Bando::QObject
3
3
  q_object do
4
4
  slot "_on_process_error_occurred(QProcess::ProcessError)"
@@ -1,37 +1,39 @@
1
- require_relative "pass/clients"
1
+ require_relative "pass/backend"
2
+ require_relative "pass/process"
2
3
 
3
4
  module Pass
4
5
  def self.show(store, passname, on_success:, on_failure:)
5
- client.show(store, passname, on_success:, on_failure:)
6
+ backend.show(store, passname, on_success:, on_failure:)
6
7
  end
7
8
 
8
9
  def self.insert(store, passname, password, extra, on_success:, on_failure:)
9
- client.insert(store, passname, password, extra, on_success:, on_failure:)
10
+ backend.insert(store, passname, password, extra, on_success:, on_failure:)
10
11
  end
11
12
 
12
13
  def self.otp(store, passname, on_success:, on_failure:)
13
- client.otp(store, passname, on_success:, on_failure:)
14
+ backend.otp(store, passname, on_success:, on_failure:)
14
15
  end
15
16
 
16
17
  def self.otp_insert(store, passname, password, on_success:, on_failure:)
17
- client.otp_insert(store, passname, password, on_success:, on_failure:)
18
+ backend.otp_insert(store, passname, password, on_success:, on_failure:)
18
19
  end
19
20
 
20
21
  def self.pwgen(pw_length, on_success:, on_failure:)
21
- client.pwgen(pw_length, on_success:, on_failure:)
22
+ backend.pwgen(pw_length, on_success:, on_failure:)
22
23
  end
23
24
 
24
- def self.client
25
- @client ||= lambda do
25
+ def self.backend
26
+ @backend ||= lambda do
26
27
  [
27
- ["pass", ::Pass::Clients::Pass],
28
- ["gopass", ::Pass::Clients::GoPass]
28
+ ["pass", ::Pass::Backend::Pass],
29
+ ["gopass", ::Pass::Backend::GoPass]
29
30
  ].each do |program, klass|
30
31
  r = QProcess.execute(program, QStringList.new << "--version")
31
32
  return klass.new if r.zero?
32
33
  end
33
34
 
34
- ::Pass::Clients::Pass.new
35
+ ::Pass::Backend::Pass.new
35
36
  end.call
36
37
  end
38
+ private_class_method :backend
37
39
  end
data/lib/pass-qt/lib.rb CHANGED
@@ -1,2 +1,2 @@
1
- require_relative "lib/contrib"
1
+ require_relative "lib/ctrlc"
2
2
  require_relative "lib/pass"
@@ -1,3 +1,3 @@
1
1
  module PassQt
2
- VERSION = "2.0.7"
2
+ VERSION = "2.1.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-pass-qt
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.7
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Doe
@@ -38,32 +38,38 @@ files:
38
38
  - exe/ruby-pass-qt
39
39
  - lib/pass-qt.rb
40
40
  - lib/pass-qt/app.rb
41
- - lib/pass-qt/app/assets/README.md
42
- - lib/pass-qt/app/assets/app.svg
43
- - lib/pass-qt/app/components.rb
44
- - lib/pass-qt/app/components/passinfowidget.rb
45
- - lib/pass-qt/app/components/passinfowidget/helpers.rb
46
- - lib/pass-qt/app/components/passlistwidget.rb
47
- - lib/pass-qt/app/components/passlistwidget/treewidget.rb
48
- - lib/pass-qt/app/components/passlistwidget/treewidget/helpers.rb
49
- - lib/pass-qt/app/components/passlistwidget/treewidget/treebuilder.rb
50
- - lib/pass-qt/app/components/passlistwidget/treewidget/treefilter.rb
51
41
  - lib/pass-qt/app/views.rb
52
42
  - lib/pass-qt/app/views/browsestoresdialog.rb
43
+ - lib/pass-qt/app/views/browsestoresdialog/ui.rb
53
44
  - lib/pass-qt/app/views/mainwindow.rb
45
+ - lib/pass-qt/app/views/mainwindow/components.rb
46
+ - lib/pass-qt/app/views/mainwindow/components/passinfowidget.rb
47
+ - lib/pass-qt/app/views/mainwindow/components/passinfowidget/helpers.rb
48
+ - lib/pass-qt/app/views/mainwindow/components/passinfowidget/ui.rb
49
+ - lib/pass-qt/app/views/mainwindow/components/passlistwidget.rb
50
+ - lib/pass-qt/app/views/mainwindow/components/passlistwidget/treewidget.rb
51
+ - lib/pass-qt/app/views/mainwindow/components/passlistwidget/treewidget/funcs.rb
52
+ - lib/pass-qt/app/views/mainwindow/components/passlistwidget/treewidget/funcs/filter.rb
53
+ - lib/pass-qt/app/views/mainwindow/components/passlistwidget/treewidget/funcs/refresh.rb
54
+ - lib/pass-qt/app/views/mainwindow/components/passlistwidget/treewidget/helpers.rb
55
+ - lib/pass-qt/app/views/mainwindow/components/passlistwidget/treewidget/ui.rb
56
+ - lib/pass-qt/app/views/mainwindow/components/passlistwidget/ui.rb
57
+ - lib/pass-qt/app/views/mainwindow/ui.rb
54
58
  - lib/pass-qt/app/views/newonetimepassworddialog.rb
59
+ - lib/pass-qt/app/views/newonetimepassworddialog/ui.rb
55
60
  - lib/pass-qt/app/views/newpassworddialog.rb
61
+ - lib/pass-qt/app/views/newpassworddialog/ui.rb
56
62
  - lib/pass-qt/config.rb
57
63
  - lib/pass-qt/config/initializers/qt6.rb
58
64
  - lib/pass-qt/config/settings.rb
59
65
  - lib/pass-qt/lib.rb
60
- - lib/pass-qt/lib/contrib.rb
61
- - lib/pass-qt/lib/contrib/process.rb
62
- - lib/pass-qt/lib/contrib/sighandler.rb
66
+ - lib/pass-qt/lib/ctrlc.rb
67
+ - lib/pass-qt/lib/ctrlc/handler.rb
63
68
  - lib/pass-qt/lib/pass.rb
64
- - lib/pass-qt/lib/pass/clients.rb
65
- - lib/pass-qt/lib/pass/clients/gopass.rb
66
- - lib/pass-qt/lib/pass/clients/pass.rb
69
+ - lib/pass-qt/lib/pass/backend.rb
70
+ - lib/pass-qt/lib/pass/backend/gopass.rb
71
+ - lib/pass-qt/lib/pass/backend/pass.rb
72
+ - lib/pass-qt/lib/pass/process.rb
67
73
  - lib/pass-qt/version.rb
68
74
  - misc/screenshots/mainwindow.png
69
75
  homepage: https://github.com/souk4711/ruby-pass-qt
@@ -1,5 +0,0 @@
1
- # Assets
2
-
3
- ## License
4
-
5
- - [app.svg](./app.svg) come from [vinceliuice/Colloid-icon-theme](https://github.com/vinceliuice/Colloid-icon-theme)
@@ -1 +0,0 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><image xlink:href="data:image/png;base64,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" width="62.749" height="62.749" x=".625" y="1.25" preserveAspectRatio="none"/><rect width="55.999" height="55.999" x="4" y="4" fill="#124aa0" rx="13" ry="13"/><path d="M3.998 45.998v1c0 7.203 5.8 13.004 13.004 13.004h29.996c7.203 0 13.004-5.8 13.004-13.004v-1c0 7.203-5.8 13.002-13.004 13.002H17.002A12.975 12.975 0 0 1 3.998 45.998" opacity=".15"/><path fill="#fff" d="M3.998 18.004v-1C3.998 9.801 9.798 4 17.002 4h29.996c7.203 0 13.004 5.8 13.004 13.004v1c0-7.203-5.8-13.002-13.004-13.002H17.002A12.975 12.975 0 0 0 3.998 18.004" opacity=".15"/><path fill="#fff" d="M20.537 18c-3.036 0-5.992 2.477-5.478 5.455l3.287 19.09C18.859 45.524 20.79 48 23.826 48h15.348c3.036 0 4.967-2.476 5.48-5.455l3.288-19.09C48.455 20.477 45.499 18 42.463 18zM31.5 25a5.5 5.5 0 0 1 5.5 5.5 5.5 5.5 0 0 1-3 4.898V40.5c0 .831-.669 1.5-1.5 1.5h-2c-.831 0-1.5-.669-1.5-1.5v-5.107a5.5 5.5 0 0 1-3-4.893 5.5 5.5 0 0 1 5.5-5.5"/></svg>
@@ -1,26 +0,0 @@
1
- class PassInfoWidget < RubyQt6::Bando::QWidget
2
- module Helpers
3
- def self.parse_passfile(data)
4
- lines = data["stdout"].lines
5
- password = lines[0][..-2]
6
-
7
- username = ""
8
- website = ""
9
- lines.each do |line|
10
- matched = line.match(/\A(\w+:\s*)?(.*)\n/)
11
- next if matched.nil?
12
-
13
- case matched[1]&.rstrip&.downcase
14
- when "username:" then username = matched[2]
15
- when "website:" then website = matched[2]
16
- end
17
- end
18
-
19
- {
20
- "password" => password,
21
- "username" => username,
22
- "website" => website
23
- }
24
- end
25
- end
26
- end
@@ -1,18 +0,0 @@
1
- class PassListWidget < RubyQt6::Bando::QWidget
2
- class TreeWidget < RubyQt6::Bando::QTreeWidget
3
- module Helpers
4
- def self.passfile?(fileinfo)
5
- case fileinfo
6
- when QFileInfo then fileinfo.suffix.downcase == "gpg"
7
- when QString then fileinfo.ends_with(".gpg", Qt::CaseInsensitive)
8
- else raise "unreachable!"
9
- end
10
- end
11
-
12
- def self.folderpath(store, fileinfo)
13
- folder = fileinfo.dir? ? fileinfo.absolute_file_path : fileinfo.absolute_path
14
- QDir.new(store).relative_file_path(folder)
15
- end
16
- end
17
- end
18
- end
@@ -1,46 +0,0 @@
1
- class PassListWidget < RubyQt6::Bando::QWidget
2
- class TreeWidget < RubyQt6::Bando::QTreeWidget
3
- DataItem = Struct.new(:passname, :treewidgetitem)
4
-
5
- class TreeBuilder
6
- def initialize
7
- @fileiconprovider = QFileIconProvider.new
8
- end
9
-
10
- def perform(treewidget, store, dataitems)
11
- treewidget.clear
12
-
13
- store_root_path = QDir.new(store)
14
- dirs = [store]
15
- until dirs.empty?
16
- dir = dirs.shift
17
- diritem = dataitems[dir]&.treewidgetitem || treewidget.invisible_root_item
18
-
19
- entry_list = QDir.new(dir).entry_info_list(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)
20
- entry_list.each do |entry|
21
- next if entry.hidden?
22
- next if entry.file_name.starts_with(".")
23
-
24
- filepath = entry.absolute_file_path
25
- next if dataitems.key?(filepath)
26
-
27
- if entry.dir?
28
- dirs << filepath
29
- passname = store_root_path.relative_file_path(filepath)
30
- elsif entry.file?
31
- next unless Helpers.passfile?(entry)
32
- passname = store_root_path.relative_file_path(filepath)
33
- passname = passname[0, passname.size - entry.suffix.size - 1]
34
- else
35
- next
36
- end
37
-
38
- item = QTreeWidgetItem.new(diritem, QStringList.new << entry.complete_base_name << filepath)
39
- item.set_icon(0, @fileiconprovider.icon(entry))
40
- dataitems[filepath] = DataItem.new(passname, item)
41
- end
42
- end
43
- end
44
- end
45
- end
46
- end
@@ -1,45 +0,0 @@
1
- class PassListWidget < RubyQt6::Bando::QWidget
2
- class TreeWidget < RubyQt6::Bando::QTreeWidget
3
- class TreeFilter
4
- def perform(treewidget, dataitems, text)
5
- treewidget.set_current_item(nil)
6
-
7
- if text.empty?
8
- dataitems.each do |_, item|
9
- item.treewidgetitem.set_hidden(false)
10
- item.treewidgetitem.set_selected(false)
11
- end
12
- return
13
- end
14
-
15
- re_options = QRegularExpression::UnanchoredWildcardConversion | QRegularExpression::NonPathWildcardConversion
16
- re = QRegularExpression.from_wildcard(text, nil, re_options)
17
-
18
- filepath_matched = Set.new
19
- filepath_matched_1st = nil
20
- dataitems.each do |filepath, item|
21
- has_match = re.match(item.passname).has_match
22
- next unless has_match
23
-
24
- if filepath_matched_1st.nil?
25
- filepath_matched_1st = filepath if Helpers.passfile?(filepath)
26
- end
27
-
28
- loop do
29
- filepath_matched << filepath
30
- filepath = QFileInfo.new(filepath).absolute_path
31
- break unless dataitems.key?(filepath)
32
- end
33
- end
34
-
35
- dataitems.each do |filepath, item|
36
- visible = filepath_matched.include?(filepath)
37
- item.treewidgetitem.set_hidden(!visible)
38
-
39
- selected = filepath_matched_1st == filepath
40
- item.treewidgetitem.set_selected(selected)
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,2 +0,0 @@
1
- require_relative "contrib/process"
2
- require_relative "contrib/sighandler"
@@ -1,2 +0,0 @@
1
- require_relative "clients/pass"
2
- require_relative "clients/gopass"