twterm 1.3.0 → 2.0.0.beta1
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.
- checksums.yaml +4 -4
- data/README.md +14 -18
- data/bin/twterm +1 -1
- data/lib/twterm/app.rb +120 -30
- data/lib/twterm/client.rb +10 -13
- data/lib/twterm/completion_mamanger.rb +11 -6
- data/lib/twterm/direct_message.rb +6 -28
- data/lib/twterm/direct_message_composer.rb +10 -5
- data/lib/twterm/direct_message_manager.rb +5 -6
- data/lib/twterm/event/notification/abstract_notification.rb +27 -0
- data/lib/twterm/event/notification/error.rb +13 -0
- data/lib/twterm/event/notification/info.rb +13 -0
- data/lib/twterm/event/notification/success.rb +13 -0
- data/lib/twterm/event/notification/warning.rb +13 -0
- data/lib/twterm/event_dispatcher.rb +1 -1
- data/lib/twterm/extensions/array.rb +5 -0
- data/lib/twterm/extensions/enumerator/lazy.rb +3 -0
- data/lib/twterm/extensions/string.rb +0 -4
- data/lib/twterm/friendship.rb +1 -85
- data/lib/twterm/image/between.rb +31 -0
- data/lib/twterm/image/blank_line.rb +21 -0
- data/lib/twterm/image/bold.rb +31 -0
- data/lib/twterm/image/brackets.rb +21 -0
- data/lib/twterm/image/color.rb +45 -0
- data/lib/twterm/image/empty.rb +21 -0
- data/lib/twterm/image/horizontal_sequential_image.rb +48 -0
- data/lib/twterm/image/parens.rb +21 -0
- data/lib/twterm/image/string_image.rb +38 -0
- data/lib/twterm/image/vertical_sequential_image.rb +43 -0
- data/lib/twterm/image.rb +107 -0
- data/lib/twterm/key_mapper/abstract_key_mapper.rb +51 -0
- data/lib/twterm/key_mapper/app_key_mapper.rb +13 -0
- data/lib/twterm/key_mapper/cursor_key_mapper.rb +13 -0
- data/lib/twterm/key_mapper/general_key_mapper.rb +18 -0
- data/lib/twterm/key_mapper/no_such_command.rb +20 -0
- data/lib/twterm/key_mapper/no_such_key.rb +16 -0
- data/lib/twterm/key_mapper/status_key_mapper.rb +18 -0
- data/lib/twterm/key_mapper/tab_key_mapper.rb +31 -0
- data/lib/twterm/key_mapper.rb +127 -0
- data/lib/twterm/list.rb +0 -31
- data/lib/twterm/notifier.rb +7 -7
- data/lib/twterm/repository/abstract_entity_repository.rb +41 -0
- data/lib/twterm/repository/abstract_expirable_entity_repository.rb +35 -0
- data/lib/twterm/repository/abstract_repository.rb +64 -0
- data/lib/twterm/repository/direct_message_repository.rb +14 -0
- data/lib/twterm/repository/friendship_repository.rb +108 -0
- data/lib/twterm/repository/hashtag_repository.rb +39 -0
- data/lib/twterm/repository/list_repository.rb +14 -0
- data/lib/twterm/repository/status_repository.rb +36 -0
- data/lib/twterm/repository/user_repository.rb +22 -0
- data/lib/twterm/rest_client.rb +107 -63
- data/lib/twterm/screen.rb +21 -15
- data/lib/twterm/search_query_window.rb +139 -0
- data/lib/twterm/status.rb +14 -108
- data/lib/twterm/streaming_client.rb +13 -12
- data/lib/twterm/tab/base.rb +48 -8
- data/lib/twterm/tab/direct_message/conversation.rb +53 -52
- data/lib/twterm/tab/direct_message/conversation_list.rb +46 -45
- data/lib/twterm/tab/dumpable.rb +3 -3
- data/lib/twterm/tab/key_assignments_cheatsheet.rb +58 -57
- data/lib/twterm/tab/loadable.rb +20 -0
- data/lib/twterm/tab/new/list.rb +32 -43
- data/lib/twterm/tab/new/search.rb +31 -44
- data/lib/twterm/tab/new/start.rb +44 -55
- data/lib/twterm/tab/new/user.rb +15 -12
- data/lib/twterm/tab/rate_limit_status.rb +84 -0
- data/lib/twterm/tab/scrollable.rb +39 -19
- data/lib/twterm/tab/searchable.rb +133 -0
- data/lib/twterm/tab/statuses/base.rb +139 -129
- data/lib/twterm/tab/statuses/conversation.rb +26 -15
- data/lib/twterm/tab/statuses/favorites.rb +10 -8
- data/lib/twterm/tab/statuses/home.rb +10 -9
- data/lib/twterm/tab/statuses/list_timeline.rb +12 -8
- data/lib/twterm/tab/statuses/mentions.rb +17 -11
- data/lib/twterm/tab/statuses/search.rb +8 -5
- data/lib/twterm/tab/statuses/user_timeline.rb +11 -8
- data/lib/twterm/tab/user_list_management.rb +109 -0
- data/lib/twterm/tab/user_tab.rb +125 -126
- data/lib/twterm/tab/users/base.rb +39 -41
- data/lib/twterm/tab/users/followers.rb +9 -6
- data/lib/twterm/tab/users/friends.rb +9 -6
- data/lib/twterm/tab_manager.rb +64 -40
- data/lib/twterm/tweetbox.rb +18 -13
- data/lib/twterm/uri_opener.rb +2 -1
- data/lib/twterm/user.rb +2 -110
- data/lib/twterm/version.rb +1 -1
- data/lib/twterm/view.rb +30 -0
- data/lib/twterm.rb +3 -9
- data/spec/fixtures/status.json +107 -0
- data/spec/fixtures/user.json +102 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/supports/shared_examples/abstract_key_mapper.rb +17 -0
- data/spec/twterm/extension/enumerator/lazy_spec.rb +11 -0
- data/spec/twterm/friendship_spec.rb +0 -102
- data/spec/twterm/image/blank_line_spec.rb +11 -0
- data/spec/twterm/image/brackets_spec.rb +12 -0
- data/spec/twterm/image/color_spec.rb +22 -0
- data/spec/twterm/image/empry_spec.rb +11 -0
- data/spec/twterm/image/horizontal_sequential_image_spec.rb +15 -0
- data/spec/twterm/image/parens_spec.rb +12 -0
- data/spec/twterm/image/string_image_spec.rb +12 -0
- data/spec/twterm/image/vertical_sequential_image_spec.rb +14 -0
- data/spec/twterm/image_spec.rb +65 -0
- data/spec/twterm/key_mapper/abstract_key_mapper_spec.rb +21 -0
- data/spec/twterm/key_mapper/app_key_mapper_spec.rb +7 -0
- data/spec/twterm/key_mapper/status_key_mapper_spec.rb +7 -0
- data/spec/twterm/key_mapper/tab_key_mapper_spec.rb +7 -0
- data/spec/twterm/repository/friendship_repository_spec.rb +108 -0
- data/spec/twterm/status_spec.rb +58 -0
- data/spec/twterm/user_spec.rb +94 -0
- data/twterm.gemspec +13 -10
- metadata +129 -35
- data/lib/twterm/event/notification.rb +0 -33
- data/lib/twterm/extensions/integer.rb +0 -5
- data/lib/twterm/filter_query_window.rb +0 -91
- data/lib/twterm/filterable_list.rb +0 -41
- data/lib/twterm/history/base.rb +0 -21
- data/lib/twterm/history/hashtag.rb +0 -13
- data/lib/twterm/history/savable.rb +0 -37
- data/lib/twterm/history/screen_name.rb +0 -11
- data/lib/twterm/promise.rb +0 -143
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 064c6b973d192af1687649528910f091550c24ed
|
4
|
+
data.tar.gz: e7c65c16eb7c113e68b3f8aa9d03fcfafbe703d4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eaa76b8503cd6749d4df7ac6e261ebeb13b1a59cef56d5aba5e327e0946013e46a180a3c5d424cbb8590adba4440e91be3234b78e91564b35e6555afa942c9e2
|
7
|
+
data.tar.gz: 6c92404ae8e51b1867efe30d93bf5bbd2a51ee4dfb06d6e02d8449913222b5d6bda82f7a98fac416718ac19bfad75743e6a428c54fd86fd816e6e0f968eed679
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# twterm
|
2
2
|
|
3
|
-
A full-featured
|
3
|
+
A full-featured TUI Twitter client
|
4
4
|
|
5
5
|
## Screenshot
|
6
6
|
|
@@ -8,8 +8,8 @@ A full-featured CLI Twitter client
|
|
8
8
|
|
9
9
|
## Requirements
|
10
10
|
|
11
|
-
- Ruby (>= 2.1, compiled with
|
12
|
-
-
|
11
|
+
- Ruby (>= 2.1, compiled with ncurses and Readline)
|
12
|
+
- ncurses
|
13
13
|
- Readline
|
14
14
|
|
15
15
|
## Installation
|
@@ -26,25 +26,21 @@ To launch twterm, just type in your console:
|
|
26
26
|
$ twterm
|
27
27
|
```
|
28
28
|
|
29
|
-
###
|
29
|
+
### Default key assignments
|
30
|
+
|
31
|
+
Key assignments can be configured by editing `~/.twterm/keys.toml`
|
30
32
|
|
31
33
|
key | operation
|
32
34
|
--- | ---
|
33
|
-
`
|
34
|
-
`
|
35
|
-
`
|
36
|
-
`
|
37
|
-
`
|
38
|
-
`
|
39
|
-
`n` | compose new tweet
|
40
|
-
`N` | open new tab
|
41
|
-
`r` | reply
|
42
|
-
`R` | retweet
|
35
|
+
`h` `←` | previous tab
|
36
|
+
`j` `↓` | move down
|
37
|
+
`k` `↑` | move up
|
38
|
+
`l` `→` | next tab
|
39
|
+
`^N` | new tweet
|
40
|
+
`^T` | new tab
|
43
41
|
`w` | close current tab
|
44
|
-
`
|
45
|
-
|
46
|
-
|
47
|
-
Type `?` key to see the full list of key assignments.
|
42
|
+
`F10` | quit
|
43
|
+
`F1` | key assignments cheatsheet
|
48
44
|
|
49
45
|
## License
|
50
46
|
|
data/bin/twterm
CHANGED
data/lib/twterm/app.rb
CHANGED
@@ -1,55 +1,120 @@
|
|
1
1
|
require 'curses'
|
2
|
+
|
3
|
+
require 'twterm/completion_mamanger'
|
4
|
+
require 'twterm/direct_message_composer'
|
2
5
|
require 'twterm/event/screen/resize'
|
6
|
+
require 'twterm/repository/direct_message_repository'
|
7
|
+
require 'twterm/repository/friendship_repository'
|
8
|
+
require 'twterm/repository/hashtag_repository'
|
9
|
+
require 'twterm/repository/list_repository'
|
10
|
+
require 'twterm/repository/status_repository'
|
11
|
+
require 'twterm/repository/user_repository'
|
12
|
+
require 'twterm/tab_manager'
|
13
|
+
require 'twterm/tweetbox'
|
3
14
|
require 'twterm/uri_opener'
|
4
15
|
|
5
16
|
module Twterm
|
6
17
|
class App
|
7
18
|
include Publisher
|
8
|
-
|
19
|
+
|
20
|
+
attr_reader :screen
|
9
21
|
|
10
22
|
DATA_DIR = "#{ENV['HOME']}/.twterm".freeze
|
11
23
|
|
12
|
-
def
|
24
|
+
def completion_manager
|
25
|
+
@completion_mamanger ||= CompletionManager.new(self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def direct_message_composer
|
29
|
+
@direct_message_composer ||= DirectMessageComposer.new(self, client)
|
30
|
+
end
|
31
|
+
|
32
|
+
def direct_message_repository
|
33
|
+
@direct_messages_repository ||= Repository::DirectMessageRepository.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def friendship_repository
|
37
|
+
@friendship_repository ||= Repository::FriendshipRepository.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def hashtag_repository
|
41
|
+
@hashtag_repository ||= Repository::HashtagRepository.new
|
42
|
+
end
|
43
|
+
|
44
|
+
def list_repository
|
45
|
+
@list_repository ||= Repository::ListRepository.new
|
46
|
+
end
|
47
|
+
|
48
|
+
def run
|
13
49
|
Dir.mkdir(DATA_DIR, 0700) unless File.directory?(DATA_DIR)
|
14
50
|
|
15
51
|
Auth.authenticate_user(config) if config[:user_id].nil?
|
16
52
|
|
17
|
-
|
18
|
-
FilterQueryWindow.instance
|
53
|
+
KeyMapper.instance
|
19
54
|
|
20
|
-
|
21
|
-
TabManager.instance.add_and_show(timeline)
|
55
|
+
@screen = Screen.new(self, client)
|
22
56
|
|
23
|
-
|
57
|
+
SearchQueryWindow.instance
|
24
58
|
|
25
|
-
|
26
|
-
|
59
|
+
timeline = Tab::Statuses::Home.new(self, client)
|
60
|
+
tab_manager.add_and_show(timeline)
|
27
61
|
|
28
|
-
|
62
|
+
mentions_tab = Tab::Statuses::Mentions.new(self, client)
|
63
|
+
|
64
|
+
tab_manager.add(mentions_tab)
|
65
|
+
tab_manager.recover_tabs
|
66
|
+
|
67
|
+
screen.refresh
|
29
68
|
|
30
69
|
client.connect_user_stream
|
31
70
|
|
32
71
|
reset_interruption_handler
|
33
72
|
|
73
|
+
Signal.trap(:WINCH) { on_resize }
|
74
|
+
Scheduler.new(60) { on_resize }
|
75
|
+
|
34
76
|
URIOpener.instance
|
35
77
|
|
36
|
-
|
37
|
-
|
78
|
+
Scheduler.new(300) do
|
79
|
+
status_repository.expire(3600)
|
38
80
|
|
39
|
-
|
40
|
-
|
41
|
-
publish(Event::Screen::Resize.new(lines, cols))
|
81
|
+
_ = status_repository.all.map { |user_id| user_repository.find(user_id) }
|
82
|
+
user_repository.expire(3600)
|
42
83
|
end
|
43
84
|
|
44
|
-
|
45
|
-
|
46
|
-
|
85
|
+
direct_message_repository.before_create do |dm|
|
86
|
+
user_repository.create(dm.recipient)
|
87
|
+
user_repository.create(dm.sender)
|
88
|
+
end
|
47
89
|
|
48
|
-
|
49
|
-
|
90
|
+
user_repository.before_create do |user|
|
91
|
+
client_id = client.user_id
|
92
|
+
|
93
|
+
if user.following?
|
94
|
+
friendship_repository.follow(client_id, user.id)
|
95
|
+
else
|
96
|
+
friendship_repository.unfollow(client_id, user.id)
|
97
|
+
end
|
98
|
+
|
99
|
+
if user.follow_request_sent?
|
100
|
+
friendship_repository.following_requested(client_id, user.id)
|
101
|
+
else
|
102
|
+
friendship_repository.following_not_requested(client_id, user.id)
|
103
|
+
end
|
104
|
+
end
|
50
105
|
|
51
|
-
|
52
|
-
|
106
|
+
status_repository.before_create do |tweet|
|
107
|
+
user_repository.create(tweet.user)
|
108
|
+
end
|
109
|
+
|
110
|
+
status_repository.before_create do |tweet|
|
111
|
+
tweet.hashtags.each do |hashtag|
|
112
|
+
hashtag_repository.create(hashtag.text)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
screen.wait
|
117
|
+
screen.refresh
|
53
118
|
end
|
54
119
|
|
55
120
|
def register_interruption_handler(&block)
|
@@ -58,15 +123,31 @@ module Twterm
|
|
58
123
|
end
|
59
124
|
|
60
125
|
def reset_interruption_handler
|
61
|
-
Signal.trap(:INT) {
|
126
|
+
Signal.trap(:INT) { quit }
|
62
127
|
end
|
63
128
|
|
64
129
|
def quit
|
65
130
|
Curses.close_screen
|
66
|
-
|
131
|
+
tab_manager.dump_tabs
|
67
132
|
exit
|
68
133
|
end
|
69
134
|
|
135
|
+
def status_repository
|
136
|
+
@status_repository ||= Repository::StatusRepository.new
|
137
|
+
end
|
138
|
+
|
139
|
+
def tab_manager
|
140
|
+
@tab_manager ||= TabManager.new(self, client)
|
141
|
+
end
|
142
|
+
|
143
|
+
def tweetbox
|
144
|
+
@tweetbox = Tweetbox.new(self, client)
|
145
|
+
end
|
146
|
+
|
147
|
+
def user_repository
|
148
|
+
@user_repository ||= Repository::UserRepository.new
|
149
|
+
end
|
150
|
+
|
70
151
|
private
|
71
152
|
|
72
153
|
def client
|
@@ -74,7 +155,15 @@ module Twterm
|
|
74
155
|
config[:user_id].to_i,
|
75
156
|
config[:screen_name],
|
76
157
|
config[:access_token],
|
77
|
-
config[:access_token_secret]
|
158
|
+
config[:access_token_secret],
|
159
|
+
{
|
160
|
+
friendship: friendship_repository,
|
161
|
+
direct_message: direct_message_repository,
|
162
|
+
hashtag: hashtag_repository,
|
163
|
+
list: list_repository,
|
164
|
+
status: status_repository,
|
165
|
+
user: user_repository,
|
166
|
+
}
|
78
167
|
)
|
79
168
|
end
|
80
169
|
|
@@ -82,11 +171,12 @@ module Twterm
|
|
82
171
|
@config ||= Config.new
|
83
172
|
end
|
84
173
|
|
85
|
-
def
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
174
|
+
def on_resize
|
175
|
+
return if Curses.closed?
|
176
|
+
|
177
|
+
lines = `tput lines`.to_i
|
178
|
+
cols = `tput cols`.to_i
|
179
|
+
publish(Event::Screen::Resize.new(lines, cols))
|
90
180
|
end
|
91
181
|
end
|
92
182
|
end
|
data/lib/twterm/client.rb
CHANGED
@@ -8,12 +8,17 @@ module Twterm
|
|
8
8
|
|
9
9
|
attr_reader :user_id, :screen_name
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
def initialize(user_id, screen_name, access_token, access_token_secret)
|
11
|
+
def initialize(user_id, screen_name, access_token, access_token_secret, repositories)
|
14
12
|
@user_id, @screen_name = user_id, screen_name
|
15
13
|
@access_token, @access_token_secret = access_token, access_token_secret
|
16
14
|
|
15
|
+
@friendship_repository = repositories[:friendship]
|
16
|
+
@direct_message_repository = repositories[:direct_message]
|
17
|
+
@hashtag_repository = repositories[:hashtag]
|
18
|
+
@list_repository = repositories[:list]
|
19
|
+
@status_repository = repositories[:status]
|
20
|
+
@user_repository = repositories[:user]
|
21
|
+
|
17
22
|
@callbacks = {}
|
18
23
|
|
19
24
|
@mute_filter = -> _ { true }
|
@@ -26,18 +31,10 @@ module Twterm
|
|
26
31
|
end
|
27
32
|
|
28
33
|
direct_message_manager
|
29
|
-
|
30
|
-
@@instances << self
|
31
34
|
end
|
32
35
|
|
33
|
-
|
34
|
-
detector = -> (instance) { instance.user_id == user_id }
|
35
|
-
instance = @@instances.find(&detector)
|
36
|
-
instance.nil? ? super : instance
|
37
|
-
end
|
36
|
+
private
|
38
37
|
|
39
|
-
|
40
|
-
@@instances[0]
|
41
|
-
end
|
38
|
+
attr_reader :friendship_repository, :direct_message_repository, :hashtag_repository, :list_repository, :status_repository, :user_repository
|
42
39
|
end
|
43
40
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Twterm
|
2
2
|
class CompletionManager
|
3
|
-
|
3
|
+
def initialize(app)
|
4
|
+
@app = app
|
4
5
|
|
5
|
-
def initialize
|
6
6
|
Readline.basic_word_break_characters = " \t\n\"\\'`$><=;|&{("
|
7
7
|
Readline.completion_case_fold = false
|
8
8
|
end
|
@@ -12,12 +12,12 @@ module Twterm
|
|
12
12
|
|
13
13
|
Readline.completion_proc = proc do |str|
|
14
14
|
if str.start_with?('#')
|
15
|
-
|
15
|
+
app.hashtag_repository.all
|
16
16
|
.map { |tag| "##{tag}" }
|
17
17
|
.select { |tag| tag.start_with?(str) }
|
18
18
|
elsif str.start_with?('@')
|
19
|
-
|
20
|
-
.map { |
|
19
|
+
app.user_repository.all
|
20
|
+
.map { |user| "@#{user.screen_name}" }
|
21
21
|
.select { |name| name.start_with?(str) }
|
22
22
|
else
|
23
23
|
[]
|
@@ -29,9 +29,14 @@ module Twterm
|
|
29
29
|
Readline.completion_append_character = ''
|
30
30
|
|
31
31
|
Readline.completion_proc = proc do |str|
|
32
|
-
|
32
|
+
app.user_repository.all
|
33
|
+
.map { |user| user.screen_name }
|
33
34
|
.select { |name| name.start_with?(str) }
|
34
35
|
end
|
35
36
|
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
attr_reader :app
|
36
41
|
end
|
37
42
|
end
|
@@ -3,15 +3,11 @@ require 'twterm/utils'
|
|
3
3
|
|
4
4
|
module Twterm
|
5
5
|
class DirectMessage
|
6
|
-
attr_reader :id, :created_at, :
|
7
|
-
|
8
|
-
@@instances = {}
|
6
|
+
attr_reader :id, :created_at, :recipient_id, :sender_id, :text
|
9
7
|
|
10
8
|
def initialize(message)
|
11
9
|
@id = message.id
|
12
10
|
update!(message)
|
13
|
-
|
14
|
-
@@instances[id] = self
|
15
11
|
end
|
16
12
|
|
17
13
|
def ==(other)
|
@@ -23,18 +19,10 @@ module Twterm
|
|
23
19
|
@created_at.strftime(format)
|
24
20
|
end
|
25
21
|
|
26
|
-
def matches?(q)
|
27
|
-
[
|
28
|
-
sender.name,
|
29
|
-
sender.screen_name,
|
30
|
-
text
|
31
|
-
].map(&:downcase).any? { |x| x.include?(q) }
|
32
|
-
end
|
33
|
-
|
34
22
|
def update!(message)
|
35
23
|
@created_at = message.created_at.dup.localtime
|
36
|
-
@
|
37
|
-
@
|
24
|
+
@recipient_id = message.recipient.id
|
25
|
+
@sender_id = message.sender.id
|
38
26
|
@text = message.text
|
39
27
|
|
40
28
|
self
|
@@ -43,12 +31,10 @@ module Twterm
|
|
43
31
|
class Conversation
|
44
32
|
include Utils
|
45
33
|
|
46
|
-
attr_reader :
|
34
|
+
attr_reader :collocutor_id, :messages
|
47
35
|
|
48
|
-
def initialize(
|
49
|
-
|
50
|
-
|
51
|
-
@collocutor = collocutor
|
36
|
+
def initialize(collocutor_id)
|
37
|
+
@collocutor_id = collocutor_id
|
52
38
|
@messages = []
|
53
39
|
end
|
54
40
|
|
@@ -59,14 +45,6 @@ module Twterm
|
|
59
45
|
self
|
60
46
|
end
|
61
47
|
|
62
|
-
def matches?(q)
|
63
|
-
[
|
64
|
-
collocutor.screen_name,
|
65
|
-
collocutor.name,
|
66
|
-
preview
|
67
|
-
].map(&:downcase).any? { |x| x.include?(q.downcase) }
|
68
|
-
end
|
69
|
-
|
70
48
|
def preview
|
71
49
|
messages.sort_by(&:created_at).last.text.gsub("\n", ' ')
|
72
50
|
end
|
@@ -4,12 +4,15 @@ require 'twterm/utils'
|
|
4
4
|
|
5
5
|
module Twterm
|
6
6
|
class DirectMessageComposer
|
7
|
-
include Singleton
|
8
7
|
include Readline
|
9
8
|
include Curses
|
10
9
|
include Publisher
|
11
10
|
include Utils
|
12
11
|
|
12
|
+
def initialize(app, client)
|
13
|
+
@app, @client = app, client
|
14
|
+
end
|
15
|
+
|
13
16
|
def compose(recipient)
|
14
17
|
check_type User, recipient
|
15
18
|
|
@@ -18,7 +21,7 @@ module Twterm
|
|
18
21
|
resetter = proc do
|
19
22
|
reset_prog_mode
|
20
23
|
sleep 0.1
|
21
|
-
|
24
|
+
app.screen.refresh
|
22
25
|
end
|
23
26
|
|
24
27
|
thread = Thread.new do
|
@@ -26,7 +29,7 @@ module Twterm
|
|
26
29
|
|
27
30
|
puts "\nCompose new message to @%s:" % recipient.screen_name
|
28
31
|
|
29
|
-
|
32
|
+
app.completion_manager.set_default_mode!
|
30
33
|
|
31
34
|
loop do
|
32
35
|
line = (readline('> ', true) || '').strip
|
@@ -46,7 +49,7 @@ module Twterm
|
|
46
49
|
send(recipient) unless text.empty?
|
47
50
|
end
|
48
51
|
|
49
|
-
|
52
|
+
app.register_interruption_handler do
|
50
53
|
thread.kill
|
51
54
|
clear
|
52
55
|
puts "\nCanceled"
|
@@ -58,12 +61,14 @@ module Twterm
|
|
58
61
|
|
59
62
|
private
|
60
63
|
|
64
|
+
attr_reader :app, :client
|
65
|
+
|
61
66
|
def clear
|
62
67
|
@text = ''
|
63
68
|
end
|
64
69
|
|
65
70
|
def send(recipient)
|
66
|
-
|
71
|
+
client.create_direct_message(recipient, text)
|
67
72
|
clear
|
68
73
|
end
|
69
74
|
|
@@ -21,22 +21,21 @@ module Twterm
|
|
21
21
|
Scheduler.new(300) { fetch }
|
22
22
|
end
|
23
23
|
|
24
|
-
def add(
|
25
|
-
check_type User, collocutor
|
24
|
+
def add(collocutor_id, message)
|
26
25
|
check_type DirectMessage, message
|
27
26
|
|
28
|
-
@conversations[
|
29
|
-
@conversations[
|
27
|
+
@conversations[collocutor_id] ||= DirectMessage::Conversation.new(collocutor_id)
|
28
|
+
@conversations[collocutor_id] << message
|
30
29
|
end
|
31
30
|
|
32
31
|
def fetch
|
33
32
|
client.direct_messages_received.then do |messages|
|
34
|
-
messages.each { |m| add(m.
|
33
|
+
messages.each { |m| add(m.sender_id, m) }
|
35
34
|
publish(Event::DirectMessage::Fetched.new)
|
36
35
|
end
|
37
36
|
|
38
37
|
client.direct_messages_sent.then do |messages|
|
39
|
-
messages.each { |m| add(m.
|
38
|
+
messages.each { |m| add(m.recipient_id, m) }
|
40
39
|
publish(Event::DirectMessage::Fetched.new)
|
41
40
|
end
|
42
41
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'twterm/event/base'
|
2
|
+
|
3
|
+
module Twterm
|
4
|
+
module Event
|
5
|
+
module Notification
|
6
|
+
class AbstractNotification < Twterm::Event::Base
|
7
|
+
attr_reader :time
|
8
|
+
|
9
|
+
def initialize(message)
|
10
|
+
super(CGI.unescapeHTML(message))
|
11
|
+
|
12
|
+
@time = Time.now
|
13
|
+
end
|
14
|
+
|
15
|
+
def fields
|
16
|
+
{
|
17
|
+
message: String
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def color
|
22
|
+
raise NotImplementedError, 'color method must be overridden'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -3,7 +3,10 @@ class Enumerator
|
|
3
3
|
def scan(initial, sym = nil)
|
4
4
|
acc = initial
|
5
5
|
|
6
|
+
@_scan_has_yielded_initial_value = false
|
7
|
+
|
6
8
|
Enumerator::Lazy.new(self) do |y, x|
|
9
|
+
y << initial && @_scan_has_yielded_initial_value = true unless @_scan_has_yielded_initial_value
|
7
10
|
acc = sym.nil? ? yield(acc, x) : sym.to_proc.call(acc, x)
|
8
11
|
y << acc
|
9
12
|
end
|