• R/O
  • HTTP
  • SSH
  • HTTPS

提交

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

移転させました https://launchpad.net/twikoto/ver2.x


Commit MetaInfo

修订版484eb9425c571ab1951a4ab03ec34dfe6def94f7 (tree)
时间2011-06-16 16:14:48
作者azyobuzin <azyobuzin@user...>
Commiterazyobuzin

Log Message

ReactiveOAuth使うようにしてみた
TODO:タイムライン取得

更改概述

  • delete: "\202\302\202\242\202\261\202\306\202Q/InfrastructureAssemblies/LinqToTwitter.dll"
  • delete: "\202\302\202\242\202\261\202\306\202Q/InfrastructureAssemblies/LinqToTwitter.pdb"
  • delete: "\202\302\202\242\202\261\202\306\202Q/InfrastructureAssemblies/ReactiveOAuth.XML"
  • delete: "\202\302\202\242\202\261\202\306\202Q/InfrastructureAssemblies/ReactiveOAuth.dll"
  • delete: "\202\302\202\242\202\261\202\306\202Q/InfrastructureAssemblies/ReactiveOAuth.pdb"
  • delete: "\202\302\202\242\202\261\202\306\202Q/Models/Model.cs"
  • delete: "\202\302\202\242\202\261\202\306\202Q/Models/RequestPinCodeEventArgs.cs"
  • delete: "\202\302\202\242\202\261\202\306\202Q/Models/Twitter/Status.cs"
  • delete: "\202\302\202\242\202\261\202\306\202Q/Models/Twitter/User.cs"
  • delete: "\202\302\202\242\202\261\202\306\202Q/Models/UpdateStatusCompletedEventArgs.cs"
  • delete: "\202\302\202\242\202\261\202\306\202Q/Properties/Resources.Designer.cs"
  • delete: "\202\302\202\242\202\261\202\306\202Q/Properties/Settings.Designer.cs"
  • delete: "\202\302\202\242\202\261\202\306\202Q/ViewModels/InputPinWindowViewModel.cs"
  • delete: "\202\302\202\242\202\261\202\306\202Q/ViewModels/MainWindowViewModel.cs"
  • delete: "\202\302\202\242\202\261\202\306\202Q/\202\302\202\242\202\261\202\306\202Q.csproj"
  • delete: "\202\302\202\242\202\261\202\306\202Q/app.config"

差异

Binary files "a/\202\302\202\242\202\261\202\306\202Q/InfrastructureAssemblies/LinqToTwitter.dll" and /dev/null differ
Binary files "a/\202\302\202\242\202\261\202\306\202Q/InfrastructureAssemblies/LinqToTwitter.pdb" and /dev/null differ
--- /dev/null
+++ "b/\202\302\202\242\202\261\202\306\202Q/InfrastructureAssemblies/ReactiveOAuth.XML"
@@ -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>
Binary files /dev/null and "b/\202\302\202\242\202\261\202\306\202Q/InfrastructureAssemblies/ReactiveOAuth.dll" differ
Binary files /dev/null and "b/\202\302\202\242\202\261\202\306\202Q/InfrastructureAssemblies/ReactiveOAuth.pdb" differ
--- "a/\202\302\202\242\202\261\202\306\202Q/Models/Model.cs"
+++ "b/\202\302\202\242\202\261\202\306\202Q/Models/Model.cs"
@@ -1,12 +1,14 @@
11 using System;
22 using System.Collections.Generic;
33 using System.Linq;
4-using System.Text;
5-
6-using Livet;
7-using LinqToTwitter;
4+using System.Net;
5+using System.Reactive.Linq;
86 using System.Threading;
97 using System.Threading.Tasks;
8+using System.Xml.Linq;
9+using Azyobuzi.Twikoto2.Models.Twitter;
10+using Codeplex.OAuth;
11+using Livet;
1012
1113 namespace Azyobuzi.Twikoto2.Models
1214 {
@@ -35,7 +37,10 @@ namespace Azyobuzi.Twikoto2.Models
3537 }
3638 }
3739
38- private TwitterContext twCtx = new TwitterContext();
40+ private const string ConsumerKey = "otUyZUQT0lupkH2Pnt4Zbw";
41+ private const string ConsumerSecret = "RwgpTjzZVXFeSOywxwVLaCViP3G68dXQCzi3xNApA";
42+
43+ private AccessToken token;
3944
4045 bool _IsAuthorized;
4146
@@ -54,40 +59,17 @@ namespace Azyobuzi.Twikoto2.Models
5459
5560 public void Authorize()
5661 {
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;
6663
6764 if (string.IsNullOrEmpty(Settings.AccessToken) || string.IsNullOrEmpty(Settings.AccessTokenSecret))
6865 {
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)));
8169 }
8270 else
8371 {
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);
9173 this.IsAuthorized = true;
9274 }
9375 }
@@ -115,37 +97,34 @@ namespace Azyobuzi.Twikoto2.Models
11597 }
11698 #endregion
11799
118- public void EndAuthorize(string pin, Action<TwitterAsyncResponse<UserIdentifier>> callback)
100+ public IObservable<TokenResponse<AccessToken>> EndAuthorize(RequestToken reqToken, string pin)
119101 {
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(_ =>
137105 {
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;
140111 });
141- }
142112 }
143113
144- public Task<Status> UpdateStatus(string text, string inReplyToId)
114+ public IObservable<Status> UpdateStatus(string text, string inReplyToId)
145115 {
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(_)));
149128 }
150129
151130 private Dictionary<Query, DispatcherCollection<Status>> timelinesCache =
@@ -189,29 +168,29 @@ namespace Azyobuzi.Twikoto2.Models
189168 {
190169 var timeline = this.Timeline;
191170 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+ //}
215194
216195 foreach (var status in statuses.Where(status => !timeline.Contains(status)))
217196 timeline.Add(status);
@@ -229,12 +208,16 @@ namespace Azyobuzi.Twikoto2.Models
229208 }
230209 }
231210
232- public IEnumerable<List> GetLists()
211+ public IObservable<string> GetListNames()
233212 {
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+ );
238221 }
239222 }
240223 }
--- "a/\202\302\202\242\202\261\202\306\202Q/Models/RequestPinCodeEventArgs.cs"
+++ "b/\202\302\202\242\202\261\202\306\202Q/Models/RequestPinCodeEventArgs.cs"
@@ -1,9 +1,19 @@
11 using System;
2+using Codeplex.OAuth;
23
34 namespace Azyobuzi.Twikoto2.Models
45 {
56 class RequestPinCodeEventArgs : EventArgs
67 {
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; }
818 }
919 }
--- /dev/null
+++ "b/\202\302\202\242\202\261\202\306\202Q/Models/Twitter/Status.cs"
@@ -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+}
--- /dev/null
+++ "b/\202\302\202\242\202\261\202\306\202Q/Models/Twitter/User.cs"
@@ -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+}
--- "a/\202\302\202\242\202\261\202\306\202Q/Models/UpdateStatusCompletedEventArgs.cs"
+++ /dev/null
@@ -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-}
--- "a/\202\302\202\242\202\261\202\306\202Q/Properties/Resources.Designer.cs"
+++ "b/\202\302\202\242\202\261\202\306\202Q/Properties/Resources.Designer.cs"
@@ -1,7 +1,7 @@
11 //------------------------------------------------------------------------------
22 // <auto-generated>
33 // このコードはツールによって生成されました。
4-// ランタイム バージョン:4.0.30319.225
4+// ランタイム バージョン:4.0.30319.235
55 //
66 // このファイルへの変更は、以下の状況下で不正な動作の原因になったり、
77 // コードが再生成されるときに損失したりします。
--- "a/\202\302\202\242\202\261\202\306\202Q/Properties/Settings.Designer.cs"
+++ "b/\202\302\202\242\202\261\202\306\202Q/Properties/Settings.Designer.cs"
@@ -1,7 +1,7 @@
11 //------------------------------------------------------------------------------
22 // <auto-generated>
33 // このコードはツールによって生成されました。
4-// ランタイム バージョン:4.0.30319.225
4+// ランタイム バージョン:4.0.30319.235
55 //
66 // このファイルへの変更は、以下の状況下で不正な動作の原因になったり、
77 // コードが再生成されるときに損失したりします。
--- "a/\202\302\202\242\202\261\202\306\202Q/ViewModels/InputPinWindowViewModel.cs"
+++ "b/\202\302\202\242\202\261\202\306\202Q/ViewModels/InputPinWindowViewModel.cs"
@@ -1,4 +1,5 @@
11 using System;
2+using Codeplex.OAuth;
23 using Livet;
34 using Livet.Command;
45 using Livet.Messaging.Window;
@@ -8,6 +9,8 @@ namespace Azyobuzi.Twikoto2.ViewModels
89 public class InputPinWindowViewModel : ViewModel
910 {
1011 public Uri AuthorizeUri { set; get; }
12+
13+ public RequestToken RequestToken { set; get; }
1114
1215 string _PinCode;
1316
--- "a/\202\302\202\242\202\261\202\306\202Q/ViewModels/MainWindowViewModel.cs"
+++ "b/\202\302\202\242\202\261\202\306\202Q/ViewModels/MainWindowViewModel.cs"
@@ -1,17 +1,15 @@
11 using System;
2-using System.Collections.Generic;
3-using System.Linq;
4-using System.Text;
52 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;
79 using Livet;
810 using Livet.Command;
911 using Livet.Messaging;
10-using Livet.Messaging.File;
1112 using Livet.Messaging.Window;
12-using Azyobuzi.Twikoto2.Models;
13-using System.Windows;
14-using System.Threading.Tasks;
1513
1614 namespace Azyobuzi.Twikoto2.ViewModels
1715 {
@@ -69,7 +67,7 @@ namespace Azyobuzi.Twikoto2.ViewModels
6967 DispatcherHelper.UIDispatcher);
7068 this.SelectedQuery = this.QueryTypes[0];
7169 }
72-
70+
7371 private Model model = new Model();
7472
7573 public Settings Settings
@@ -82,29 +80,22 @@ namespace Azyobuzi.Twikoto2.ViewModels
8280
8381 private void GetLists()
8482 {
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()
9985 {
100- DispatcherHelper.BeginInvoke(() =>
86+ Type = TimelineTypes.List,
87+ Name = "List : " + _,
88+ Parameter = _
89+ })
90+ .Subscribe(
91+ this.QueryTypes.Add,
92+ ex => DispatcherHelper.BeginInvoke(() =>
10193 this.Messenger.Raise(new InformationMessage(
102- resTask.Exception.ToString(),
94+ ex.ToString(),
10395 "リスト取得失敗",
10496 MessageBoxImage.Error,
105- "ShowInfo")));
106- }
107- });
97+ "ShowInfo")))
98+ );
10899 }
109100
110101 #region LoadedCommand
@@ -134,7 +125,11 @@ namespace Azyobuzi.Twikoto2.ViewModels
134125 DispatcherHelper.BeginInvoke(() =>
135126 {
136127 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+ };
138133 vm.PropertyChanged += this.InputPinWindowViewModel_PropertyChanged;
139134 this.Messenger.Raise(new TransitionMessage(vm, "GetPinCode"));
140135 });
@@ -146,24 +141,22 @@ namespace Azyobuzi.Twikoto2.ViewModels
146141 if (e.PropertyName == "Closed" && vm.Closed)
147142 {
148143 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+ );
152159
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- });
167160 }
168161 }
169162
@@ -181,7 +174,7 @@ namespace Azyobuzi.Twikoto2.ViewModels
181174 RaisePropertyChanged("Authorizing");
182175 }
183176 }
184-
177+
185178 #region ClosingCommand
186179 DelegateCommand _ClosingCommand;
187180
@@ -200,7 +193,7 @@ namespace Azyobuzi.Twikoto2.ViewModels
200193 this.Settings.Save();
201194 }
202195 #endregion
203-
196+
204197 string _StatusText = "";
205198
206199 public string StatusText
@@ -224,7 +217,7 @@ namespace Azyobuzi.Twikoto2.ViewModels
224217 return StatusText.Trim().Length > 140;
225218 }
226219 }
227-
220+
228221 string _InReplyToId = "";
229222
230223 public string InReplyToId
@@ -241,7 +234,7 @@ namespace Azyobuzi.Twikoto2.ViewModels
241234 RaisePropertyChanged("InReplyToId");
242235 }
243236 }
244-
237+
245238 bool _Posting;
246239
247240 public bool Posting
@@ -256,7 +249,7 @@ namespace Azyobuzi.Twikoto2.ViewModels
256249 RaisePropertyChanged("Posting");
257250 }
258251 }
259-
252+
260253 #region PostCommand
261254 DelegateCommand _PostCommand;
262255
@@ -280,30 +273,26 @@ namespace Azyobuzi.Twikoto2.ViewModels
280273 private void Post()
281274 {
282275 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+
302291 }
303292 #endregion
304-
293+
305294 public DispatcherCollection<QueryViewModel> QueryTypes { private set; get; }
306-
295+
307296 QueryViewModel _SelectedQuery;
308297
309298 public QueryViewModel SelectedQuery
@@ -335,7 +324,7 @@ namespace Azyobuzi.Twikoto2.ViewModels
335324 }
336325 }
337326
338- public DispatcherCollection<LinqToTwitter.Status> Timeline
327+ public DispatcherCollection<Status> Timeline
339328 {
340329 get
341330 {
--- "a/\202\302\202\242\202\261\202\306\202Q/app.config"
+++ "b/\202\302\202\242\202\261\202\306\202Q/app.config"
@@ -1,3 +1,11 @@
11 <?xml version="1.0"?>
22 <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>
--- "a/\202\302\202\242\202\261\202\306\202Q/\202\302\202\242\202\261\202\306\202Q.csproj"
+++ "b/\202\302\202\242\202\261\202\306\202Q/\202\302\202\242\202\261\202\306\202Q.csproj"
@@ -11,8 +11,7 @@
1111 <RootNamespace>Azyobuzi.Twikoto2</RootNamespace>
1212 <AssemblyName>Twikoto2</AssemblyName>
1313 <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
14- <TargetFrameworkProfile>
15- </TargetFrameworkProfile>
14+ <TargetFrameworkProfile>Client</TargetFrameworkProfile>
1615 <FileAlignment>512</FileAlignment>
1716 <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
1817 <WarningLevel>4</WarningLevel>
@@ -36,10 +35,6 @@
3635 <WarningLevel>4</WarningLevel>
3736 </PropertyGroup>
3837 <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>
4338 <Reference Include="Livet, Version=0.95.2011.517, Culture=neutral, processorArchitecture=MSIL">
4439 <SpecificVersion>False</SpecificVersion>
4540 <HintPath>InfrastructureAssemblies\Livet.dll</HintPath>
@@ -48,8 +43,14 @@
4843 <SpecificVersion>False</SpecificVersion>
4944 <HintPath>InfrastructureAssemblies\Microsoft.Expression.Interactions.dll</HintPath>
5045 </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>
5150 <Reference Include="System" />
5251 <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" />
5354 <Reference Include="System.Windows.Interactivity">
5455 <SpecificVersion>False</SpecificVersion>
5556 <HintPath>InfrastructureAssemblies\System.Windows.Interactivity.dll</HintPath>
@@ -70,6 +71,8 @@
7071 <Generator>MSBuild:Compile</Generator>
7172 <SubType>Designer</SubType>
7273 </ApplicationDefinition>
74+ <Compile Include="Models\Twitter\Status.cs" />
75+ <Compile Include="Models\Twitter\User.cs" />
7376 <Compile Include="Views\ToLocalTimeConverter.cs" />
7477 <Page Include="Views\InputPinWindow.xaml">
7578 <SubType>Designer</SubType>
@@ -88,7 +91,6 @@
8891 <Compile Include="Models\Model.cs" />
8992 <Compile Include="Models\Query.cs" />
9093 <Compile Include="Models\RequestPinCodeEventArgs.cs" />
91- <Compile Include="Models\UpdateStatusCompletedEventArgs.cs" />
9294 <Compile Include="Models\Settings.cs" />
9395 <Compile Include="Models\TimelineTypes.cs" />
9496 <Compile Include="MyNotifyObject.cs" />
@@ -121,7 +123,9 @@
121123 <Generator>ResXFileCodeGenerator</Generator>
122124 <LastGenOutput>Resources.Designer.cs</LastGenOutput>
123125 </EmbeddedResource>
124- <None Include="app.config" />
126+ <None Include="app.config">
127+ <SubType>Designer</SubType>
128+ </None>
125129 <None Include="Properties\Settings.settings">
126130 <Generator>SettingsSingleFileGenerator</Generator>
127131 <LastGenOutput>Settings.Designer.cs</LastGenOutput>
@@ -131,10 +135,12 @@
131135 <ItemGroup>
132136 <Content Include="InfrastructureAssemblies\Design\Livet.Design.dll" />
133137 <Content Include="InfrastructureAssemblies\Design\Livet.Expression.Design.dll" />
134- <Content Include="InfrastructureAssemblies\LinqToTwitter.dll" />
135138 <Content Include="InfrastructureAssemblies\Livet.dll" />
136139 <Resource Include="InfrastructureAssemblies\Livet.XML" />
137140 <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" />
138144 <Content Include="InfrastructureAssemblies\System.Windows.Interactivity.dll" />
139145 </ItemGroup>
140146 <ItemGroup>