移転させました https://launchpad.net/twikoto/ver2.x
Revision | 484eb9425c571ab1951a4ab03ec34dfe6def94f7 (tree) |
---|---|
Zeit | 2011-06-16 16:14:48 |
Autor | azyobuzin <azyobuzin@user...> |
Commiter | azyobuzin |
ReactiveOAuth使うようにしてみた
TODO:タイムライン取得
@@ -0,0 +1,73 @@ | ||
1 | +<?xml version="1.0"?> | |
2 | +<doc> | |
3 | + <assembly> | |
4 | + <name>ReactiveOAuth</name> | |
5 | + </assembly> | |
6 | + <members> | |
7 | + <member name="T:Codeplex.OAuth.MethodType"> | |
8 | + <summary>WebRequest HttpMethodType</summary> | |
9 | + </member> | |
10 | + <member name="M:Codeplex.OAuth.MethodTypeExtensions.ToUpperString(Codeplex.OAuth.MethodType)"> | |
11 | + <summary>convert to UPPERCASE string</summary> | |
12 | + </member> | |
13 | + <member name="T:Codeplex.OAuth.OAuthAuthorizer"> | |
14 | + <summary>OAuth Authorization Client</summary> | |
15 | + </member> | |
16 | + <member name="M:Codeplex.OAuth.OAuthAuthorizer.BuildAuthorizeUrl(System.String,Codeplex.OAuth.RequestToken)"> | |
17 | + <summary>construct AuthrizeUrl + RequestTokenKey</summary> | |
18 | + </member> | |
19 | + <member name="M:Codeplex.OAuth.OAuthAuthorizer.GetRequestToken(System.String,Codeplex.OAuth.Parameter[])"> | |
20 | + <summary>asynchronus get RequestToken</summary> | |
21 | + <param name="otherParameters">need parameters except consumer_key,timestamp,nonce,signature,signature_method,version</param> | |
22 | + </member> | |
23 | + <member name="M:Codeplex.OAuth.OAuthAuthorizer.GetRequestToken(System.String,System.Collections.Generic.IEnumerable{Codeplex.OAuth.Parameter})"> | |
24 | + <summary>asynchronus get RequestToken</summary> | |
25 | + <param name="otherParameters">need parameters except consumer_key,timestamp,nonce,signature,signature_method,version</param> | |
26 | + </member> | |
27 | + <member name="M:Codeplex.OAuth.OAuthAuthorizer.GetAccessToken(System.String,Codeplex.OAuth.RequestToken,System.String)"> | |
28 | + <summary>asynchronus get GetAccessToken</summary> | |
29 | + </member> | |
30 | + <member name="M:Codeplex.OAuth.OAuthAuthorizer.GetAccessToken(System.String,System.String,System.String,System.String)"> | |
31 | + <summary>asynchronus get GetAccessToken for xAuth</summary> | |
32 | + </member> | |
33 | + <member name="T:Codeplex.OAuth.OAuthClient"> | |
34 | + <summary>access protected resource client</summary> | |
35 | + </member> | |
36 | + <member name="M:Codeplex.OAuth.OAuthClient.GetResponse"> | |
37 | + <summary>asynchronus GetResponse</summary> | |
38 | + </member> | |
39 | + <member name="M:Codeplex.OAuth.OAuthClient.GetResponseText"> | |
40 | + <summary>asynchronus GetResponse and return ResponseText</summary> | |
41 | + </member> | |
42 | + <member name="M:Codeplex.OAuth.OAuthClient.GetResponseLines"> | |
43 | + <summary>asynchronus GetResponse and return onelines</summary> | |
44 | + </member> | |
45 | + <member name="T:Codeplex.OAuth.Parameter"> | |
46 | + <summary>represents query parameter(Key and Value)</summary> | |
47 | + </member> | |
48 | + <member name="M:Codeplex.OAuth.Parameter.ToString"> | |
49 | + <summary>UrlEncode(Key)=UrlEncode(Value)</summary> | |
50 | + </member> | |
51 | + <member name="T:Codeplex.OAuth.ParameterCollection"> | |
52 | + <summary>represents query parameter(Key and Value) collection</summary> | |
53 | + </member> | |
54 | + <member name="M:Codeplex.OAuth.ParametersExtension.ToQueryParameter(System.Collections.Generic.IEnumerable{Codeplex.OAuth.Parameter})"> | |
55 | + <summary>convert urlencoded querystring</summary> | |
56 | + </member> | |
57 | + <member name="T:Codeplex.OAuth.Token"> | |
58 | + <summary>represents OAuth Token</summary> | |
59 | + </member> | |
60 | + <member name="T:Codeplex.OAuth.AccessToken"> | |
61 | + <summary>represents OAuth AccessToken</summary> | |
62 | + </member> | |
63 | + <member name="T:Codeplex.OAuth.RequestToken"> | |
64 | + <summary>represents OAuth RequestToken</summary> | |
65 | + </member> | |
66 | + <member name="T:Codeplex.OAuth.TokenResponse`1"> | |
67 | + <summary>OAuth Response</summary> | |
68 | + </member> | |
69 | + <member name="M:Codeplex.OAuth.Utility.UrlEncode(System.String)"> | |
70 | + <summary>Escape RFC3986 String</summary> | |
71 | + </member> | |
72 | + </members> | |
73 | +</doc> |
@@ -1,12 +1,14 @@ | ||
1 | 1 | using System; |
2 | 2 | using System.Collections.Generic; |
3 | 3 | using System.Linq; |
4 | -using System.Text; | |
5 | - | |
6 | -using Livet; | |
7 | -using LinqToTwitter; | |
4 | +using System.Net; | |
5 | +using System.Reactive.Linq; | |
8 | 6 | using System.Threading; |
9 | 7 | using System.Threading.Tasks; |
8 | +using System.Xml.Linq; | |
9 | +using Azyobuzi.Twikoto2.Models.Twitter; | |
10 | +using Codeplex.OAuth; | |
11 | +using Livet; | |
10 | 12 | |
11 | 13 | namespace Azyobuzi.Twikoto2.Models |
12 | 14 | { |
@@ -35,7 +37,10 @@ namespace Azyobuzi.Twikoto2.Models | ||
35 | 37 | } |
36 | 38 | } |
37 | 39 | |
38 | - private TwitterContext twCtx = new TwitterContext(); | |
40 | + private const string ConsumerKey = "otUyZUQT0lupkH2Pnt4Zbw"; | |
41 | + private const string ConsumerSecret = "RwgpTjzZVXFeSOywxwVLaCViP3G68dXQCzi3xNApA"; | |
42 | + | |
43 | + private AccessToken token; | |
39 | 44 | |
40 | 45 | bool _IsAuthorized; |
41 | 46 |
@@ -54,40 +59,17 @@ namespace Azyobuzi.Twikoto2.Models | ||
54 | 59 | |
55 | 60 | public void Authorize() |
56 | 61 | { |
57 | - var auth = new PinAuthorizer() | |
58 | - { | |
59 | - UserAgent = "Twikoto2" | |
60 | - }; | |
61 | - | |
62 | - twCtx.AuthorizedClient = auth; | |
63 | - | |
64 | - const string ConsumerKey = "otUyZUQT0lupkH2Pnt4Zbw"; | |
65 | - const string ConsumerSecret = "RwgpTjzZVXFeSOywxwVLaCViP3G68dXQCzi3xNApA"; | |
62 | + ServicePointManager.Expect100Continue = false; | |
66 | 63 | |
67 | 64 | if (string.IsNullOrEmpty(Settings.AccessToken) || string.IsNullOrEmpty(Settings.AccessTokenSecret)) |
68 | 65 | { |
69 | - auth.Credentials = new InMemoryCredentials() | |
70 | - { | |
71 | - ConsumerKey = ConsumerKey, | |
72 | - ConsumerSecret = ConsumerSecret | |
73 | - }; | |
74 | - | |
75 | - auth.GoToTwitterAuthorization = uri => OnRequestPinCode(new RequestPinCodeEventArgs() | |
76 | - { | |
77 | - AuthorizeUri = uri | |
78 | - }); | |
79 | - | |
80 | - auth.BeginAuthorize(_ => { }); | |
66 | + var auth = new OAuthAuthorizer(ConsumerKey, ConsumerSecret); | |
67 | + auth.GetRequestToken("https://api.twitter.com/oauth/request_token") | |
68 | + .Subscribe(_ => OnRequestPinCode(new RequestPinCodeEventArgs(auth, _.Token))); | |
81 | 69 | } |
82 | 70 | else |
83 | 71 | { |
84 | - auth.Credentials = new InMemoryCredentials() | |
85 | - { | |
86 | - ConsumerKey = ConsumerKey, | |
87 | - ConsumerSecret = ConsumerSecret, | |
88 | - OAuthToken = this.Settings.AccessToken, | |
89 | - AccessToken = this.Settings.AccessTokenSecret | |
90 | - }; | |
72 | + token = new AccessToken(this.Settings.AccessToken, this.Settings.AccessTokenSecret); | |
91 | 73 | this.IsAuthorized = true; |
92 | 74 | } |
93 | 75 | } |
@@ -115,37 +97,34 @@ namespace Azyobuzi.Twikoto2.Models | ||
115 | 97 | } |
116 | 98 | #endregion |
117 | 99 | |
118 | - public void EndAuthorize(string pin, Action<TwitterAsyncResponse<UserIdentifier>> callback) | |
100 | + public IObservable<TokenResponse<AccessToken>> EndAuthorize(RequestToken reqToken, string pin) | |
119 | 101 | { |
120 | - try | |
121 | - { | |
122 | - var auth = (PinAuthorizer)this.twCtx.AuthorizedClient; | |
123 | - auth.CompleteAuthorize(pin, res => | |
124 | - { | |
125 | - if (res.Status == TwitterErrorStatus.Success) | |
126 | - { | |
127 | - this.Settings.AccessToken = auth.OAuthTwitter.OAuthToken; | |
128 | - this.Settings.AccessTokenSecret = auth.OAuthTwitter.OAuthTokenSecret; | |
129 | - this.Settings.ScreenName = res.State.ScreenName; | |
130 | - } | |
131 | - callback(res); | |
132 | - }); | |
133 | - } | |
134 | - catch (Exception ex) | |
135 | - { | |
136 | - callback(new TwitterAsyncResponse<UserIdentifier>() | |
102 | + return new OAuthAuthorizer(ConsumerKey, ConsumerSecret) | |
103 | + .GetAccessToken("https://api.twitter.com/oauth/access_token", reqToken, pin) | |
104 | + .Do(_ => | |
137 | 105 | { |
138 | - Error = ex, | |
139 | - Status = TwitterErrorStatus.RequestProcessingException | |
106 | + this.token = _.Token; | |
107 | + this.Settings.AccessToken = _.Token.Key; | |
108 | + this.Settings.AccessTokenSecret = _.Token.Secret; | |
109 | + this.Settings.ScreenName = _.ExtraData["screen_name"].First(); | |
110 | + this.IsAuthorized = true; | |
140 | 111 | }); |
141 | - } | |
142 | 112 | } |
143 | 113 | |
144 | - public Task<Status> UpdateStatus(string text, string inReplyToId) | |
114 | + public IObservable<Status> UpdateStatus(string text, string inReplyToId) | |
145 | 115 | { |
146 | - var t = new Task<Status>(() => twCtx.UpdateStatus(text, inReplyToId)); | |
147 | - t.Start(); | |
148 | - return t; | |
116 | + return new OAuthClient(ConsumerKey, ConsumerSecret, this.token) | |
117 | + { | |
118 | + Url = "https://api.twitter.com/1/statuses/update.xml", | |
119 | + MethodType = MethodType.Post, | |
120 | + Parameters = | |
121 | + { | |
122 | + { "status", text }, | |
123 | + { "in_reply_to_status_id", inReplyToId } | |
124 | + } | |
125 | + } | |
126 | + .GetResponseText() | |
127 | + .Select(_ => new Status(XElement.Parse(_))); | |
149 | 128 | } |
150 | 129 | |
151 | 130 | private Dictionary<Query, DispatcherCollection<Status>> timelinesCache = |
@@ -189,29 +168,29 @@ namespace Azyobuzi.Twikoto2.Models | ||
189 | 168 | { |
190 | 169 | var timeline = this.Timeline; |
191 | 170 | IEnumerable<Status> statuses = Enumerable.Empty<Status>(); |
192 | - | |
193 | - switch (this.currentQuery.Type) | |
194 | - { | |
195 | - case TimelineTypes.Home: | |
196 | - case TimelineTypes.Mentions: | |
197 | - statuses = from status in twCtx.Status | |
198 | - where status.Type == | |
199 | - (this.currentQuery.Type == TimelineTypes.Home ? | |
200 | - StatusType.Home : StatusType.Mentions) && | |
201 | - status.Page == page | |
202 | - select status; | |
203 | - break; | |
204 | - case TimelineTypes.List: | |
205 | - var splited = this.currentQuery.Parameter.Split('/'); | |
206 | - statuses = (from list in twCtx.List | |
207 | - where list.Type == ListType.Statuses && | |
208 | - list./*Owner*/ScreenName == splited[0].TrimStart('@') && | |
209 | - list.ListID == splited[1] && | |
210 | - list.Page == page | |
211 | - select list.Statuses) | |
212 | - .FirstOrDefault(); | |
213 | - break; | |
214 | - } | |
171 | + //TODO | |
172 | + //switch (this.currentQuery.Type) | |
173 | + //{ | |
174 | + // case TimelineTypes.Home: | |
175 | + // case TimelineTypes.Mentions: | |
176 | + // statuses = from status in twCtx.Status | |
177 | + // where status.Type == | |
178 | + // (this.currentQuery.Type == TimelineTypes.Home ? | |
179 | + // StatusType.Home : StatusType.Mentions) && | |
180 | + // status.Page == page | |
181 | + // select status; | |
182 | + // break; | |
183 | + // case TimelineTypes.List: | |
184 | + // var splited = this.currentQuery.Parameter.Split('/'); | |
185 | + // statuses = (from list in twCtx.List | |
186 | + // where list.Type == ListType.Statuses && | |
187 | + // list./*Owner*/ScreenName == splited[0].TrimStart('@') && | |
188 | + // list.ListID == splited[1] && | |
189 | + // list.Page == page | |
190 | + // select list.Statuses) | |
191 | + // .FirstOrDefault(); | |
192 | + // break; | |
193 | + //} | |
215 | 194 | |
216 | 195 | foreach (var status in statuses.Where(status => !timeline.Contains(status))) |
217 | 196 | timeline.Add(status); |
@@ -229,12 +208,16 @@ namespace Azyobuzi.Twikoto2.Models | ||
229 | 208 | } |
230 | 209 | } |
231 | 210 | |
232 | - public IEnumerable<List> GetLists() | |
211 | + public IObservable<string> GetListNames() | |
233 | 212 | { |
234 | - return new[] { ListType.Lists, ListType.Subscriptions } | |
235 | - .SelectMany(type => twCtx.List | |
236 | - .Where(list => list.Type == type && list.ScreenName == this.Settings.ScreenName) | |
237 | - .OrderBy(list => list.FullName)); | |
213 | + return new[] { "https://api.twitter.com/2/lists.xml", "https://api.twitter.com/2/lists/subscriptions.xml" } | |
214 | + .ToObservable() | |
215 | + .SelectMany(_ => new OAuthClient(ConsumerKey, ConsumerSecret, token) { Url = _ }.GetResponseText()) | |
216 | + .SelectMany(_ => XElement.Parse(_) | |
217 | + .Element("lists") | |
218 | + .Elements("list") | |
219 | + .Select(listElm => listElm.Element("full_name").Value) | |
220 | + ); | |
238 | 221 | } |
239 | 222 | } |
240 | 223 | } |
@@ -1,9 +1,19 @@ | ||
1 | 1 | using System; |
2 | +using Codeplex.OAuth; | |
2 | 3 | |
3 | 4 | namespace Azyobuzi.Twikoto2.Models |
4 | 5 | { |
5 | 6 | class RequestPinCodeEventArgs : EventArgs |
6 | 7 | { |
7 | - public string AuthorizeUri { set; get; } | |
8 | + public RequestPinCodeEventArgs(OAuthAuthorizer authorizer, RequestToken requestToken) | |
9 | + { | |
10 | + this.RequestToken = requestToken; | |
11 | + this.AuthorizeUri = authorizer.BuildAuthorizeUrl( | |
12 | + "https://api.twitter.com/oauth/authorize", | |
13 | + requestToken); | |
14 | + } | |
15 | + | |
16 | + public RequestToken RequestToken { private set; get; } | |
17 | + public string AuthorizeUri { private set; get; } | |
8 | 18 | } |
9 | 19 | } |
@@ -0,0 +1,30 @@ | ||
1 | +using System; | |
2 | +using System.Globalization; | |
3 | +using System.Xml.Linq; | |
4 | + | |
5 | +namespace Azyobuzi.Twikoto2.Models.Twitter | |
6 | +{ | |
7 | + public class Status | |
8 | + { | |
9 | + public Status() { } | |
10 | + | |
11 | + public Status(XElement xml) | |
12 | + { | |
13 | + this.CreatedAt = DateTime.ParseExact( | |
14 | + xml.Element("created_at").Value, | |
15 | + "ddd MMM dd HH:mm:ss %zzzz yyyy", | |
16 | + CultureInfo.InvariantCulture, | |
17 | + DateTimeStyles.AssumeUniversal); | |
18 | + this.Id = xml.Element("id").Value; | |
19 | + this.InReplyToStatusId = xml.Element("in_reply_to_status_id").Value; | |
20 | + this.Text = xml.Element("text").Value; | |
21 | + this.User = new User(xml.Element("user")); | |
22 | + } | |
23 | + | |
24 | + public DateTime CreatedAt { get; set; } | |
25 | + public string Id { get; set; } | |
26 | + public string InReplyToStatusId { get; set; } | |
27 | + public string Text { get; set; } | |
28 | + public User User { get; set; } | |
29 | + } | |
30 | +} |
@@ -0,0 +1,38 @@ | ||
1 | +using System; | |
2 | +using System.Globalization; | |
3 | +using System.Xml.Linq; | |
4 | + | |
5 | +namespace Azyobuzi.Twikoto2.Models.Twitter | |
6 | +{ | |
7 | + public class User | |
8 | + { | |
9 | + public User() { } | |
10 | + | |
11 | + public User(XElement xml) | |
12 | + { | |
13 | + this.CreatedAt = DateTime.ParseExact( | |
14 | + xml.Element("created_at").Value, | |
15 | + "ddd MMM dd HH:mm:ss %zzzz yyyy", | |
16 | + CultureInfo.InvariantCulture, | |
17 | + DateTimeStyles.AssumeUniversal); | |
18 | + this.Id = xml.Element("id").Value; | |
19 | + this.ScreenName = xml.Element("screen_name").Value; | |
20 | + this.Name = xml.Element("name").Value; | |
21 | + this.Description = xml.Element("description").Value; | |
22 | + this.Location = xml.Element("location").Value; | |
23 | + this.FriendsCount = int.Parse(xml.Element("friends_count").Value); | |
24 | + this.FollowersCount = int.Parse(xml.Element("followers_count").Value); | |
25 | + this.StatusesCount = int.Parse(xml.Element("statuses_count").Value); | |
26 | + } | |
27 | + | |
28 | + public DateTime CreatedAt { get; set; } | |
29 | + public string Id { get; set; } | |
30 | + public string ScreenName { get; set; } | |
31 | + public string Name { get; set; } | |
32 | + public string Description { get; set; } | |
33 | + public string Location { get; set; } | |
34 | + public int FriendsCount { get; set; } | |
35 | + public int FollowersCount { get; set; } | |
36 | + public int StatusesCount { get; set; } | |
37 | + } | |
38 | +} |
@@ -1,10 +0,0 @@ | ||
1 | -using System; | |
2 | -using LinqToTwitter; | |
3 | - | |
4 | -namespace Azyobuzi.Twikoto2.Models | |
5 | -{ | |
6 | - class UpdateStatusCompletedEventArgs : EventArgs | |
7 | - { | |
8 | - public TwitterAsyncResponse<Status> Result { set; get; } | |
9 | - } | |
10 | -} |
@@ -1,7 +1,7 @@ | ||
1 | 1 | //------------------------------------------------------------------------------ |
2 | 2 | // <auto-generated> |
3 | 3 | // このコードはツールによって生成されました。 |
4 | -// ランタイム バージョン:4.0.30319.225 | |
4 | +// ランタイム バージョン:4.0.30319.235 | |
5 | 5 | // |
6 | 6 | // このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 |
7 | 7 | // コードが再生成されるときに損失したりします。 |
@@ -1,7 +1,7 @@ | ||
1 | 1 | //------------------------------------------------------------------------------ |
2 | 2 | // <auto-generated> |
3 | 3 | // このコードはツールによって生成されました。 |
4 | -// ランタイム バージョン:4.0.30319.225 | |
4 | +// ランタイム バージョン:4.0.30319.235 | |
5 | 5 | // |
6 | 6 | // このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 |
7 | 7 | // コードが再生成されるときに損失したりします。 |
@@ -1,4 +1,5 @@ | ||
1 | 1 | using System; |
2 | +using Codeplex.OAuth; | |
2 | 3 | using Livet; |
3 | 4 | using Livet.Command; |
4 | 5 | using Livet.Messaging.Window; |
@@ -8,6 +9,8 @@ namespace Azyobuzi.Twikoto2.ViewModels | ||
8 | 9 | public class InputPinWindowViewModel : ViewModel |
9 | 10 | { |
10 | 11 | public Uri AuthorizeUri { set; get; } |
12 | + | |
13 | + public RequestToken RequestToken { set; get; } | |
11 | 14 | |
12 | 15 | string _PinCode; |
13 | 16 |
@@ -1,17 +1,15 @@ | ||
1 | 1 | using System; |
2 | -using System.Collections.Generic; | |
3 | -using System.Linq; | |
4 | -using System.Text; | |
5 | 2 | using System.ComponentModel; |
6 | -using System.Threading; | |
3 | +using System.Linq; | |
4 | +using System.Reactive.Linq; | |
5 | +using System.Threading.Tasks; | |
6 | +using System.Windows; | |
7 | +using Azyobuzi.Twikoto2.Models; | |
8 | +using Azyobuzi.Twikoto2.Models.Twitter; | |
7 | 9 | using Livet; |
8 | 10 | using Livet.Command; |
9 | 11 | using Livet.Messaging; |
10 | -using Livet.Messaging.File; | |
11 | 12 | using Livet.Messaging.Window; |
12 | -using Azyobuzi.Twikoto2.Models; | |
13 | -using System.Windows; | |
14 | -using System.Threading.Tasks; | |
15 | 13 | |
16 | 14 | namespace Azyobuzi.Twikoto2.ViewModels |
17 | 15 | { |
@@ -69,7 +67,7 @@ namespace Azyobuzi.Twikoto2.ViewModels | ||
69 | 67 | DispatcherHelper.UIDispatcher); |
70 | 68 | this.SelectedQuery = this.QueryTypes[0]; |
71 | 69 | } |
72 | - | |
70 | + | |
73 | 71 | private Model model = new Model(); |
74 | 72 | |
75 | 73 | public Settings Settings |
@@ -82,29 +80,22 @@ namespace Azyobuzi.Twikoto2.ViewModels | ||
82 | 80 | |
83 | 81 | private void GetLists() |
84 | 82 | { |
85 | - var t = new Task(() => | |
86 | - { | |
87 | - foreach (var list in this.model.GetLists()) | |
88 | - this.QueryTypes.Add(new QueryViewModel() | |
89 | - { | |
90 | - Type = TimelineTypes.List, | |
91 | - Name = "List : " + list.FullName, | |
92 | - Parameter = list.FullName | |
93 | - }); | |
94 | - }); | |
95 | - t.Start(); | |
96 | - t.ContinueWith(resTask => | |
97 | - { | |
98 | - if (resTask.Exception != null) | |
83 | + this.model.GetListNames() | |
84 | + .Select(_ => new QueryViewModel() | |
99 | 85 | { |
100 | - DispatcherHelper.BeginInvoke(() => | |
86 | + Type = TimelineTypes.List, | |
87 | + Name = "List : " + _, | |
88 | + Parameter = _ | |
89 | + }) | |
90 | + .Subscribe( | |
91 | + this.QueryTypes.Add, | |
92 | + ex => DispatcherHelper.BeginInvoke(() => | |
101 | 93 | this.Messenger.Raise(new InformationMessage( |
102 | - resTask.Exception.ToString(), | |
94 | + ex.ToString(), | |
103 | 95 | "リスト取得失敗", |
104 | 96 | MessageBoxImage.Error, |
105 | - "ShowInfo"))); | |
106 | - } | |
107 | - }); | |
97 | + "ShowInfo"))) | |
98 | + ); | |
108 | 99 | } |
109 | 100 | |
110 | 101 | #region LoadedCommand |
@@ -134,7 +125,11 @@ namespace Azyobuzi.Twikoto2.ViewModels | ||
134 | 125 | DispatcherHelper.BeginInvoke(() => |
135 | 126 | { |
136 | 127 | this.Authorizing = true; |
137 | - var vm = new InputPinWindowViewModel() { AuthorizeUri = new Uri(e.AuthorizeUri) }; | |
128 | + var vm = new InputPinWindowViewModel() | |
129 | + { | |
130 | + AuthorizeUri = new Uri(e.AuthorizeUri), | |
131 | + RequestToken = e.RequestToken | |
132 | + }; | |
138 | 133 | vm.PropertyChanged += this.InputPinWindowViewModel_PropertyChanged; |
139 | 134 | this.Messenger.Raise(new TransitionMessage(vm, "GetPinCode")); |
140 | 135 | }); |
@@ -146,24 +141,22 @@ namespace Azyobuzi.Twikoto2.ViewModels | ||
146 | 141 | if (e.PropertyName == "Closed" && vm.Closed) |
147 | 142 | { |
148 | 143 | vm.PropertyChanged -= this.InputPinWindowViewModel_PropertyChanged; |
149 | - this.model.EndAuthorize(vm.PinCode, res => | |
150 | - { | |
151 | - this.Authorizing = false; | |
144 | + this.model.EndAuthorize(vm.RequestToken, vm.PinCode) | |
145 | + .ObserveOnDispatcher() | |
146 | + .Finally(() => this.Authorizing = false) | |
147 | + .Subscribe( | |
148 | + _ => this.GetLists(), | |
149 | + ex => | |
150 | + { | |
151 | + this.Messenger.Raise(new InformationMessage( | |
152 | + ex.ToString(), | |
153 | + "認証失敗", | |
154 | + MessageBoxImage.Error, | |
155 | + "ShowInfo")); | |
156 | + this.Messenger.Raise(new WindowActionMessage("ChangeWindowState", WindowAction.Close)); | |
157 | + } | |
158 | + ); | |
152 | 159 | |
153 | - if (res.Error != null) | |
154 | - { | |
155 | - this.Messenger.Raise(new InformationMessage( | |
156 | - res.Error.ToString(), | |
157 | - "認証失敗", | |
158 | - MessageBoxImage.Error, | |
159 | - "ShowInfo")); | |
160 | - this.Messenger.Raise(new WindowActionMessage("ChangeWindowState", WindowAction.Close)); | |
161 | - } | |
162 | - else | |
163 | - { | |
164 | - this.GetLists(); | |
165 | - } | |
166 | - }); | |
167 | 160 | } |
168 | 161 | } |
169 | 162 |
@@ -181,7 +174,7 @@ namespace Azyobuzi.Twikoto2.ViewModels | ||
181 | 174 | RaisePropertyChanged("Authorizing"); |
182 | 175 | } |
183 | 176 | } |
184 | - | |
177 | + | |
185 | 178 | #region ClosingCommand |
186 | 179 | DelegateCommand _ClosingCommand; |
187 | 180 |
@@ -200,7 +193,7 @@ namespace Azyobuzi.Twikoto2.ViewModels | ||
200 | 193 | this.Settings.Save(); |
201 | 194 | } |
202 | 195 | #endregion |
203 | - | |
196 | + | |
204 | 197 | string _StatusText = ""; |
205 | 198 | |
206 | 199 | public string StatusText |
@@ -224,7 +217,7 @@ namespace Azyobuzi.Twikoto2.ViewModels | ||
224 | 217 | return StatusText.Trim().Length > 140; |
225 | 218 | } |
226 | 219 | } |
227 | - | |
220 | + | |
228 | 221 | string _InReplyToId = ""; |
229 | 222 | |
230 | 223 | public string InReplyToId |
@@ -241,7 +234,7 @@ namespace Azyobuzi.Twikoto2.ViewModels | ||
241 | 234 | RaisePropertyChanged("InReplyToId"); |
242 | 235 | } |
243 | 236 | } |
244 | - | |
237 | + | |
245 | 238 | bool _Posting; |
246 | 239 | |
247 | 240 | public bool Posting |
@@ -256,7 +249,7 @@ namespace Azyobuzi.Twikoto2.ViewModels | ||
256 | 249 | RaisePropertyChanged("Posting"); |
257 | 250 | } |
258 | 251 | } |
259 | - | |
252 | + | |
260 | 253 | #region PostCommand |
261 | 254 | DelegateCommand _PostCommand; |
262 | 255 |
@@ -280,30 +273,26 @@ namespace Azyobuzi.Twikoto2.ViewModels | ||
280 | 273 | private void Post() |
281 | 274 | { |
282 | 275 | this.Posting = true; |
283 | - var t = this.model.UpdateStatus(this.StatusText, this.InReplyToId); | |
284 | - t.ContinueWith(resTask => | |
285 | - { | |
286 | - this.Posting = false; | |
287 | - if (resTask.Exception == null) | |
288 | - { | |
289 | - this.StatusText = ""; | |
290 | - this.InReplyToId = ""; | |
291 | - } | |
292 | - else | |
293 | - { | |
294 | - DispatcherHelper.BeginInvoke(() => | |
295 | - this.Messenger.Raise(new InformationMessage( | |
296 | - resTask.Exception.ToString(), | |
297 | - "投稿失敗", | |
298 | - MessageBoxImage.Error, | |
299 | - "ShowInfo"))); | |
300 | - } | |
301 | - }); | |
276 | + this.model.UpdateStatus(this.StatusText, this.InReplyToId) | |
277 | + .ObserveOnDispatcher() | |
278 | + .Finally(() => this.Posting = false) | |
279 | + .Subscribe( | |
280 | + _ => | |
281 | + { | |
282 | + this.StatusText = ""; | |
283 | + this.InReplyToId = ""; | |
284 | + }, | |
285 | + ex => this.Messenger.Raise(new InformationMessage( | |
286 | + ex.ToString(), | |
287 | + "投稿失敗", | |
288 | + MessageBoxImage.Error, | |
289 | + "ShowInfo"))); | |
290 | + | |
302 | 291 | } |
303 | 292 | #endregion |
304 | - | |
293 | + | |
305 | 294 | public DispatcherCollection<QueryViewModel> QueryTypes { private set; get; } |
306 | - | |
295 | + | |
307 | 296 | QueryViewModel _SelectedQuery; |
308 | 297 | |
309 | 298 | public QueryViewModel SelectedQuery |
@@ -335,7 +324,7 @@ namespace Azyobuzi.Twikoto2.ViewModels | ||
335 | 324 | } |
336 | 325 | } |
337 | 326 | |
338 | - public DispatcherCollection<LinqToTwitter.Status> Timeline | |
327 | + public DispatcherCollection<Status> Timeline | |
339 | 328 | { |
340 | 329 | get |
341 | 330 | { |
@@ -1,3 +1,11 @@ | ||
1 | 1 | <?xml version="1.0"?> |
2 | 2 | <configuration> |
3 | -<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration> | |
3 | +<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/></startup> <runtime> | |
4 | + <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> | |
5 | + <dependentAssembly> | |
6 | + <assemblyIdentity name="System.Reactive" publicKeyToken="31BF3856AD364E35" culture="neutral"/> | |
7 | + <bindingRedirect oldVersion="0.0.0.0-1.1.10605.0" newVersion="1.1.10605.0"/> | |
8 | + </dependentAssembly> | |
9 | + </assemblyBinding> | |
10 | + </runtime> | |
11 | +</configuration> |
@@ -11,8 +11,7 @@ | ||
11 | 11 | <RootNamespace>Azyobuzi.Twikoto2</RootNamespace> |
12 | 12 | <AssemblyName>Twikoto2</AssemblyName> |
13 | 13 | <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> |
14 | - <TargetFrameworkProfile> | |
15 | - </TargetFrameworkProfile> | |
14 | + <TargetFrameworkProfile>Client</TargetFrameworkProfile> | |
16 | 15 | <FileAlignment>512</FileAlignment> |
17 | 16 | <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> |
18 | 17 | <WarningLevel>4</WarningLevel> |
@@ -36,10 +35,6 @@ | ||
36 | 35 | <WarningLevel>4</WarningLevel> |
37 | 36 | </PropertyGroup> |
38 | 37 | <ItemGroup> |
39 | - <Reference Include="LinqToTwitter, Version=2.0.20.0, Culture=neutral, processorArchitecture=MSIL"> | |
40 | - <SpecificVersion>False</SpecificVersion> | |
41 | - <HintPath>InfrastructureAssemblies\LinqToTwitter.dll</HintPath> | |
42 | - </Reference> | |
43 | 38 | <Reference Include="Livet, Version=0.95.2011.517, Culture=neutral, processorArchitecture=MSIL"> |
44 | 39 | <SpecificVersion>False</SpecificVersion> |
45 | 40 | <HintPath>InfrastructureAssemblies\Livet.dll</HintPath> |
@@ -48,8 +43,14 @@ | ||
48 | 43 | <SpecificVersion>False</SpecificVersion> |
49 | 44 | <HintPath>InfrastructureAssemblies\Microsoft.Expression.Interactions.dll</HintPath> |
50 | 45 | </Reference> |
46 | + <Reference Include="ReactiveOAuth, Version=0.3.0.0, Culture=neutral, processorArchitecture=MSIL"> | |
47 | + <SpecificVersion>False</SpecificVersion> | |
48 | + <HintPath>InfrastructureAssemblies\ReactiveOAuth.dll</HintPath> | |
49 | + </Reference> | |
51 | 50 | <Reference Include="System" /> |
52 | 51 | <Reference Include="System.Drawing" /> |
52 | + <Reference Include="System.Reactive, Version=1.1.10605.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" /> | |
53 | + <Reference Include="System.Reactive.Windows.Threading, Version=1.1.10605.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" /> | |
53 | 54 | <Reference Include="System.Windows.Interactivity"> |
54 | 55 | <SpecificVersion>False</SpecificVersion> |
55 | 56 | <HintPath>InfrastructureAssemblies\System.Windows.Interactivity.dll</HintPath> |
@@ -70,6 +71,8 @@ | ||
70 | 71 | <Generator>MSBuild:Compile</Generator> |
71 | 72 | <SubType>Designer</SubType> |
72 | 73 | </ApplicationDefinition> |
74 | + <Compile Include="Models\Twitter\Status.cs" /> | |
75 | + <Compile Include="Models\Twitter\User.cs" /> | |
73 | 76 | <Compile Include="Views\ToLocalTimeConverter.cs" /> |
74 | 77 | <Page Include="Views\InputPinWindow.xaml"> |
75 | 78 | <SubType>Designer</SubType> |
@@ -88,7 +91,6 @@ | ||
88 | 91 | <Compile Include="Models\Model.cs" /> |
89 | 92 | <Compile Include="Models\Query.cs" /> |
90 | 93 | <Compile Include="Models\RequestPinCodeEventArgs.cs" /> |
91 | - <Compile Include="Models\UpdateStatusCompletedEventArgs.cs" /> | |
92 | 94 | <Compile Include="Models\Settings.cs" /> |
93 | 95 | <Compile Include="Models\TimelineTypes.cs" /> |
94 | 96 | <Compile Include="MyNotifyObject.cs" /> |
@@ -121,7 +123,9 @@ | ||
121 | 123 | <Generator>ResXFileCodeGenerator</Generator> |
122 | 124 | <LastGenOutput>Resources.Designer.cs</LastGenOutput> |
123 | 125 | </EmbeddedResource> |
124 | - <None Include="app.config" /> | |
126 | + <None Include="app.config"> | |
127 | + <SubType>Designer</SubType> | |
128 | + </None> | |
125 | 129 | <None Include="Properties\Settings.settings"> |
126 | 130 | <Generator>SettingsSingleFileGenerator</Generator> |
127 | 131 | <LastGenOutput>Settings.Designer.cs</LastGenOutput> |
@@ -131,10 +135,12 @@ | ||
131 | 135 | <ItemGroup> |
132 | 136 | <Content Include="InfrastructureAssemblies\Design\Livet.Design.dll" /> |
133 | 137 | <Content Include="InfrastructureAssemblies\Design\Livet.Expression.Design.dll" /> |
134 | - <Content Include="InfrastructureAssemblies\LinqToTwitter.dll" /> | |
135 | 138 | <Content Include="InfrastructureAssemblies\Livet.dll" /> |
136 | 139 | <Resource Include="InfrastructureAssemblies\Livet.XML" /> |
137 | 140 | <Content Include="InfrastructureAssemblies\Microsoft.Expression.Interactions.dll" /> |
141 | + <Content Include="InfrastructureAssemblies\ReactiveOAuth.dll" /> | |
142 | + <Content Include="InfrastructureAssemblies\ReactiveOAuth.pdb" /> | |
143 | + <Resource Include="InfrastructureAssemblies\ReactiveOAuth.XML" /> | |
138 | 144 | <Content Include="InfrastructureAssemblies\System.Windows.Interactivity.dll" /> |
139 | 145 | </ItemGroup> |
140 | 146 | <ItemGroup> |