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
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'concurrent'
|
2
|
+
|
3
|
+
require 'twterm/event/notification/success'
|
4
|
+
require 'twterm/image'
|
5
|
+
require 'twterm/publisher'
|
6
|
+
require 'twterm/tab/dumpable'
|
7
|
+
require 'twterm/tab/loadable'
|
8
|
+
require 'twterm/tab/searchable'
|
9
|
+
|
10
|
+
module Twterm
|
11
|
+
module Tab
|
12
|
+
class UserListManagement < Base
|
13
|
+
include Dumpable
|
14
|
+
include Loadable
|
15
|
+
include Publisher
|
16
|
+
include Searchable
|
17
|
+
|
18
|
+
@@lists = Concurrent::Array.new
|
19
|
+
|
20
|
+
def initialize(app, client, user_id)
|
21
|
+
super(app, client)
|
22
|
+
|
23
|
+
@user_id = user_id
|
24
|
+
@list_ids = Concurrent::Array.new
|
25
|
+
|
26
|
+
client.owned_lists.then do |lists|
|
27
|
+
@@lists = lists.sort_by(&:full_name)
|
28
|
+
render
|
29
|
+
end
|
30
|
+
|
31
|
+
client.memberships(user_id, filter_to_owned_lists: true, count: 1000).then do |lists|
|
32
|
+
@list_ids = lists.map(&:id)
|
33
|
+
initially_loaded!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def drawable_item_count
|
38
|
+
window.maxy / 3
|
39
|
+
end
|
40
|
+
|
41
|
+
def dump
|
42
|
+
user_id
|
43
|
+
end
|
44
|
+
|
45
|
+
def image
|
46
|
+
return Image.string(initially_loaded? ? 'No lists found' : 'Loading...') if items.empty?
|
47
|
+
|
48
|
+
drawable_items.map.with_index do |list, i|
|
49
|
+
cursor = Image.cursor(2, scroller.current_index?(i))
|
50
|
+
|
51
|
+
summary = Image.checkbox(@list_ids.include?(list.id)) - Image.whitespace - Image.string(list.full_name)
|
52
|
+
description = Image.string(' ') - Image.string(list.description)
|
53
|
+
|
54
|
+
cursor - Image.whitespace - (summary | description)
|
55
|
+
end
|
56
|
+
.intersperse(Image.blank_line)
|
57
|
+
.reduce(Image.empty, :|)
|
58
|
+
end
|
59
|
+
|
60
|
+
def items
|
61
|
+
@@lists
|
62
|
+
end
|
63
|
+
|
64
|
+
def matches?(list, query)
|
65
|
+
[
|
66
|
+
list.description,
|
67
|
+
list.full_name,
|
68
|
+
].any? { |x| x.downcase.include?(query.downcase) }
|
69
|
+
end
|
70
|
+
|
71
|
+
def respond_to_key(key)
|
72
|
+
return true if scroller.respond_to_key(key)
|
73
|
+
|
74
|
+
case key
|
75
|
+
when 10 then toggle
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def title
|
80
|
+
(user.nil? ? 'Loading' : "@#{user.screen_name} lists").freeze
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
attr_reader :list_ids, :user_id
|
86
|
+
|
87
|
+
def user
|
88
|
+
app.user_repository.find(user_id)
|
89
|
+
end
|
90
|
+
|
91
|
+
def toggle
|
92
|
+
list = scroller.current_item
|
93
|
+
|
94
|
+
if list_ids.include?(list.id)
|
95
|
+
client.remove_list_member(list.id, user_id).then do
|
96
|
+
@list_ids.delete(list.id)
|
97
|
+
publish(Event::Notification::Success.new("Removed @#{user.screen_name} from #{list.name}"))
|
98
|
+
end
|
99
|
+
else
|
100
|
+
client.add_list_member(list.id, user_id).then do
|
101
|
+
@list_ids.push(list.id)
|
102
|
+
publish(Event::Notification::Success.new("Added @#{user.screen_name} to #{list.name}"))
|
103
|
+
end
|
104
|
+
end
|
105
|
+
.then { render }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/lib/twterm/tab/user_tab.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'twterm/event/open_uri'
|
2
2
|
require 'twterm/publisher'
|
3
3
|
require 'twterm/tab/base'
|
4
|
+
require 'twterm/tab/user_list_management'
|
4
5
|
|
5
6
|
module Twterm
|
6
7
|
module Tab
|
@@ -24,19 +25,19 @@ module Twterm
|
|
24
25
|
end
|
25
26
|
|
26
27
|
def fetch
|
27
|
-
|
28
|
+
render
|
28
29
|
end
|
29
30
|
|
30
|
-
def initialize(user_id)
|
31
|
-
super()
|
31
|
+
def initialize(app, client, user_id)
|
32
|
+
super(app, client)
|
32
33
|
|
33
34
|
self.title = 'Loading...'.freeze
|
34
35
|
@user_id = user_id
|
35
36
|
|
36
|
-
|
37
|
-
|
37
|
+
find_or_fetch_user(user_id).then do |user|
|
38
|
+
render
|
38
39
|
|
39
|
-
|
40
|
+
client.lookup_friendships.then { render } unless app.friendship_repository.already_looked_up?(user_id)
|
40
41
|
self.title = "@#{user.screen_name}"
|
41
42
|
end
|
42
43
|
end
|
@@ -47,6 +48,7 @@ module Twterm
|
|
47
48
|
show_friends
|
48
49
|
show_followers
|
49
50
|
show_likes
|
51
|
+
manage_lists
|
50
52
|
)
|
51
53
|
items << :compose_direct_message unless myself?
|
52
54
|
items << :open_website unless user.website.nil?
|
@@ -60,17 +62,11 @@ module Twterm
|
|
60
62
|
def respond_to_key(key)
|
61
63
|
return true if scroller.respond_to_key(key)
|
62
64
|
|
65
|
+
k = KeyMapper.instance
|
66
|
+
|
63
67
|
case key
|
64
|
-
when ?D
|
65
|
-
compose_direct_message unless myself?
|
66
|
-
when ?F
|
67
|
-
follow unless myself?
|
68
68
|
when 10
|
69
69
|
perform_selected_action
|
70
|
-
when ?t
|
71
|
-
open_timeline_tab
|
72
|
-
when ?W
|
73
|
-
open_website
|
74
70
|
else
|
75
71
|
return false
|
76
72
|
end
|
@@ -85,25 +81,25 @@ module Twterm
|
|
85
81
|
end
|
86
82
|
|
87
83
|
def block
|
88
|
-
|
89
|
-
|
84
|
+
client.block(user_id).then do |users|
|
85
|
+
render
|
90
86
|
|
91
87
|
user = users.first
|
92
|
-
publish(Event::Notification.new(
|
88
|
+
publish(Event::Notification::Success.new('Blocked @%s' % user.screen_name))
|
93
89
|
end
|
94
90
|
end
|
95
91
|
|
96
92
|
def blocking?
|
97
|
-
|
93
|
+
app.friendship_repository.blocking?(client.user_id, user_id)
|
98
94
|
end
|
99
95
|
|
100
96
|
def compose_direct_message
|
101
|
-
|
97
|
+
app.direct_message_composer.compose(user)
|
102
98
|
end
|
103
99
|
|
104
100
|
def follow
|
105
|
-
|
106
|
-
|
101
|
+
client.follow(user_id).then do |users|
|
102
|
+
render
|
107
103
|
|
108
104
|
user = users.first
|
109
105
|
if user.protected?
|
@@ -111,42 +107,47 @@ module Twterm
|
|
111
107
|
else
|
112
108
|
msg = "Followed @#{user.screen_name}"
|
113
109
|
end
|
114
|
-
publish(Event::Notification.new(
|
110
|
+
publish(Event::Notification::Success.new(msg))
|
115
111
|
end
|
116
112
|
end
|
117
113
|
|
118
114
|
def followed?
|
119
|
-
|
115
|
+
app.friendship_repository.following?(user_id, client.user_id)
|
120
116
|
end
|
121
117
|
|
122
118
|
def following?
|
123
|
-
|
119
|
+
app.friendship_repository.following?(client.user_id, user_id)
|
124
120
|
end
|
125
121
|
|
126
122
|
def following_requested?
|
127
|
-
|
123
|
+
app.friendship_repository.following_requested?(client.user_id, user_id)
|
128
124
|
end
|
129
125
|
|
130
126
|
def mute
|
131
|
-
|
132
|
-
|
127
|
+
client.mute(user_id).then do |users|
|
128
|
+
render
|
133
129
|
|
134
130
|
user = users.first
|
135
|
-
publish(Event::Notification.new(
|
131
|
+
publish(Event::Notification::Success.new('Muted @%s' % user.screen_name))
|
136
132
|
end
|
137
133
|
end
|
138
134
|
|
139
135
|
def muting?
|
140
|
-
|
136
|
+
app.friendship_repository.muting?(client.user_id, user_id)
|
141
137
|
end
|
142
138
|
|
143
139
|
def myself?
|
144
|
-
user_id ==
|
140
|
+
user_id == client.user_id
|
141
|
+
end
|
142
|
+
|
143
|
+
def open_list_management_tab
|
144
|
+
tab = Tab::UserListManagement.new(app, client, user_id)
|
145
|
+
app.tab_manager.add_and_show(tab)
|
145
146
|
end
|
146
147
|
|
147
148
|
def open_timeline_tab
|
148
|
-
tab = Tab::Statuses::UserTimeline.new(user_id)
|
149
|
-
|
149
|
+
tab = Tab::Statuses::UserTimeline.new(app, client, user_id)
|
150
|
+
app.tab_manager.add_and_show(tab)
|
150
151
|
end
|
151
152
|
|
152
153
|
def open_website
|
@@ -159,6 +160,8 @@ module Twterm
|
|
159
160
|
case scroller.current_item
|
160
161
|
when :compose_direct_message
|
161
162
|
compose_direct_message
|
163
|
+
when :manage_lists
|
164
|
+
open_list_management_tab
|
162
165
|
when :open_timeline_tab
|
163
166
|
open_timeline_tab
|
164
167
|
when :open_website
|
@@ -185,138 +188,134 @@ module Twterm
|
|
185
188
|
end
|
186
189
|
|
187
190
|
def show_likes
|
188
|
-
tab = Tab::Statuses::Favorites.new(user_id)
|
189
|
-
|
191
|
+
tab = Tab::Statuses::Favorites.new(app, client, user_id)
|
192
|
+
app.tab_manager.add_and_show(tab)
|
190
193
|
end
|
191
194
|
|
192
195
|
def show_followers
|
193
|
-
tab = Tab::Users::Followers.new(user_id)
|
194
|
-
|
196
|
+
tab = Tab::Users::Followers.new(app, client, user_id)
|
197
|
+
app.tab_manager.add_and_show(tab)
|
195
198
|
end
|
196
199
|
|
197
200
|
def show_friends
|
198
|
-
tab = Tab::Users::Friends.new(user_id)
|
199
|
-
|
201
|
+
tab = Tab::Users::Friends.new(app, client, user_id)
|
202
|
+
app.tab_manager.add_and_show(tab)
|
200
203
|
end
|
201
204
|
|
202
205
|
def unblock
|
203
|
-
|
204
|
-
|
206
|
+
client.unblock(user_id).then do |users|
|
207
|
+
render
|
205
208
|
|
206
209
|
user = users.first
|
207
|
-
publish(Event::Notification.new(
|
210
|
+
publish(Event::Notification::Success.new('Unblocked @%s' % user.screen_name))
|
208
211
|
end
|
209
212
|
end
|
210
213
|
|
211
214
|
def unfollow
|
212
|
-
|
213
|
-
|
215
|
+
client.unfollow(user_id).then do |users|
|
216
|
+
render
|
214
217
|
|
215
218
|
user = users.first
|
216
|
-
publish(Event::Notification.new(
|
219
|
+
publish(Event::Notification::Success.new('Unfollowed @%s' % user.screen_name))
|
217
220
|
end
|
218
221
|
end
|
219
222
|
|
220
223
|
def unmute
|
221
|
-
|
222
|
-
|
224
|
+
client.unmute(user_id).then do |users|
|
225
|
+
render
|
223
226
|
|
224
227
|
user = users.first
|
225
|
-
publish(Event::Notification.new(
|
228
|
+
publish(Event::Notification::Success.new('Unmuted @%s' % user.screen_name))
|
226
229
|
end
|
227
230
|
end
|
228
231
|
|
229
|
-
def
|
232
|
+
def image
|
230
233
|
if user.nil?
|
231
|
-
|
232
|
-
return
|
233
|
-
end
|
234
|
-
|
235
|
-
window.setpos(2, 3)
|
236
|
-
window.bold { window.addstr(user.name) }
|
237
|
-
window.addstr(" (@#{user.screen_name})")
|
238
|
-
|
239
|
-
window.with_color(:yellow) { window.addstr(' [protected]') } if user.protected?
|
240
|
-
window.with_color(:cyan) { window.addstr(' [verified]') } if user.verified?
|
241
|
-
|
242
|
-
window.setpos(5, 4)
|
243
|
-
if myself?
|
244
|
-
window.with_color(:yellow) { window.addstr(' [your account]') }
|
245
|
-
else
|
246
|
-
window.with_color(:green) { window.addstr(' [following]') } if following?
|
247
|
-
window.with_color(:white) { window.addstr(' [not following]') } if !following? && !blocking? && !following_requested?
|
248
|
-
window.with_color(:yellow) { window.addstr(' [following requested]') } if following_requested?
|
249
|
-
window.with_color(:cyan) { window.addstr(' [follows you]') } if followed?
|
250
|
-
window.with_color(:red) { window.addstr(' [muting]') } if muting?
|
251
|
-
window.with_color(:red) { window.addstr(' [blocking]') } if blocking?
|
252
|
-
end
|
253
|
-
|
254
|
-
user.description.split_by_width(window.maxx - 6).each.with_index(7) do |line, i|
|
255
|
-
window.setpos(i, 5)
|
256
|
-
window.addstr(line)
|
234
|
+
find_or_fetch_user(user_id).then { render }
|
235
|
+
return Image.empty
|
257
236
|
end
|
258
237
|
|
259
|
-
|
260
|
-
window.addstr("Location: #{user.location}") unless user.location.nil?
|
238
|
+
name = !Image.string(user.name) - Image.whitespace - Image.string("@#{user.screen_name}").parens
|
261
239
|
|
262
|
-
|
240
|
+
badges = [
|
241
|
+
(Image.string('protected').brackets.color(:yellow) if user.protected?),
|
242
|
+
(Image.string('verified').brackets.color(:cyan) if user.verified?),
|
243
|
+
].compact.intersperse(Image.whitespace).reduce(Image.empty, :-)
|
263
244
|
|
264
|
-
|
265
|
-
if
|
266
|
-
|
267
|
-
|
245
|
+
status =
|
246
|
+
if myself?
|
247
|
+
Image.string('your account').brackets.color(:yellow)
|
248
|
+
else
|
249
|
+
[
|
250
|
+
['following', :green, following?],
|
251
|
+
['not following', :white, !following? && !blocking? && !following_requested?],
|
252
|
+
['following requested', :yellow, following_requested?],
|
253
|
+
['follows you', :cyan, followed?],
|
254
|
+
['muting', :red, muting?],
|
255
|
+
['blocking', :red, blocking?],
|
256
|
+
]
|
257
|
+
.select { |_, _, p| p }
|
258
|
+
.map { |s, c, _| Image.string(s).brackets.color(c) }
|
259
|
+
.intersperse(Image.whitespace)
|
260
|
+
.reduce(Image.empty, :-)
|
268
261
|
end
|
269
262
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
263
|
+
description = user.description.split_by_width(window.maxx - 4)
|
264
|
+
.map(&Image.method(:string))
|
265
|
+
.reduce(Image.empty, :|)
|
266
|
+
|
267
|
+
location = Image.string("Location: #{user.location}")
|
268
|
+
|
269
|
+
foo = drawable_items.map.with_index(0) do |item, i|
|
270
|
+
Image.cursor(1, scroller.current_index?(i)) - Image.whitespace -
|
271
|
+
case item
|
272
|
+
when :compose_direct_message
|
273
|
+
Image.string('Compose direct message')
|
274
|
+
when :toggle_block
|
275
|
+
if blocking?
|
276
|
+
Image.string('Unblock this user')
|
277
|
+
else
|
278
|
+
Image.string('Block this user')
|
279
|
+
end
|
280
|
+
when :toggle_follow
|
281
|
+
if following?
|
282
|
+
Image.string('Unfollow this user')
|
283
|
+
elsif following_requested?
|
284
|
+
Image.string('Following request sent')
|
285
|
+
else
|
286
|
+
Image.string('Follow this user')
|
287
|
+
end
|
288
|
+
when :toggle_mute
|
289
|
+
if muting?
|
290
|
+
Image.string('Unmute this user')
|
291
|
+
else
|
292
|
+
Image.string('Mute this user')
|
293
|
+
end
|
294
|
+
when :open_timeline_tab
|
295
|
+
Image.number(user.statuses_count) - Image.whitespace - Image.plural(user.statuses_count, 'tweet')
|
296
|
+
when :open_website
|
297
|
+
Image.string("Open website (#{user.website})")
|
298
|
+
when :show_likes
|
299
|
+
Image.number(user.favorites_count) - Image.whitespace - Image.plural(user.favorites_count, 'like')
|
300
|
+
when :show_followers
|
301
|
+
Image.number(user.followers_count) - Image.whitespace - Image.plural(user.followers_count, 'follower')
|
302
|
+
when :show_friends
|
303
|
+
Image.number(user.friends_count) - Image.whitespace - Image.string('following')
|
304
|
+
when :manage_lists
|
305
|
+
Image.string('Add to / Remove from lists')
|
291
306
|
end
|
292
|
-
when :toggle_mute
|
293
|
-
if muting?
|
294
|
-
window.addstr(' Unmute this user')
|
295
|
-
else
|
296
|
-
window.addstr(' Mute this user')
|
297
|
-
end
|
298
|
-
when :open_timeline_tab
|
299
|
-
window.addstr("[ ] #{user.statuses_count.format} tweets")
|
300
|
-
window.setpos(current_line, 6)
|
301
|
-
window.bold { window.addch(?t) }
|
302
|
-
when :open_website
|
303
|
-
window.addstr("[ ] Open website (#{user.website})")
|
304
|
-
window.setpos(current_line, 6)
|
305
|
-
window.bold { window.addch(?W) }
|
306
|
-
when :show_likes
|
307
|
-
window.addstr(" #{user.favorites_count.format} likes")
|
308
|
-
when :show_followers
|
309
|
-
window.addstr(" #{user.followers_count.format} followers")
|
310
|
-
when :show_friends
|
311
|
-
window.addstr(" #{user.friends_count.format} following")
|
312
|
-
end
|
313
|
-
|
314
|
-
current_line += 2
|
315
307
|
end
|
308
|
+
.intersperse(Image.blank_line)
|
309
|
+
.reduce(Image.empty, :|)
|
310
|
+
|
311
|
+
[name, badges, status, description, location, foo]
|
312
|
+
.compact
|
313
|
+
.intersperse(Image.blank_line)
|
314
|
+
.reduce(Image.empty, :|)
|
316
315
|
end
|
317
316
|
|
318
317
|
def user
|
319
|
-
|
318
|
+
app.user_repository.find(user_id)
|
320
319
|
end
|
321
320
|
end
|
322
321
|
end
|
@@ -1,11 +1,14 @@
|
|
1
|
+
require 'concurrent'
|
2
|
+
|
1
3
|
require 'twterm/tab/base'
|
4
|
+
require 'twterm/tab/loadable'
|
2
5
|
|
3
6
|
module Twterm
|
4
7
|
module Tab
|
5
8
|
module Users
|
6
9
|
class Base < Tab::Base
|
7
|
-
include
|
8
|
-
include
|
10
|
+
include Loadable
|
11
|
+
include Searchable
|
9
12
|
|
10
13
|
attr_reader :user_ids
|
11
14
|
|
@@ -13,37 +16,35 @@ module Twterm
|
|
13
16
|
(window.maxy - 6).div(3)
|
14
17
|
end
|
15
18
|
|
16
|
-
def close
|
17
|
-
@instance_keeper.kill
|
18
|
-
super
|
19
|
-
end
|
20
|
-
|
21
19
|
def fetch; end
|
22
20
|
|
23
|
-
def initialize
|
24
|
-
super()
|
25
|
-
@user_ids =
|
26
|
-
|
27
|
-
@instance_keeper = Scheduler.new(300) { items.each(&:touch!) }
|
21
|
+
def initialize(app, client)
|
22
|
+
super(app, client)
|
23
|
+
@user_ids = Concurrent::Array.new
|
28
24
|
end
|
29
25
|
|
30
26
|
def items
|
31
|
-
|
32
|
-
|
27
|
+
user_ids.map { |id| app.user_repository.find(id) }.compact
|
28
|
+
end
|
29
|
+
|
30
|
+
def matches?(user, query)
|
31
|
+
[
|
32
|
+
user.name,
|
33
|
+
user.screen_name,
|
34
|
+
user.description
|
35
|
+
].compact.any? { |x| x.downcase.include?(query.downcase) }
|
33
36
|
end
|
34
37
|
|
35
38
|
def respond_to_key(key)
|
36
39
|
return true if scroller.respond_to_key(key)
|
37
40
|
|
41
|
+
k = KeyMapper.instance
|
42
|
+
|
38
43
|
case key
|
39
|
-
when 10
|
44
|
+
when 10
|
40
45
|
show_user
|
41
|
-
when
|
46
|
+
when k[:tab, :reload]
|
42
47
|
fetch
|
43
|
-
when ?q
|
44
|
-
reset_filter
|
45
|
-
when ?/
|
46
|
-
filter
|
47
48
|
else
|
48
49
|
return false
|
49
50
|
end
|
@@ -59,31 +60,28 @@ module Twterm
|
|
59
60
|
|
60
61
|
def show_user
|
61
62
|
user = current_item
|
62
|
-
tab = Tab::UserTab.new(user.id)
|
63
|
-
|
63
|
+
tab = Tab::UserTab.new(app, client, user.id)
|
64
|
+
app.tab_manager.add_and_show(tab)
|
64
65
|
end
|
65
66
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
window.bold { window.with_color(user.color) { window.addstr(user.name) } }
|
80
|
-
window.addstr(" (@#{user.screen_name})")
|
81
|
-
window.with_color(:yellow) { window.addstr(' [protected]') } if user.protected?
|
82
|
-
window.with_color(:cyan) { window.addstr(' [verified]') } if user.verified?
|
83
|
-
window.setpos(i * 3 + 6, 7)
|
67
|
+
def image
|
68
|
+
return Image.string(initially_loaded? ? 'No result found' : 'Loading...') if items.empty?
|
69
|
+
|
70
|
+
drawable_items.map.with_index(0) do |user, i|
|
71
|
+
cursor = Image.cursor(2, scroller.current_index?(i))
|
72
|
+
|
73
|
+
header = [
|
74
|
+
!Image.string(user.name).color(user.color),
|
75
|
+
Image.string("@#{user.screen_name}"),
|
76
|
+
(Image.string('protected').brackets if user.protected?),
|
77
|
+
(Image.string('verified').brackets if user.verified?),
|
78
|
+
].compact.intersperse(Image.whitespace).reduce(Image.empty, :-)
|
79
|
+
|
84
80
|
bio_chunks = user.description.gsub(/[\n\r]/, ' ').split_by_width(window.maxx - 10)
|
85
|
-
|
81
|
+
cursor - Image.whitespace - (header | Image.string("#{bio_chunks[0]}#{'...' unless bio_chunks[1].nil?}"))
|
86
82
|
end
|
83
|
+
.intersperse(Image.blank_line)
|
84
|
+
.reduce(Image.empty, :|)
|
87
85
|
end
|
88
86
|
end
|
89
87
|
end
|
@@ -13,18 +13,21 @@ module Twterm
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def fetch
|
16
|
-
|
16
|
+
client.followers(user_id) do |users|
|
17
17
|
@user_ids.concat(users.map(&:id)).uniq!
|
18
|
-
|
18
|
+
render
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def initialize(user_id)
|
23
|
-
super()
|
22
|
+
def initialize(app, client, user_id)
|
23
|
+
super(app, client)
|
24
24
|
|
25
25
|
@user_id = user_id
|
26
26
|
|
27
|
-
fetch
|
27
|
+
fetch.then do
|
28
|
+
initially_loaded!
|
29
|
+
move_to_top
|
30
|
+
end
|
28
31
|
end
|
29
32
|
|
30
33
|
def title
|
@@ -34,7 +37,7 @@ module Twterm
|
|
34
37
|
private
|
35
38
|
|
36
39
|
def user
|
37
|
-
|
40
|
+
app.user_repository.find(user_id)
|
38
41
|
end
|
39
42
|
end
|
40
43
|
end
|