twterm 1.3.0 → 2.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|