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.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -18
  3. data/bin/twterm +1 -1
  4. data/lib/twterm/app.rb +120 -30
  5. data/lib/twterm/client.rb +10 -13
  6. data/lib/twterm/completion_mamanger.rb +11 -6
  7. data/lib/twterm/direct_message.rb +6 -28
  8. data/lib/twterm/direct_message_composer.rb +10 -5
  9. data/lib/twterm/direct_message_manager.rb +5 -6
  10. data/lib/twterm/event/notification/abstract_notification.rb +27 -0
  11. data/lib/twterm/event/notification/error.rb +13 -0
  12. data/lib/twterm/event/notification/info.rb +13 -0
  13. data/lib/twterm/event/notification/success.rb +13 -0
  14. data/lib/twterm/event/notification/warning.rb +13 -0
  15. data/lib/twterm/event_dispatcher.rb +1 -1
  16. data/lib/twterm/extensions/array.rb +5 -0
  17. data/lib/twterm/extensions/enumerator/lazy.rb +3 -0
  18. data/lib/twterm/extensions/string.rb +0 -4
  19. data/lib/twterm/friendship.rb +1 -85
  20. data/lib/twterm/image/between.rb +31 -0
  21. data/lib/twterm/image/blank_line.rb +21 -0
  22. data/lib/twterm/image/bold.rb +31 -0
  23. data/lib/twterm/image/brackets.rb +21 -0
  24. data/lib/twterm/image/color.rb +45 -0
  25. data/lib/twterm/image/empty.rb +21 -0
  26. data/lib/twterm/image/horizontal_sequential_image.rb +48 -0
  27. data/lib/twterm/image/parens.rb +21 -0
  28. data/lib/twterm/image/string_image.rb +38 -0
  29. data/lib/twterm/image/vertical_sequential_image.rb +43 -0
  30. data/lib/twterm/image.rb +107 -0
  31. data/lib/twterm/key_mapper/abstract_key_mapper.rb +51 -0
  32. data/lib/twterm/key_mapper/app_key_mapper.rb +13 -0
  33. data/lib/twterm/key_mapper/cursor_key_mapper.rb +13 -0
  34. data/lib/twterm/key_mapper/general_key_mapper.rb +18 -0
  35. data/lib/twterm/key_mapper/no_such_command.rb +20 -0
  36. data/lib/twterm/key_mapper/no_such_key.rb +16 -0
  37. data/lib/twterm/key_mapper/status_key_mapper.rb +18 -0
  38. data/lib/twterm/key_mapper/tab_key_mapper.rb +31 -0
  39. data/lib/twterm/key_mapper.rb +127 -0
  40. data/lib/twterm/list.rb +0 -31
  41. data/lib/twterm/notifier.rb +7 -7
  42. data/lib/twterm/repository/abstract_entity_repository.rb +41 -0
  43. data/lib/twterm/repository/abstract_expirable_entity_repository.rb +35 -0
  44. data/lib/twterm/repository/abstract_repository.rb +64 -0
  45. data/lib/twterm/repository/direct_message_repository.rb +14 -0
  46. data/lib/twterm/repository/friendship_repository.rb +108 -0
  47. data/lib/twterm/repository/hashtag_repository.rb +39 -0
  48. data/lib/twterm/repository/list_repository.rb +14 -0
  49. data/lib/twterm/repository/status_repository.rb +36 -0
  50. data/lib/twterm/repository/user_repository.rb +22 -0
  51. data/lib/twterm/rest_client.rb +107 -63
  52. data/lib/twterm/screen.rb +21 -15
  53. data/lib/twterm/search_query_window.rb +139 -0
  54. data/lib/twterm/status.rb +14 -108
  55. data/lib/twterm/streaming_client.rb +13 -12
  56. data/lib/twterm/tab/base.rb +48 -8
  57. data/lib/twterm/tab/direct_message/conversation.rb +53 -52
  58. data/lib/twterm/tab/direct_message/conversation_list.rb +46 -45
  59. data/lib/twterm/tab/dumpable.rb +3 -3
  60. data/lib/twterm/tab/key_assignments_cheatsheet.rb +58 -57
  61. data/lib/twterm/tab/loadable.rb +20 -0
  62. data/lib/twterm/tab/new/list.rb +32 -43
  63. data/lib/twterm/tab/new/search.rb +31 -44
  64. data/lib/twterm/tab/new/start.rb +44 -55
  65. data/lib/twterm/tab/new/user.rb +15 -12
  66. data/lib/twterm/tab/rate_limit_status.rb +84 -0
  67. data/lib/twterm/tab/scrollable.rb +39 -19
  68. data/lib/twterm/tab/searchable.rb +133 -0
  69. data/lib/twterm/tab/statuses/base.rb +139 -129
  70. data/lib/twterm/tab/statuses/conversation.rb +26 -15
  71. data/lib/twterm/tab/statuses/favorites.rb +10 -8
  72. data/lib/twterm/tab/statuses/home.rb +10 -9
  73. data/lib/twterm/tab/statuses/list_timeline.rb +12 -8
  74. data/lib/twterm/tab/statuses/mentions.rb +17 -11
  75. data/lib/twterm/tab/statuses/search.rb +8 -5
  76. data/lib/twterm/tab/statuses/user_timeline.rb +11 -8
  77. data/lib/twterm/tab/user_list_management.rb +109 -0
  78. data/lib/twterm/tab/user_tab.rb +125 -126
  79. data/lib/twterm/tab/users/base.rb +39 -41
  80. data/lib/twterm/tab/users/followers.rb +9 -6
  81. data/lib/twterm/tab/users/friends.rb +9 -6
  82. data/lib/twterm/tab_manager.rb +64 -40
  83. data/lib/twterm/tweetbox.rb +18 -13
  84. data/lib/twterm/uri_opener.rb +2 -1
  85. data/lib/twterm/user.rb +2 -110
  86. data/lib/twterm/version.rb +1 -1
  87. data/lib/twterm/view.rb +30 -0
  88. data/lib/twterm.rb +3 -9
  89. data/spec/fixtures/status.json +107 -0
  90. data/spec/fixtures/user.json +102 -0
  91. data/spec/spec_helper.rb +7 -0
  92. data/spec/supports/shared_examples/abstract_key_mapper.rb +17 -0
  93. data/spec/twterm/extension/enumerator/lazy_spec.rb +11 -0
  94. data/spec/twterm/friendship_spec.rb +0 -102
  95. data/spec/twterm/image/blank_line_spec.rb +11 -0
  96. data/spec/twterm/image/brackets_spec.rb +12 -0
  97. data/spec/twterm/image/color_spec.rb +22 -0
  98. data/spec/twterm/image/empry_spec.rb +11 -0
  99. data/spec/twterm/image/horizontal_sequential_image_spec.rb +15 -0
  100. data/spec/twterm/image/parens_spec.rb +12 -0
  101. data/spec/twterm/image/string_image_spec.rb +12 -0
  102. data/spec/twterm/image/vertical_sequential_image_spec.rb +14 -0
  103. data/spec/twterm/image_spec.rb +65 -0
  104. data/spec/twterm/key_mapper/abstract_key_mapper_spec.rb +21 -0
  105. data/spec/twterm/key_mapper/app_key_mapper_spec.rb +7 -0
  106. data/spec/twterm/key_mapper/status_key_mapper_spec.rb +7 -0
  107. data/spec/twterm/key_mapper/tab_key_mapper_spec.rb +7 -0
  108. data/spec/twterm/repository/friendship_repository_spec.rb +108 -0
  109. data/spec/twterm/status_spec.rb +58 -0
  110. data/spec/twterm/user_spec.rb +94 -0
  111. data/twterm.gemspec +13 -10
  112. metadata +129 -35
  113. data/lib/twterm/event/notification.rb +0 -33
  114. data/lib/twterm/extensions/integer.rb +0 -5
  115. data/lib/twterm/filter_query_window.rb +0 -91
  116. data/lib/twterm/filterable_list.rb +0 -41
  117. data/lib/twterm/history/base.rb +0 -21
  118. data/lib/twterm/history/hashtag.rb +0 -13
  119. data/lib/twterm/history/savable.rb +0 -37
  120. data/lib/twterm/history/screen_name.rb +0 -11
  121. data/lib/twterm/promise.rb +0 -143
@@ -1,18 +1,21 @@
1
+ require 'concurrent'
2
+
1
3
  require 'twterm/event/open_uri'
2
4
  require 'twterm/event/status/delete'
3
5
  require 'twterm/publisher'
4
6
  require 'twterm/subscriber'
5
7
  require 'twterm/tab/base'
8
+ require 'twterm/tab/loadable'
6
9
  require 'twterm/utils'
7
10
 
8
11
  module Twterm
9
12
  module Tab
10
13
  module Statuses
11
14
  class Base < Tab::Base
12
- include FilterableList
13
15
  include Publisher
14
- include Scrollable
16
+ include Searchable
15
17
  include Subscriber
18
+ include Loadable
16
19
  include Utils
17
20
 
18
21
  def append(status)
@@ -20,62 +23,81 @@ module Twterm
20
23
 
21
24
  return if @status_ids.include?(status.id)
22
25
 
23
- @status_ids.unshift(status.id)
26
+ @status_ids.push(status.id)
24
27
  status.split(window.maxx - 4)
25
- status.touch!
26
28
  scroller.item_appended!
27
- refresh
29
+ render
28
30
  end
29
31
 
30
32
  def delete(status_id)
31
- Status.delete(status_id)
32
- refresh
33
+ app.status_repository.delete(status_id)
34
+ render
33
35
  end
34
36
 
35
37
  def destroy_status
36
- status = highlighted_status
38
+ status = highlighted_original_status
37
39
 
38
- Client.current.destroy_status(status)
40
+ client.destroy_status(status)
39
41
  end
40
42
 
41
43
  def drawable_item_count
42
- statuses.reverse.drop(scroller.offset).lazy
44
+ statuses.drop(scroller.offset).lazy
43
45
  .map { |s| s.split(window.maxx - 4).count + 2 }
44
46
  .scan(0, :+)
45
- .select { |l| l < window.maxy }
47
+ .each_cons(2)
48
+ .select { |_, l| l < window.maxy }
46
49
  .count
47
50
  end
48
51
 
49
52
  def favorite
50
- return if highlighted_status.nil?
53
+ status = highlighted_original_status
54
+
55
+ return if status.nil?
51
56
 
52
- method_name = highlighted_status.favorited ? :unfavorite : :favorite
53
- Client.current.method(method_name).call(highlighted_status)
54
- .then { refresh }
57
+ if status.favorited?
58
+ client.unfavorite(status)
59
+ .then { status.unfavorite! }
60
+ else
61
+ client.favorite(status)
62
+ .then { status.favorite! }
63
+ end
64
+ .then { render }
55
65
  end
56
66
 
57
67
  def fetch
58
68
  fail NotImplementedError, 'fetch method must be implemented'
59
69
  end
60
70
 
61
- def initialize
62
- super
71
+ def initialize(app, client)
72
+ super(app, client)
63
73
 
64
- @status_ids = []
74
+ @status_ids = Concurrent::Array.new
65
75
 
66
76
  subscribe(Event::Status::Delete) { |e| delete(e.status_id) }
67
77
  end
68
78
 
69
79
  def items
70
- statuses.reverse
80
+ statuses
81
+ end
82
+
83
+ def matches?(status, query)
84
+ user = app.user_repository.find(status.user_id)
85
+
86
+ [
87
+ status.text,
88
+ user.screen_name,
89
+ user.name
90
+ ].any? { |x| x.downcase.include?(query.downcase) }
71
91
  end
72
92
 
73
93
  def open_link
74
- return if highlighted_status.nil?
94
+ status = highlighted_original_status
95
+
96
+ return if status.nil?
75
97
 
76
- status = highlighted_status
77
98
  urls = status.urls.map(&:expanded_url) + status.media.map(&:expanded_url)
78
99
  urls
100
+ .uniq
79
101
  .map { |url| Event::OpenURI.new(url) }
80
102
  .each { |e| publish(e) }
81
103
  end
@@ -85,42 +107,40 @@ module Twterm
85
107
 
86
108
  return if @status_ids.include?(status.id)
87
109
 
88
- @status_ids << status.id
110
+ @status_ids.unshift(status.id)
89
111
  status.split(window.maxx - 4)
90
- status.touch!
91
112
  scroller.item_prepended!
92
- refresh
113
+ render
93
114
  end
94
115
 
95
116
  def reply
96
117
  return if highlighted_status.nil?
97
- Tweetbox.instance.compose(highlighted_status)
118
+
119
+ app.tweetbox.compose(highlighted_original_status)
98
120
  end
99
121
 
100
122
  def respond_to_key(key)
101
123
  return true if scroller.respond_to_key(key)
102
124
 
125
+ k = KeyMapper.instance
126
+
103
127
  case key
104
- when ?c
128
+ when k[:status, :conversation]
105
129
  show_conversation
106
- when ?D
130
+ when k[:status, :destroy]
107
131
  destroy_status
108
- when ?F, ?L
132
+ when k[:status, :like]
109
133
  favorite
110
- when ?o
134
+ when k[:status, :open_link]
111
135
  open_link
112
- when ?r
136
+ when k[:status, :reply]
113
137
  reply
114
- when ?R
138
+ when k[:status, :retweet]
115
139
  retweet
116
- when 18
140
+ when k[:tab, :reload]
117
141
  fetch
118
- when ?U
142
+ when k[:status, :user]
119
143
  show_user
120
- when ?/
121
- filter
122
- when ?q
123
- reset_filter
124
144
  else
125
145
  return false
126
146
  end
@@ -128,120 +148,110 @@ module Twterm
128
148
  end
129
149
 
130
150
  def retweet
131
- return if highlighted_status.nil?
132
- Client.current.retweet(highlighted_status).then { refresh }
151
+ status = highlighted_original_status
152
+
153
+ return if status.nil?
154
+
155
+ if status.retweeted?
156
+ client.unretweet(status)
157
+ .then { status.unretweet! }
158
+ else
159
+ client.retweet(status)
160
+ .then { status.retweet! }
161
+ end
162
+ .then { render }
133
163
  end
134
164
 
135
165
  def show_conversation
136
- return if highlighted_status.nil?
137
- tab = Tab::Statuses::Conversation.new(highlighted_status.id)
138
- TabManager.instance.add_and_show(tab)
166
+ status = highlighted_original_status
167
+
168
+ return if status.nil?
169
+
170
+ tab = Tab::Statuses::Conversation.new(app, client, highlighted_original_status.id)
171
+ app.tab_manager.add_and_show(tab)
139
172
  end
140
173
 
141
174
  def show_user
142
- return if highlighted_status.nil?
143
- user = highlighted_status.user
144
- user_tab = Tab::UserTab.new(user.id)
145
- TabManager.instance.add_and_show(user_tab)
175
+ status = highlighted_original_status
176
+
177
+ return if status.nil?
178
+
179
+ user_id = status.user_id
180
+ user_tab = Tab::UserTab.new(app, client, user_id)
181
+ app.tab_manager.add_and_show(user_tab)
146
182
  end
147
183
 
148
184
  def statuses
149
- statuses = @status_ids.map { |id| Status.find(id) }.reject(&:nil?)
185
+ statuses = @status_ids.map { |id| app.status_repository.find(id) }.compact
150
186
  @status_ids = statuses.map(&:id)
151
187
 
152
- if filter_query.empty?
153
- statuses
154
- else
155
- statuses.select { |s| s.matches?(filter_query) }
156
- end
157
- end
158
-
159
- def touch_statuses
160
- statuses.reverse.take(100).each(&:touch!)
188
+ statuses
161
189
  end
162
190
 
163
191
  def total_item_count
164
- filter_query.empty? ? @status_ids.count : statuses.count
165
- end
166
-
167
- def update
168
- line = 0
169
-
170
- scroller.drawable_items.each.with_index(0) do |status, i|
171
- formatted_lines = status.split(window.maxx - 4).count
172
- window.with_color(:black, :magenta) do
173
- (formatted_lines + 1).times do |j|
174
- window.setpos(line + j, 0)
175
- window.addch(' ')
176
- end
177
- end if scroller.current_item?(i)
178
-
179
- window.setpos(line, 2)
180
-
181
- window.bold do
182
- window.with_color(status.user.color) do
183
- window.addstr(status.user.name)
184
- end
185
- end
186
-
187
- window.addstr(" (@#{status.user.screen_name}) [#{status.date}] ")
188
-
189
- unless status.retweeted_by.nil?
190
- window.addstr('(retweeted by ')
191
- window.bold do
192
- window.addstr("@#{status.retweeted_by.screen_name}")
193
- end
194
- window.addstr(') ')
195
- end
196
-
197
- if status.favorited?
198
- window.with_color(:black, :red) do
199
- window.addch(' ')
200
- end
201
-
202
- window.addch(' ')
203
- end
204
-
205
- if status.retweeted?
206
- window.with_color(:black, :green) do
207
- window.addch(' ')
208
- end
209
- window.addch(' ')
210
- end
211
-
212
- if status.favorite_count > 0
213
- window.with_color(:red) do
214
- window.addstr("#{status.favorite_count}like#{status.favorite_count > 1 ? 's' : ''}")
215
- end
216
- window.addch(' ')
217
- end
218
-
219
- if status.retweet_count > 0
220
- window.with_color(:green) do
221
- window.addstr("#{status.retweet_count}RT#{status.retweet_count > 1 ? 's' : ''}")
222
- end
223
- window.addch(' ')
224
- end
225
-
226
- status.split(window.maxx - 4).each do |str|
227
- line += 1
228
- window.setpos(line, 2)
229
- window.addstr(str)
230
- end
231
-
232
- line += 2
233
- end
192
+ search_query.empty? ? @status_ids.count : statuses.count
234
193
  end
235
194
 
236
195
  private
237
196
 
197
+ def highlighted_original_status
198
+ status = highlighted_status
199
+
200
+ status.retweet? ? app.status_repository.find(status.retweeted_status_id) : status
201
+ end
202
+
238
203
  def highlighted_status
239
- statuses[scroller.count - scroller.index - 1]
204
+ statuses[scroller.index]
205
+ end
206
+
207
+ def image
208
+ return Image.string(initially_loaded? ? 'No results found' : 'Loading...') if items.empty?
209
+
210
+ scroller.drawable_items.map.with_index(0) do |status, i|
211
+ original = status.retweet? ? app.status_repository.find(status.retweeted_status_id) : status
212
+ user = app.user_repository.find(original.user_id)
213
+ retweeted_by = app.user_repository.find(status.user_id)
214
+
215
+ header = [
216
+ !Image.string(user.name).color(user.color),
217
+ Image.string("@#{user.screen_name}").parens,
218
+ Image.string(original.date.to_s).brackets,
219
+ (Image.whitespace.color(:black, :red) if original.favorited?),
220
+ (Image.whitespace.color(:black, :green) if original.retweeted?),
221
+ ((Image.string('retweeted by ') - !Image.string("@#{retweeted_by.screen_name}")).parens if status.retweet?),
222
+ ((Image.number(original.favorite_count) - Image.plural(original.favorite_count, 'like')).color(:red) if original.favorite_count.positive?),
223
+ ((Image.number(original.retweet_count) - Image.plural(original.retweet_count, 'RT')).color(:green) if original.retweet_count.positive?),
224
+ ].compact.intersperse(Image.whitespace).reduce(Image.empty, :-)
225
+
226
+ body = original
227
+ .split(window.maxx - 4)
228
+ .map(&Image.method(:string))
229
+ .reduce(Image.empty, :|)
230
+
231
+ s = header | body
232
+
233
+ Image.cursor(s.height, scroller.current_index?(i)) - Image.whitespace - s
234
+ end
235
+ .intersperse(Image.blank_line)
236
+ .reduce(Image.empty, :|)
240
237
  end
241
238
 
242
239
  def sort
243
- @status_ids &= Status.all.map(&:id)
244
- @status_ids.sort_by! { |id| Status.find(id).appeared_at }
240
+ return if items.empty? || scroller.current_item.nil?
241
+
242
+ repo = app.status_repository
243
+
244
+ @status_ids &= repo.ids
245
+ @status_ids.sort_by! { |id| repo.find(id).created_at }.reverse!
246
+
247
+ formerly_selected_status_id = scroller.current_item.id
248
+
249
+ unless formerly_selected_status_id.nil?
250
+ new_index = @status_ids.index(formerly_selected_status_id)
251
+ scroller.move_to(new_index) unless new_index.nil?
252
+ end
253
+
254
+ self
245
255
  end
246
256
  end
247
257
  end
@@ -1,3 +1,5 @@
1
+ require 'concurrent'
2
+
1
3
  require 'twterm/tab/statuses/base'
2
4
 
3
5
  module Twterm
@@ -12,37 +14,46 @@ module Twterm
12
14
  other.is_a?(self.class) && status == other.status
13
15
  end
14
16
 
15
- def fetch_in_reply_to_status(status)
16
- status.in_reply_to_status.then do |in_reply_to|
17
- return if in_reply_to.nil?
18
- append(in_reply_to)
19
- sort
20
- Thread.new { fetch_in_reply_to_status(in_reply_to) }
17
+ def fetch_ancestor(status)
18
+ in_reply_to_status_id = status.in_reply_to_status_id
19
+
20
+ if in_reply_to_status_id.nil?
21
+ Concurrent::Promise.fulfill(nil)
22
+ elsif (instance = app.status_repository.find(in_reply_to_status_id))
23
+ Concurrent::Promise.fulfill(instance)
24
+ else
25
+ client.show_status(in_reply_to_status_id)
21
26
  end
27
+ .then do |in_reply_to|
28
+ next if in_reply_to.nil?
29
+ append(in_reply_to)
30
+ sort
31
+ fetch_ancestor(in_reply_to)
32
+ end
22
33
  end
23
34
 
24
- def fetch_replies(status)
25
- status.replies.each do |reply|
35
+ def find_descendants(status)
36
+ app.status_repository.find_replies_for(status.id).each do |reply|
26
37
  prepend(reply)
27
- sort
28
- Thread.new { fetch_replies(reply) }
38
+ find_descendants(reply)
29
39
  end
40
+ sort
30
41
  end
31
42
 
32
43
  def dump
33
44
  @status.id
34
45
  end
35
46
 
36
- def initialize(status_id)
37
- super()
47
+ def initialize(app, client, status_id)
48
+ super(app, client)
38
49
 
39
- Status.find_or_fetch(status_id).then do |status|
50
+ find_or_fetch_status(status_id).then do |status|
40
51
  @status = status
41
52
 
42
53
  append(status)
43
54
  scroller.move_to_top
44
- Thread.new { fetch_in_reply_to_status(status) }
45
- Thread.new { fetch_replies(status) }
55
+ fetch_ancestor(status)
56
+ find_descendants(status)
46
57
  end
47
58
  end
48
59
 
@@ -17,23 +17,25 @@ module Twterm
17
17
  end
18
18
 
19
19
  def fetch
20
- Client.current.favorites(@user.id).then do |statuses|
21
- statuses.reverse.each(&method(:prepend))
20
+ client.favorites(@user.id).then do |statuses|
21
+ statuses.each { |s| append(s) }
22
22
  sort
23
- yield if block_given?
24
23
  end
25
24
  end
26
25
 
27
- def initialize(user_id)
28
- super()
26
+ def initialize(app, client, user_id)
27
+ super(app, client)
29
28
 
30
29
  @user_id = user_id
31
30
 
32
- User.find_or_fetch(user_id).then do |user|
31
+ find_or_fetch_user(user_id).then do |user|
33
32
  @user = user
34
- TabManager.instance.refresh_window
33
+ app.tab_manager.refresh_window
35
34
 
36
- fetch { scroller.move_to_top }
35
+ fetch.then do
36
+ initially_loaded!
37
+ scroller.move_to_top
38
+ end
37
39
  end
38
40
  end
39
41
 
@@ -15,21 +15,22 @@ module Twterm
15
15
  end
16
16
 
17
17
  def fetch
18
- @client.home_timeline.then do |statuses|
19
- statuses.each(&method(:prepend))
18
+ client.home_timeline.then do |statuses|
19
+ statuses.each { |s| append(s) }
20
20
  sort
21
- yield if block_given?
22
21
  end
23
22
  end
24
23
 
25
- def initialize(client)
26
- check_type Client, client
24
+ def initialize(app, client)
25
+ super(app, client)
27
26
 
28
- super()
29
- @client = client
30
- subscribe(Event::Status::Timeline) { |e| prepend e.status }
27
+ subscribe(Event::Status::Timeline) { |e| prepend(e.status) }
28
+
29
+ fetch.then do
30
+ initially_loaded!
31
+ scroller.move_to_top
32
+ end
31
33
 
32
- fetch { scroller.move_to_top }
33
34
  @auto_reloader = Scheduler.new(180) { fetch }
34
35
  end
35
36
 
@@ -8,25 +8,29 @@ module Twterm
8
8
 
9
9
  attr_reader :list
10
10
 
11
- def initialize(list_id)
12
- super()
11
+ def initialize(app, client, list_id)
12
+ super(app, client)
13
13
 
14
14
  self.title = 'Loading...'.freeze
15
15
 
16
- List.find_or_fetch(list_id).then do |list|
16
+ find_or_fetch_list(list_id).then do |list|
17
17
  @list = list
18
18
  self.title = @list.full_name
19
- TabManager.instance.refresh_window
20
- fetch { scroller.move_to_top }
19
+ app.tab_manager.refresh_window
20
+
21
+ fetch.then do
22
+ initially_loaded!
23
+ scroller.move_to_top
24
+ end
25
+
21
26
  @auto_reloader = Scheduler.new(300) { fetch }
22
27
  end
23
28
  end
24
29
 
25
30
  def fetch
26
- Client.current.list_timeline(@list).then do |statuses|
27
- statuses.reverse.each(&method(:prepend))
31
+ client.list_timeline(@list).then do |statuses|
32
+ statuses.each { |s| append(s) }
28
33
  sort
29
- yield if block_given?
30
34
  end
31
35
  end
32
36
 
@@ -11,24 +11,30 @@ module Twterm
11
11
  end
12
12
 
13
13
  def fetch
14
- @client.mentions.then do |statuses|
15
- statuses.reverse.each(&method(:prepend))
16
- sort
17
- yield if block_given?
18
- end
14
+ client.mentions
19
15
  end
20
16
 
21
- def initialize(client)
17
+ def initialize(app, client)
22
18
  fail ArgumentError, 'argument must be an instance of Client class' unless client.is_a? Client
23
19
 
24
- super()
25
-
26
- @client = client
20
+ super(app, client)
27
21
 
28
22
  subscribe(Event::Status::Mention) { |e| prepend(e.status) }
29
23
 
30
- fetch { scroller.move_to_top }
31
- @auto_reloader = Scheduler.new(300) { fetch }
24
+ fetch.then do |statuses|
25
+ initially_loaded!
26
+ statuses.each { |s| append(s) }
27
+ scroller.move_to_top
28
+ end
29
+
30
+ @auto_reloader = Scheduler.new(300) { reload }
31
+ end
32
+
33
+ def reload
34
+ fetch.then do |statuses|
35
+ statuses.each { |s| append(s) }
36
+ sort
37
+ end
32
38
  end
33
39
 
34
40
  def title
@@ -22,20 +22,23 @@ module Twterm
22
22
  end
23
23
 
24
24
  def fetch
25
- Client.current.search(@query).then do |statuses|
25
+ client.search(@query).then do |statuses|
26
26
  statuses.each(&method(:append))
27
27
  sort
28
- yield if block_given?
29
28
  end
30
29
  end
31
30
 
32
- def initialize(query)
33
- super()
31
+ def initialize(app, client, query)
32
+ super(app, client)
34
33
 
35
34
  @query = query
36
35
  @title = "\"#{@query}\""
37
36
 
38
- fetch { scroller.move_to_top }
37
+ fetch.then do
38
+ initially_loaded!
39
+ scroller.move_to_top
40
+ end
41
+
39
42
  @auto_reloader = Scheduler.new(300) { fetch }
40
43
  end
41
44
  end
@@ -22,23 +22,26 @@ module Twterm
22
22
  end
23
23
 
24
24
  def fetch
25
- Client.current.user_timeline(@user.id).then do |statuses|
26
- statuses.reverse.each(&method(:prepend))
25
+ client.user_timeline(@user.id).then do |statuses|
26
+ statuses.each { |s| append(s) }
27
27
  sort
28
- yield if block_given?
29
28
  end
30
29
  end
31
30
 
32
- def initialize(user_id)
33
- super()
31
+ def initialize(app, client, user_id)
32
+ super(app, client)
34
33
 
35
34
  @user_id = user_id
36
35
 
37
- User.find_or_fetch(user_id).then do |user|
36
+ find_or_fetch_user(user_id).then do |user|
38
37
  @user = user
39
- TabManager.instance.refresh_window
38
+ app.tab_manager.refresh_window
39
+
40
+ fetch.then do
41
+ initially_loaded!
42
+ scroller.move_to_top
43
+ end
40
44
 
41
- fetch { scroller.move_to_top }
42
45
  @auto_reloader = Scheduler.new(120) { fetch }
43
46
  end
44
47
  end