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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/lib/twterm.rb +15 -8
  3. data/lib/twterm/app.rb +2 -3
  4. data/lib/twterm/client.rb +218 -68
  5. data/lib/twterm/filterable_list.rb +2 -1
  6. data/lib/twterm/friendship.rb +124 -0
  7. data/lib/twterm/list.rb +5 -3
  8. data/lib/twterm/promise.rb +143 -0
  9. data/lib/twterm/screen.rb +0 -1
  10. data/lib/twterm/status.rb +15 -14
  11. data/lib/twterm/tab/base.rb +15 -1
  12. data/lib/twterm/tab/key_assignments_cheatsheet.rb +7 -19
  13. data/lib/twterm/tab/new/list.rb +9 -15
  14. data/lib/twterm/tab/new/search.rb +9 -17
  15. data/lib/twterm/tab/new/start.rb +90 -29
  16. data/lib/twterm/tab/new/user.rb +5 -7
  17. data/lib/twterm/tab/scrollable.rb +36 -4
  18. data/lib/twterm/tab/statuses/base.rb +240 -0
  19. data/lib/twterm/tab/statuses/conversation.rb +54 -0
  20. data/lib/twterm/tab/statuses/favorites.rb +45 -0
  21. data/lib/twterm/tab/statuses/home.rb +36 -0
  22. data/lib/twterm/tab/statuses/list_timeline.rb +47 -0
  23. data/lib/twterm/tab/statuses/mentions.rb +40 -0
  24. data/lib/twterm/tab/statuses/search.rb +42 -0
  25. data/lib/twterm/tab/statuses/user_timeline.rb +51 -0
  26. data/lib/twterm/tab/user_tab.rb +288 -19
  27. data/lib/twterm/tab/users/base.rb +90 -0
  28. data/lib/twterm/tab/users/followers.rb +41 -0
  29. data/lib/twterm/tab/users/friends.rb +41 -0
  30. data/lib/twterm/tab_manager.rb +13 -5
  31. data/lib/twterm/user.rb +67 -8
  32. data/lib/twterm/version.rb +1 -1
  33. data/spec/twterm/friendship_spec.rb +104 -0
  34. metadata +18 -11
  35. data/lib/twterm/tab/conversation_tab.rb +0 -49
  36. data/lib/twterm/tab/list_tab.rb +0 -44
  37. data/lib/twterm/tab/mentions_tab.rb +0 -36
  38. data/lib/twterm/tab/search_tab.rb +0 -40
  39. data/lib/twterm/tab/statuses_tab.rb +0 -251
  40. data/lib/twterm/tab/timeline_tab.rb +0 -31
  41. 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
@@ -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