twterm 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/lib/twterm.rb +4 -4
  4. data/lib/twterm/app.rb +4 -1
  5. data/lib/twterm/direct_message_composer.rb +2 -1
  6. data/lib/twterm/environment.rb +5 -0
  7. data/lib/twterm/event/{base.rb → abstract_event.rb} +1 -1
  8. data/lib/twterm/event/direct_message/fetched.rb +2 -2
  9. data/lib/twterm/event/message/abstract_message.rb +2 -2
  10. data/lib/twterm/event/notification/abstract_notification.rb +2 -2
  11. data/lib/twterm/event/open_photo.rb +13 -0
  12. data/lib/twterm/event/open_uri.rb +2 -2
  13. data/lib/twterm/event/screen/refresh.rb +13 -0
  14. data/lib/twterm/event/screen/resize.rb +2 -2
  15. data/lib/twterm/event/status/{base.rb → abstract_status_event.rb} +2 -2
  16. data/lib/twterm/event/status/delete.rb +2 -2
  17. data/lib/twterm/event/status/mention.rb +2 -2
  18. data/lib/twterm/event/status/timeline.rb +2 -2
  19. data/lib/twterm/event/status_garbage_collected.rb +2 -2
  20. data/lib/twterm/event/user_garbage_collected.rb +2 -2
  21. data/lib/twterm/event_dispatcher.rb +2 -2
  22. data/lib/twterm/photo_viewer.rb +36 -0
  23. data/lib/twterm/photo_viewer_backend/abstract_photo_viewer_backend.rb +46 -0
  24. data/lib/twterm/photo_viewer_backend/browser_backend.rb +16 -0
  25. data/lib/twterm/photo_viewer_backend/imgcat_backend.rb +33 -0
  26. data/lib/twterm/photo_viewer_backend/quick_look_backend.rb +13 -0
  27. data/lib/twterm/preferences.rb +10 -0
  28. data/lib/twterm/publisher.rb +2 -2
  29. data/lib/twterm/rest_client.rb +5 -5
  30. data/lib/twterm/screen.rb +8 -6
  31. data/lib/twterm/status.rb +7 -1
  32. data/lib/twterm/tab/{base.rb → abstract_tab.rb} +1 -1
  33. data/lib/twterm/tab/direct_message/conversation.rb +2 -2
  34. data/lib/twterm/tab/direct_message/conversation_list.rb +2 -2
  35. data/lib/twterm/tab/key_assignments_cheatsheet.rb +2 -2
  36. data/lib/twterm/tab/new/{start.rb → index.rb} +2 -2
  37. data/lib/twterm/tab/new/list.rb +2 -2
  38. data/lib/twterm/tab/new/search.rb +6 -3
  39. data/lib/twterm/tab/new/user.rb +8 -7
  40. data/lib/twterm/tab/preferences/index.rb +9 -3
  41. data/lib/twterm/tab/preferences/notification_backend.rb +2 -2
  42. data/lib/twterm/tab/preferences/photo_viewer_backend.rb +86 -0
  43. data/lib/twterm/tab/rate_limit_status.rb +1 -1
  44. data/lib/twterm/tab/status_tab.rb +4 -3
  45. data/lib/twterm/tab/statuses/{base.rb → abstract_statuses_tab.rb} +2 -2
  46. data/lib/twterm/tab/statuses/conversation.rb +2 -2
  47. data/lib/twterm/tab/statuses/favorites.rb +2 -2
  48. data/lib/twterm/tab/statuses/home.rb +2 -2
  49. data/lib/twterm/tab/statuses/list_timeline.rb +2 -2
  50. data/lib/twterm/tab/statuses/mentions.rb +2 -2
  51. data/lib/twterm/tab/statuses/search.rb +2 -2
  52. data/lib/twterm/tab/statuses/user_timeline.rb +2 -2
  53. data/lib/twterm/tab/user_list_management.rb +1 -1
  54. data/lib/twterm/tab/user_tab.rb +2 -2
  55. data/lib/twterm/tab/users/{base.rb → abstract_users_tab.rb} +2 -2
  56. data/lib/twterm/tab/users/followers.rb +2 -2
  57. data/lib/twterm/tab/users/friends.rb +2 -2
  58. data/lib/twterm/tab_manager.rb +2 -2
  59. data/lib/twterm/tweetbox.rb +20 -16
  60. data/lib/twterm/version.rb +1 -1
  61. data/spec/twterm/event_dispatcher_spec.rb +1 -1
  62. data/twterm.gemspec +1 -1
  63. metadata +20 -13
  64. data/lib/twterm/tab/favorites.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d251a92afa7b450c2da0556f66fe431d6db851633b739601e0c47cb5ad45baa5
4
- data.tar.gz: a014a40ac7b5d15859880b157375ebe372e011a4a76153fc93b66075ad3a594c
3
+ metadata.gz: 3ed5b1fe74b479cd44e106d99f63dcbc348d3f3c67b4f1dd537edd9c8dd9044c
4
+ data.tar.gz: 1969619f0f236f559409b7eaf4f9ac49e8d7226e5068e405ebd18955080b7260
5
5
  SHA512:
6
- metadata.gz: 5dc37cf71fa46b22cb7e69efc5a3ad09c2fd0a65ba8c77869e6d2a494159aace7691653fe0b001952edef57153a39f5be1715ca0447fc1aa04712130aabc40f5
7
- data.tar.gz: de94a92f370e94e509063132cd69a8525df015d9825393e7570ba7d55c99466042aaab7d4261ac1e6559b4518703792ead41433a8c2ad1817115e01a7c3e7da3
6
+ metadata.gz: 2a78e4c7a2b71df77830a3639d16610de65f05ae4ca9d2a56790e7a542eb41b5a476db5e60adc784eb0905649eab2827acfdd2c93111e4d3a49afd5785f51002
7
+ data.tar.gz: d7625b41113573124d36363e5848e794698c17cb332aef8e47bdf9c54548a750ebc8003a92051a72fca8414c9b5393fffbb3b31aaf54c0bed3ce664f78c79263
data/README.md CHANGED
@@ -9,6 +9,7 @@ A full-featured TUI Twitter client
9
9
  - Ruby (>= 2.1, compiled with ncurses and Readline)
10
10
  - ncurses
11
11
  - Readline
12
+ - [GNU Libidn](https://www.gnu.org/software/libidn/)
12
13
 
13
14
  ## Installation
14
15
 
data/lib/twterm.rb CHANGED
@@ -31,16 +31,16 @@ require 'twterm/screen'
31
31
  require 'twterm/scheduler'
32
32
  require 'twterm/status'
33
33
  require 'twterm/tab_manager'
34
- require 'twterm/tab/base'
34
+ require 'twterm/tab/abstract_tab'
35
35
  require 'twterm/tab/dumpable'
36
36
  require 'twterm/tab/exceptions'
37
37
  require 'twterm/tab/scrollable'
38
38
  require 'twterm/tab/key_assignments_cheatsheet'
39
- require 'twterm/tab/new/start'
39
+ require 'twterm/tab/new/index'
40
40
  require 'twterm/tab/new/list'
41
41
  require 'twterm/tab/new/search'
42
42
  require 'twterm/tab/new/user'
43
- require 'twterm/tab/statuses/base'
43
+ require 'twterm/tab/statuses/abstract_statuses_tab'
44
44
  require 'twterm/tab/statuses/conversation'
45
45
  require 'twterm/tab/statuses/favorites'
46
46
  require 'twterm/tab/statuses/home'
@@ -49,7 +49,7 @@ require 'twterm/tab/statuses/mentions'
49
49
  require 'twterm/tab/statuses/search'
50
50
  require 'twterm/tab/statuses/user_timeline'
51
51
  require 'twterm/tab/user_tab'
52
- require 'twterm/tab/users/base'
52
+ require 'twterm/tab/users/abstract_users_tab'
53
53
  require 'twterm/tab/users/followers'
54
54
  require 'twterm/tab/users/friends'
55
55
  require 'twterm/tweetbox'
data/lib/twterm/app.rb CHANGED
@@ -3,11 +3,13 @@ require 'curses'
3
3
  require 'twterm/completion_manager'
4
4
  require 'twterm/direct_message_composer'
5
5
  require 'twterm/environment'
6
+ require 'twterm/event/screen/refresh'
6
7
  require 'twterm/event/screen/resize'
7
8
  require 'twterm/message_window'
8
9
  require 'twterm/notification_dispatcher'
9
10
  require 'twterm/persistable_configuration_proxy'
10
11
  require 'twterm/preferences'
12
+ require 'twterm/photo_viewer'
11
13
  require 'twterm/repository/direct_message_repository'
12
14
  require 'twterm/repository/friendship_repository'
13
15
  require 'twterm/repository/hashtag_repository'
@@ -75,6 +77,7 @@ module Twterm
75
77
  MessageWindow.instance
76
78
 
77
79
  @notification_dispatcher = NotificationDispatcher.new(preferences)
80
+ @photo_viewer = PhotoViewer.new(preferences)
78
81
 
79
82
  timeline = Tab::Statuses::Home.new(self, client)
80
83
  tab_manager.add_and_show(timeline)
@@ -84,7 +87,7 @@ module Twterm
84
87
  tab_manager.add(mentions_tab)
85
88
  tab_manager.recover_tabs
86
89
 
87
- screen.refresh
90
+ publish(Event::Screen::Refresh.new)
88
91
 
89
92
  client.connect_user_stream
90
93
 
@@ -1,3 +1,4 @@
1
+ require 'twterm/event/screen/refresh'
1
2
  require 'twterm/publisher'
2
3
  require 'twterm/user'
3
4
  require 'twterm/utils'
@@ -21,7 +22,7 @@ module Twterm
21
22
  resetter = proc do
22
23
  reset_prog_mode
23
24
  sleep 0.1
24
- app.screen.refresh
25
+ publish(Event::Screen::Refresh.new)
25
26
  end
26
27
 
27
28
  thread = Thread.new do
@@ -7,6 +7,7 @@ module Twterm
7
7
 
8
8
  @terminal_notifier_available = TerminalNotifier.available?
9
9
  @with_eog = system('which eog 2>&1 >/dev/null')
10
+ @with_imgcat = system('which imgcat 2>&1 >/dev/null')
10
11
  @with_tmux = system('which tmux 2>&1 >/dev/null') && !ENV['TMUX'].nil?
11
12
  @with_qlmanage = system('which qlmanage 2>&1 >/dev/null')
12
13
  end
@@ -27,6 +28,10 @@ module Twterm
27
28
  @with_eog
28
29
  end
29
30
 
31
+ def with_imgcat?
32
+ @with_imgcat
33
+ end
34
+
30
35
  def with_qlmanage?
31
36
  @with_qlmanage
32
37
  end
@@ -2,7 +2,7 @@ require 'twterm/utils'
2
2
 
3
3
  module Twterm
4
4
  module Event
5
- class Base
5
+ class AbstractEvent
6
6
  include Utils
7
7
 
8
8
  def initialize(*args)
@@ -1,9 +1,9 @@
1
- require 'twterm/event/base'
1
+ require 'twterm/event/abstract_event'
2
2
 
3
3
  module Twterm
4
4
  module Event
5
5
  module DirectMessage
6
- class Fetched < Base
6
+ class Fetched < AbstractEvent
7
7
  end
8
8
  end
9
9
  end
@@ -1,9 +1,9 @@
1
- require 'twterm/event/base'
1
+ require 'twterm/event/abstract_event'
2
2
 
3
3
  module Twterm
4
4
  module Event
5
5
  module Message
6
- class AbstractMessage < Twterm::Event::Base
6
+ class AbstractMessage < AbstractEvent
7
7
  attr_reader :time
8
8
 
9
9
  def initialize(message)
@@ -1,10 +1,10 @@
1
- require 'twterm/event/base'
1
+ require 'twterm/event/abstract_event'
2
2
 
3
3
  module Twterm
4
4
  module Event
5
5
  module Notification
6
6
  # @abstract
7
- class AbstractNotification < Event::Base
7
+ class AbstractNotification < AbstractEvent
8
8
  # @abstract
9
9
  # @return [String] notification body
10
10
  def body
@@ -0,0 +1,13 @@
1
+ require 'twitter'
2
+
3
+ require 'twterm/event/abstract_event'
4
+
5
+ module Twterm
6
+ module Event
7
+ class OpenPhoto < AbstractEvent
8
+ def fields
9
+ { photo: Twitter::Media::Photo }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,8 +1,8 @@
1
- require 'twterm/event/base'
1
+ require 'twterm/event/abstract_event'
2
2
 
3
3
  module Twterm
4
4
  module Event
5
- class OpenURI < Base
5
+ class OpenURI < AbstractEvent
6
6
  def fields
7
7
  { uri: Addressable::URI }
8
8
  end
@@ -0,0 +1,13 @@
1
+ require 'twterm/event/abstract_event'
2
+
3
+ module Twterm
4
+ module Event
5
+ module Screen
6
+ class Refresh < AbstractEvent
7
+ def fields
8
+ {}
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,9 +1,9 @@
1
- require 'twterm/event/base'
1
+ require 'twterm/event/abstract_event'
2
2
 
3
3
  module Twterm
4
4
  module Event
5
5
  module Screen
6
- class Resize < Base
6
+ class Resize < AbstractEvent
7
7
  def fields
8
8
  { lines: Integer, cols: Integer }
9
9
  end
@@ -1,10 +1,10 @@
1
1
  require 'twterm/status'
2
- require 'twterm/event/base'
2
+ require 'twterm/event/abstract_event'
3
3
 
4
4
  module Twterm
5
5
  module Event
6
6
  module Status
7
- class Base < ::Twterm::Event::Base
7
+ class AbstractStatusEvent < AbstractEvent
8
8
  def fields
9
9
  { status: ::Twterm::Status }
10
10
  end
@@ -1,9 +1,9 @@
1
- require 'twterm/event/base'
1
+ require 'twterm/event/abstract_event'
2
2
 
3
3
  module Twterm
4
4
  module Event
5
5
  module Status
6
- class Delete < Base
6
+ class Delete < AbstractStatusEvent
7
7
  def fields
8
8
  { status_id: Integer }
9
9
  end
@@ -1,9 +1,9 @@
1
- require 'twterm/event/status/base'
1
+ require 'twterm/event/status/abstract_status_event'
2
2
 
3
3
  module Twterm
4
4
  module Event
5
5
  module Status
6
- class Mention < Base
6
+ class Mention < AbstractStatusEvent
7
7
  end
8
8
  end
9
9
  end
@@ -1,9 +1,9 @@
1
- require 'twterm/event/status/base'
1
+ require 'twterm/event/status/abstract_status_event'
2
2
 
3
3
  module Twterm
4
4
  module Event
5
5
  module Status
6
- class Timeline < Base
6
+ class Timeline < AbstractStatusEvent
7
7
  end
8
8
  end
9
9
  end
@@ -1,8 +1,8 @@
1
- require 'twterm/event/base'
1
+ require 'twterm/event/abstract_event'
2
2
 
3
3
  module Twterm
4
4
  module Event
5
- class StatusGarbageCollected < Base
5
+ class StatusGarbageCollected < AbstractEvent
6
6
  def fields
7
7
  {
8
8
  id: Integer
@@ -1,8 +1,8 @@
1
- require 'twterm/event/base'
1
+ require 'twterm/event/abstract_event'
2
2
 
3
3
  module Twterm
4
4
  module Event
5
- class UserGarbageCollected < Base
5
+ class UserGarbageCollected < AbstractEvent
6
6
  def fields
7
7
  {
8
8
  id: Integer
@@ -21,8 +21,8 @@ module Twterm
21
21
 
22
22
  def register_subscription(subscriber_id, event, callback)
23
23
  check_type Class, event
24
- unless event <= Event::Base
25
- raise TypeError, 'the second argument must be a subclass of Twterm::Event::Base'
24
+ unless event <= Event::AbstractEvent
25
+ raise TypeError, 'the second argument must be a subclass of Twterm::Event::AbstractEvent'
26
26
  end
27
27
 
28
28
  @subscriptions << Subscription.new(subscriber_id, event, callback)
@@ -0,0 +1,36 @@
1
+ require 'twterm/event/open_photo'
2
+ require 'twterm/photo_viewer_backend/browser_backend'
3
+ require 'twterm/photo_viewer_backend/imgcat_backend'
4
+ require 'twterm/photo_viewer_backend/quick_look_backend'
5
+ require 'twterm/subscriber'
6
+
7
+ module Twterm
8
+ class PhotoViewer
9
+ include Subscriber
10
+
11
+ # @param preferences [Twterm::Preferences]
12
+ def initialize(preferences)
13
+ @preferences = preferences
14
+
15
+ @backends = {
16
+ browser: PhotoViewerBackend::BrowserBackend.new,
17
+ imgcat: PhotoViewerBackend::ImgcatBackend.new,
18
+ quick_look: PhotoViewerBackend::QuickLookBackend.new,
19
+ }
20
+
21
+ subscribe(Event::OpenPhoto) { |n| view(n.photo) }
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :backends, :preferences
27
+
28
+ # @param photo [Twitter::Media::Photo]
29
+ # @return [void]
30
+ def view(photo)
31
+ backends.each do |key, backend|
32
+ backend.view(photo) if preferences[:photo_viewer_backend, key]
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,46 @@
1
+ require 'concurrent'
2
+
3
+ module Twterm
4
+ module PhotoViewerBackend
5
+ # @abstract
6
+ class AbstractPhotoViewerBackend
7
+ # @abstract
8
+ def view(_photo)
9
+ raise NotImplementedError, '`view` method must be implemented'
10
+ end
11
+
12
+ private
13
+
14
+ def getc
15
+ system('stty raw -echo')
16
+ STDIN.getc
17
+ ensure
18
+ system('stty -raw echo')
19
+ end
20
+
21
+ # @param url [String]
22
+ # @yieldparam file [File]
23
+ def with_downloaded_file(url, &block)
24
+ uri = URI.parse(url)
25
+
26
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
27
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
28
+ res = http.get(uri.path)
29
+
30
+ case res
31
+ when Net::HTTPSuccess
32
+ Tempfile.open(['', '.jpg'], Dir.tmpdir) do |file|
33
+ file.binmode
34
+ file.write(res.body)
35
+ file.flush
36
+
37
+ block.call(file)
38
+ end
39
+ else
40
+ raise res
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,16 @@
1
+ require 'twterm/photo_viewer_backend/abstract_photo_viewer_backend'
2
+ require 'twterm/publisher'
3
+ require 'twterm/event/open_uri'
4
+
5
+ module Twterm
6
+ module PhotoViewerBackend
7
+ class BrowserBackend < AbstractPhotoViewerBackend
8
+ include Publisher
9
+
10
+ def view(photo)
11
+ event = Event::OpenURI.new(photo.media_url_https)
12
+ publish(event)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,33 @@
1
+ require 'curses'
2
+
3
+ require 'twterm/event/screen/refresh'
4
+ require 'twterm/photo_viewer_backend/abstract_photo_viewer_backend'
5
+ require 'twterm/publisher'
6
+
7
+ module Twterm
8
+ module PhotoViewerBackend
9
+ class ImgcatBackend < AbstractPhotoViewerBackend
10
+ include Publisher
11
+
12
+ def view(photo)
13
+ Curses.close_screen unless Curses.closed?
14
+
15
+ puts "\e[H\e[2JDownloading..."
16
+
17
+ with_downloaded_file(photo.media_url_https) do |file|
18
+ begin
19
+ puts "\e[H\e[2JRendering..."
20
+ system "imgcat #{file.path}"
21
+ getc
22
+ ensure
23
+ puts "\e[H\e[2J"
24
+ Curses.reset_prog_mode
25
+ sleep 0.1
26
+ publish(Event::Screen::Refresh.new)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+