twterm 1.0.12 → 1.1.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/lib/twterm.rb +15 -8
- data/lib/twterm/app.rb +2 -3
- data/lib/twterm/client.rb +218 -68
- data/lib/twterm/filterable_list.rb +2 -1
- data/lib/twterm/friendship.rb +124 -0
- data/lib/twterm/list.rb +5 -3
- data/lib/twterm/promise.rb +143 -0
- data/lib/twterm/screen.rb +0 -1
- data/lib/twterm/status.rb +15 -14
- data/lib/twterm/tab/base.rb +15 -1
- data/lib/twterm/tab/key_assignments_cheatsheet.rb +7 -19
- data/lib/twterm/tab/new/list.rb +9 -15
- data/lib/twterm/tab/new/search.rb +9 -17
- data/lib/twterm/tab/new/start.rb +90 -29
- data/lib/twterm/tab/new/user.rb +5 -7
- data/lib/twterm/tab/scrollable.rb +36 -4
- data/lib/twterm/tab/statuses/base.rb +240 -0
- data/lib/twterm/tab/statuses/conversation.rb +54 -0
- data/lib/twterm/tab/statuses/favorites.rb +45 -0
- data/lib/twterm/tab/statuses/home.rb +36 -0
- data/lib/twterm/tab/statuses/list_timeline.rb +47 -0
- data/lib/twterm/tab/statuses/mentions.rb +40 -0
- data/lib/twterm/tab/statuses/search.rb +42 -0
- data/lib/twterm/tab/statuses/user_timeline.rb +51 -0
- data/lib/twterm/tab/user_tab.rb +288 -19
- data/lib/twterm/tab/users/base.rb +90 -0
- data/lib/twterm/tab/users/followers.rb +41 -0
- data/lib/twterm/tab/users/friends.rb +41 -0
- data/lib/twterm/tab_manager.rb +13 -5
- data/lib/twterm/user.rb +67 -8
- data/lib/twterm/version.rb +1 -1
- data/spec/twterm/friendship_spec.rb +104 -0
- metadata +18 -11
- data/lib/twterm/tab/conversation_tab.rb +0 -49
- data/lib/twterm/tab/list_tab.rb +0 -44
- data/lib/twterm/tab/mentions_tab.rb +0 -36
- data/lib/twterm/tab/search_tab.rb +0 -40
- data/lib/twterm/tab/statuses_tab.rb +0 -251
- data/lib/twterm/tab/timeline_tab.rb +0 -31
- data/lib/twterm/user_window.rb +0 -71
@@ -1,49 +0,0 @@
|
|
1
|
-
module Twterm
|
2
|
-
module Tab
|
3
|
-
class ConversationTab
|
4
|
-
include StatusesTab
|
5
|
-
include Dumpable
|
6
|
-
|
7
|
-
attr_reader :status
|
8
|
-
|
9
|
-
def ==(other)
|
10
|
-
other.is_a?(self.class) && status == other.status
|
11
|
-
end
|
12
|
-
|
13
|
-
def fetch_in_reply_to_status(status)
|
14
|
-
status.in_reply_to_status do |in_reply_to|
|
15
|
-
return if in_reply_to.nil?
|
16
|
-
append(in_reply_to)
|
17
|
-
sort
|
18
|
-
Thread.new { fetch_in_reply_to_status(in_reply_to) }
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def fetch_replies(status)
|
23
|
-
status.replies.each do |reply|
|
24
|
-
prepend(reply)
|
25
|
-
sort
|
26
|
-
Thread.new { fetch_replies(reply) }
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def dump
|
31
|
-
@status.id
|
32
|
-
end
|
33
|
-
|
34
|
-
def initialize(status_id)
|
35
|
-
@title = 'Conversation'
|
36
|
-
super()
|
37
|
-
|
38
|
-
Status.find_or_fetch(status_id) do |status|
|
39
|
-
@status = status
|
40
|
-
|
41
|
-
append(status)
|
42
|
-
scroller.move_to_top
|
43
|
-
Thread.new { fetch_in_reply_to_status(status) }
|
44
|
-
Thread.new { fetch_replies(status) }
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
data/lib/twterm/tab/list_tab.rb
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
module Twterm
|
2
|
-
module Tab
|
3
|
-
class ListTab
|
4
|
-
include StatusesTab
|
5
|
-
include Dumpable
|
6
|
-
|
7
|
-
attr_reader :list
|
8
|
-
|
9
|
-
def initialize(list_id)
|
10
|
-
super()
|
11
|
-
|
12
|
-
List.find_or_fetch(list_id) do |list|
|
13
|
-
@list = list
|
14
|
-
@title = @list.full_name
|
15
|
-
TabManager.instance.refresh_window
|
16
|
-
fetch { scroller.move_to_top }
|
17
|
-
@auto_reloader = Scheduler.new(300) { fetch }
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def fetch
|
22
|
-
client = Client.current
|
23
|
-
client.list_timeline(@list) do |statuses|
|
24
|
-
statuses.reverse.each(&method(:prepend))
|
25
|
-
sort
|
26
|
-
yield if block_given?
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def close
|
31
|
-
@auto_reloader.kill if @auto_reloader
|
32
|
-
super
|
33
|
-
end
|
34
|
-
|
35
|
-
def ==(other)
|
36
|
-
other.is_a?(self.class) && list == other.list
|
37
|
-
end
|
38
|
-
|
39
|
-
def dump
|
40
|
-
@list.id
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
module Twterm
|
2
|
-
module Tab
|
3
|
-
class MentionsTab
|
4
|
-
include StatusesTab
|
5
|
-
|
6
|
-
def close
|
7
|
-
fail NotClosableError
|
8
|
-
end
|
9
|
-
|
10
|
-
def fetch
|
11
|
-
@client.mentions do |statuses|
|
12
|
-
statuses.reverse.each(&method(:prepend))
|
13
|
-
sort
|
14
|
-
yield if block_given?
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def initialize(client)
|
19
|
-
fail ArgumentError, 'argument must be an instance of Client class' unless client.is_a? Client
|
20
|
-
|
21
|
-
super()
|
22
|
-
|
23
|
-
@client = client
|
24
|
-
@client.on_mention do |status|
|
25
|
-
prepend(status)
|
26
|
-
Notifier.instance.show_message "Mentioned by @#{status.user.screen_name}: #{status.text}"
|
27
|
-
end
|
28
|
-
|
29
|
-
@title = 'Mentions'
|
30
|
-
|
31
|
-
fetch { scroller.move_to_top }
|
32
|
-
@auto_reloader = Scheduler.new(300) { fetch }
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module Twterm
|
2
|
-
module Tab
|
3
|
-
class SearchTab
|
4
|
-
include StatusesTab
|
5
|
-
include Dumpable
|
6
|
-
|
7
|
-
attr_reader :query
|
8
|
-
|
9
|
-
def ==(other)
|
10
|
-
other.is_a?(self.class) && query == other.query
|
11
|
-
end
|
12
|
-
|
13
|
-
def close
|
14
|
-
@auto_reloader.kill if @auto_reloader
|
15
|
-
super
|
16
|
-
end
|
17
|
-
|
18
|
-
def dump
|
19
|
-
@query
|
20
|
-
end
|
21
|
-
|
22
|
-
def fetch
|
23
|
-
Client.current.search(@query) do |statuses|
|
24
|
-
statuses.reverse.each(&method(:prepend))
|
25
|
-
yield if block_given?
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
def initialize(query)
|
30
|
-
super()
|
31
|
-
|
32
|
-
@query = query
|
33
|
-
@title = "\"#{@query}\""
|
34
|
-
|
35
|
-
fetch { scroller.move_to_top }
|
36
|
-
@auto_reloader = Scheduler.new(300) { fetch }
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,251 +0,0 @@
|
|
1
|
-
module Twterm
|
2
|
-
module Tab
|
3
|
-
module StatusesTab
|
4
|
-
include Base
|
5
|
-
include FilterableList
|
6
|
-
include Scrollable
|
7
|
-
|
8
|
-
def append(status)
|
9
|
-
fail ArgumentError,
|
10
|
-
'argument must be an instance of Status class' unless status.is_a? Status
|
11
|
-
|
12
|
-
return if @status_ids.include?(status.id)
|
13
|
-
|
14
|
-
@status_ids.unshift(status.id)
|
15
|
-
status.split(window.maxx - 4)
|
16
|
-
status.touch!
|
17
|
-
scroller.item_appended!
|
18
|
-
refresh
|
19
|
-
end
|
20
|
-
|
21
|
-
def delete(status_id)
|
22
|
-
@status_ids.delete(status_id)
|
23
|
-
refresh
|
24
|
-
end
|
25
|
-
|
26
|
-
def destroy_status
|
27
|
-
status = highlighted_status
|
28
|
-
|
29
|
-
Client.current.destroy_status(status) do
|
30
|
-
delete(status.id)
|
31
|
-
refresh
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def drawable_item_count
|
36
|
-
statuses.reverse.drop(scroller.offset).lazy
|
37
|
-
.map { |s| s.split(window.maxx - 4).count + 2 }
|
38
|
-
.scan(0, :+)
|
39
|
-
.select { |l| l < window.maxy }
|
40
|
-
.count
|
41
|
-
end
|
42
|
-
|
43
|
-
def favorite
|
44
|
-
return if highlighted_status.nil?
|
45
|
-
|
46
|
-
method_name = highlighted_status.favorited ? :unfavorite : :favorite
|
47
|
-
Client.current.method(method_name).call(highlighted_status) { refresh }
|
48
|
-
end
|
49
|
-
|
50
|
-
def fetch
|
51
|
-
fail NotImplementedError, 'fetch method must be implemented'
|
52
|
-
end
|
53
|
-
|
54
|
-
def initialize
|
55
|
-
super
|
56
|
-
|
57
|
-
@status_ids = []
|
58
|
-
end
|
59
|
-
|
60
|
-
def items
|
61
|
-
statuses.reverse
|
62
|
-
end
|
63
|
-
|
64
|
-
def open_link
|
65
|
-
return if highlighted_status.nil?
|
66
|
-
|
67
|
-
status = highlighted_status
|
68
|
-
urls = status.urls.map(&:expanded_url) + status.media.map(&:expanded_url)
|
69
|
-
urls.each(&Launchy.method(:open))
|
70
|
-
end
|
71
|
-
|
72
|
-
def prepend(status)
|
73
|
-
fail unless status.is_a? Status
|
74
|
-
|
75
|
-
return if @status_ids.include?(status.id)
|
76
|
-
|
77
|
-
@status_ids << status.id
|
78
|
-
status.split(window.maxx - 4)
|
79
|
-
status.touch!
|
80
|
-
scroller.item_prepended!
|
81
|
-
refresh
|
82
|
-
end
|
83
|
-
|
84
|
-
def reply
|
85
|
-
return if highlighted_status.nil?
|
86
|
-
Tweetbox.instance.compose(highlighted_status)
|
87
|
-
end
|
88
|
-
|
89
|
-
def respond_to_key(key)
|
90
|
-
case key
|
91
|
-
when ?c
|
92
|
-
show_conversation
|
93
|
-
when ?d, 4
|
94
|
-
10.times { scroller.move_down }
|
95
|
-
when ?D
|
96
|
-
destroy_status
|
97
|
-
when ?F
|
98
|
-
favorite
|
99
|
-
when ?g
|
100
|
-
scroller.move_to_top
|
101
|
-
when ?G
|
102
|
-
scroller.move_to_bottom
|
103
|
-
when ?j, 14, Curses::Key::DOWN
|
104
|
-
scroller.move_down
|
105
|
-
when ?k, 16, Curses::Key::UP
|
106
|
-
scroller.move_up
|
107
|
-
when ?o
|
108
|
-
open_link
|
109
|
-
when ?r
|
110
|
-
reply
|
111
|
-
when ?R
|
112
|
-
retweet
|
113
|
-
when 18
|
114
|
-
fetch
|
115
|
-
when ?u, 21
|
116
|
-
10.times { scroller.move_up }
|
117
|
-
when ?U
|
118
|
-
show_user
|
119
|
-
when ?/
|
120
|
-
filter
|
121
|
-
when ?q
|
122
|
-
reset_filter
|
123
|
-
else
|
124
|
-
return false
|
125
|
-
end
|
126
|
-
true
|
127
|
-
end
|
128
|
-
|
129
|
-
def retweet
|
130
|
-
return if highlighted_status.nil?
|
131
|
-
Client.current.retweet(highlighted_status) do
|
132
|
-
refresh
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def show_conversation
|
137
|
-
return if highlighted_status.nil?
|
138
|
-
tab = Tab::ConversationTab.new(highlighted_status.id)
|
139
|
-
TabManager.instance.add_and_show(tab)
|
140
|
-
end
|
141
|
-
|
142
|
-
def show_user
|
143
|
-
return if highlighted_status.nil?
|
144
|
-
user = highlighted_status.user
|
145
|
-
user_tab = Tab::UserTab.new(user.id)
|
146
|
-
TabManager.instance.add_and_show(user_tab)
|
147
|
-
end
|
148
|
-
|
149
|
-
def statuses
|
150
|
-
statuses = @status_ids.map { |id| Status.find(id) }.reject(&:nil?)
|
151
|
-
@status_ids = statuses.map(&:id)
|
152
|
-
|
153
|
-
if filter_query.empty?
|
154
|
-
statuses
|
155
|
-
else
|
156
|
-
statuses.select { |s| s.matches?(filter_query) }
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
def touch_statuses
|
161
|
-
statuses.reverse.take(100).each(&:touch!)
|
162
|
-
end
|
163
|
-
|
164
|
-
def total_item_count
|
165
|
-
filter_query.empty? ? @status_ids.count : statuses.count
|
166
|
-
end
|
167
|
-
|
168
|
-
def update
|
169
|
-
line = 0
|
170
|
-
|
171
|
-
scroller.drawable_items.each.with_index(0) do |status, i|
|
172
|
-
formatted_lines = status.split(window.maxx - 4).count
|
173
|
-
window.with_color(:black, :magenta) do
|
174
|
-
(formatted_lines + 1).times do |j|
|
175
|
-
window.setpos(line + j, 0)
|
176
|
-
window.addch(' ')
|
177
|
-
end
|
178
|
-
end if scroller.current_item?(i)
|
179
|
-
|
180
|
-
window.setpos(line, 2)
|
181
|
-
|
182
|
-
window.bold do
|
183
|
-
window.with_color(status.user.color) do
|
184
|
-
window.addstr(status.user.name)
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
window.addstr(" (@#{status.user.screen_name}) [#{status.date}] ")
|
189
|
-
|
190
|
-
unless status.retweeted_by.nil?
|
191
|
-
window.addstr('(retweeted by ')
|
192
|
-
window.bold do
|
193
|
-
window.addstr("@#{status.retweeted_by.screen_name}")
|
194
|
-
end
|
195
|
-
window.addstr(') ')
|
196
|
-
end
|
197
|
-
|
198
|
-
if status.favorited?
|
199
|
-
window.with_color(:black, :yellow) do
|
200
|
-
window.addch(' ')
|
201
|
-
end
|
202
|
-
|
203
|
-
window.addch(' ')
|
204
|
-
end
|
205
|
-
|
206
|
-
if status.retweeted?
|
207
|
-
window.with_color(:black, :green) do
|
208
|
-
window.addch(' ')
|
209
|
-
end
|
210
|
-
window.addch(' ')
|
211
|
-
end
|
212
|
-
|
213
|
-
if status.favorite_count > 0
|
214
|
-
window.with_color(:yellow) do
|
215
|
-
window.addstr("#{status.favorite_count}fav#{status.favorite_count > 1 ? 's' : ''}")
|
216
|
-
end
|
217
|
-
window.addch(' ')
|
218
|
-
end
|
219
|
-
|
220
|
-
if status.retweet_count > 0
|
221
|
-
window.with_color(:green) do
|
222
|
-
window.addstr("#{status.retweet_count}RT#{status.retweet_count > 1 ? 's' : ''}")
|
223
|
-
end
|
224
|
-
window.addch(' ')
|
225
|
-
end
|
226
|
-
|
227
|
-
status.split(window.maxx - 4).each do |str|
|
228
|
-
line += 1
|
229
|
-
window.setpos(line, 2)
|
230
|
-
window.addstr(str)
|
231
|
-
end
|
232
|
-
|
233
|
-
line += 2
|
234
|
-
|
235
|
-
UserWindow.instance.update(highlighted_status.user)
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
private
|
240
|
-
|
241
|
-
def highlighted_status
|
242
|
-
statuses[scroller.count - scroller.index - 1]
|
243
|
-
end
|
244
|
-
|
245
|
-
def sort
|
246
|
-
@status_ids &= Status.all.map(&:id)
|
247
|
-
@status_ids.sort_by! { |id| Status.find(id).appeared_at }
|
248
|
-
end
|
249
|
-
end
|
250
|
-
end
|
251
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module Twterm
|
2
|
-
module Tab
|
3
|
-
class TimelineTab
|
4
|
-
include StatusesTab
|
5
|
-
|
6
|
-
def close
|
7
|
-
fail NotClosableError
|
8
|
-
end
|
9
|
-
|
10
|
-
def fetch
|
11
|
-
@client.home_timeline do |statuses|
|
12
|
-
statuses.each(&method(:prepend))
|
13
|
-
sort
|
14
|
-
yield if block_given?
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def initialize(client)
|
19
|
-
fail ArgumentError, 'argument must be an instance of Client class' unless client.is_a? Client
|
20
|
-
|
21
|
-
super()
|
22
|
-
@client = client
|
23
|
-
@client.on_timeline_status(&method(:prepend))
|
24
|
-
@title = 'Timeline'
|
25
|
-
|
26
|
-
fetch { scroller.move_to_top }
|
27
|
-
@auto_reloader = Scheduler.new(180) { fetch }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|