public ShortProfileView(RectangleF rect, Tweet partialTweet, bool discloseButton) : this(rect, discloseButton) { // Load the picture we have for the user. if (partialTweet.IsSearchResult) profilePic.Image = ImageStore.RequestProfilePicture (partialTweet.UserId, null, this); }
public ConversationViewController(Tweet source) : base(null, true) { convSection = new Section (); ProcessConversation (source); Root = new RootElement (Locale.GetText("Conversation")) { convSection }; }
public DetailTweetView(RectangleF rect, Tweet tweet, TweetView.TappedEvent handler, DialogViewController parent) : base(rect) { var tweetRect = rect; if (tweet.Kind != TweetKind.Direct) tweetRect.Width -= 30; BackgroundColor = UIColor.Clear; tweetView = new TweetView (tweetRect, tweet.Text){ BackgroundColor = UIColor.Clear, }; if (handler != null) tweetView.Tapped += handler; AddSubview (tweetView); float y = tweetView.Frame.Height + PadY; string thumbUrl, previewUrl; var picUrl = PicDetect.FindPicUrl (tweet.Text, out thumbUrl, out previewUrl); if (picUrl != null){ borderAt = y; SetupImagePreview (parent, y, picUrl, thumbUrl, previewUrl); y += 90; } rect.Y = y; rect.Height = smallSize; AddSubview (new UILabel (rect) { Text = Util.FormatTime (new TimeSpan (DateTime.UtcNow.Ticks - tweet.CreatedAt)) + " ago from " + tweet.Source, TextColor = UIColor.Gray, Font = UIFont.SystemFontOfSize (smallSize) }); y += PadY; var f = Frame; f.Y += PadY; f.Height = y + PadY + smallSize + 2; Frame = f; if (tweet.Kind != TweetKind.Direct){ // Now that we now our size, center the button buttonView = UIButton.FromType (UIButtonType.Custom); buttonView.Frame = new RectangleF (tweetRect.X + tweetRect.Width, (f.Height-38)/2-4, 38, 38); UpdateButtonImage (tweet); buttonView.TouchDown += delegate { tweet.Favorited = !tweet.Favorited; Util.MainAppDelegate.FavoriteChanged (tweet); TwitterAccount.CurrentAccount.Post (String.Format ("http://api.twitter.com/1/favorites/{0}/{1}.json", tweet.Favorited ? "create" : "destroy", tweet.Id),""); UpdateButtonImage (tweet); tweet.Replace (Database.Main); }; AddSubview (buttonView); } }
public DetailTweetView(RectangleF rect, Tweet tweet, TweetView.TappedEvent tapped, TweetView.TappedEvent tapAndHold, DialogViewController parent) : base(rect) { var tweetRect = rect; if (tweet.Kind != TweetKind.Direct) tweetRect.Width -= 30; BackgroundColor = UIColor.Clear; tweetView = new TweetView (tweetRect, tweet.Text, tapped, tapAndHold){ BackgroundColor = UIColor.Clear, }; AddSubview (tweetView); float y = tweetView.Frame.Height + PadY; string thumbUrl, previewUrl; var picUrl = PicDetect.FindPicUrl (tweet.Text, out thumbUrl, out previewUrl); if (picUrl != null){ borderAt = y; SetupImagePreview (parent, y, picUrl, thumbUrl, previewUrl); y += 90; } rect.Y = y; rect.Height = smallSize; AddSubview (new UILabel (rect) { Text = Locale.Format ("{0} ago from {1}", Util.FormatTime (new TimeSpan (DateTime.UtcNow.Ticks - tweet.CreatedAt)), tweet.Source), TextColor = UIColor.Gray, BackgroundColor = UIColor.Clear, Font = UIFont.SystemFontOfSize (smallSize) }); y += PadY; var f = Frame; f.Y += PadY; f.Height = y + PadY + smallSize + 2; Frame = f; if (tweet.Kind != TweetKind.Direct){ // Now that we now our size, center the button buttonView = UIButton.FromType (UIButtonType.Custom); buttonView.Frame = new RectangleF (tweetRect.X + tweetRect.Width, (f.Height-38)/2-4, 38, 38); UpdateButtonImage (tweet.Favorited); buttonView.TouchDown += delegate { UpdateButtonImage (!tweet.Favorited); AppDelegate.MainAppDelegate.ToggleFavorite (tweet); }; AddSubview (buttonView); } }
public PhotoPostViewController (UINavigationController msp, UIImage image, Tweet tweet) : this() { this._image = image; this._MSP = msp; this.eventImage = tweet.Image; this.postOptions = tweet.Options; this.isForEvent = true; PhotoLocation = new CLLocation(eventImage.Latitude, eventImage.Longitude); this.root = CreateRoot (); Description.Value = eventImage.Name; Keywords.AddRange(tweet.Keywords); }
public void Retweet(UIViewController controller, Tweet tweet) { var sheet = Util.GetSheet (Locale.GetText ("Retweet")); sheet.AddButton (Locale.GetText ("Retweet")); sheet.AddButton (Locale.GetText ("Quote Retweet")); sheet.AddButton (Locale.GetText ("Cancel")); sheet.CancelButtonIndex = 2; sheet.Clicked += delegate(object s, UIButtonEventArgs e) { if (!tweet.Favorited && Util.Defaults.IntForKey ("disableFavoriteRetweets") == 0) ToggleFavorite (tweet); if (e.ButtonIndex == 0) TwitterAccount.CurrentAccount.Post ("http://api.twitter.com/1/statuses/retweet/" + tweet.Id + ".json", ""); else if (e.ButtonIndex == 1){ Composer.Main.Quote (controller, tweet); } }; sheet.ShowInView (AppDelegate.MainAppDelegate.MainView); }
/// <summary> /// Loads the tweets encoded in the JSon response from the server /// into the database. Users that are detected in the stream /// are entered in the user database as well. /// </summary> public static int LoadJson(Stream stream, int localAccount, TweetKind kind) { Database db = Database.Main; int count = 0; JsonValue root; string userKey; try { root = JsonValue.Load (stream); if (kind == TweetKind.Direct) userKey = "sender"; else userKey = "user"; } catch (Exception e) { Console.WriteLine (e); return -1; } // These are reusable instances that we used during population var tweet = new Tweet () { Kind = kind, LocalAccountId = localAccount }; var user = new User (); var start = DateTime.UtcNow; var usersSeen = new HashSet<long> (); lock (db){ db.Execute ("BEGIN"); foreach (JsonObject jentry in root){ var juser = jentry [userKey]; bool result; if (!ParseUser ((JsonObject) juser, user, usersSeen)) continue; if (kind == TweetKind.Direct) result = tweet.TryPopulateDirect (jentry); else result = tweet.TryPopulate (jentry); if (result){ PopulateUser (tweet, user); tweet.Insert (db); count++; } // Repeat user loading for the retweet info if (tweet.Retweeter != null) ParseUser ((JsonObject)(jentry ["retweeted_status"]["user"]), user, usersSeen); } db.Execute ("COMMIT"); } var end = DateTime.UtcNow; Util.Log ("With transactions: Spent {0} ticks in inserting {1} elements", (end-start).Ticks, count); return count; }
static Tweet FromJsonEntry(JsonObject jentry, User user) { var tweet = new Tweet () { Kind = TweetKind.Transient }; if (!tweet.TryPopulate (jentry)) return null; PopulateUser (tweet, user); if (tweet.Retweeter != null){ user = new User (); user.UpdateFromJson ((JsonObject)(jentry ["retweeted_status"]["user"])); lock (Database.Main) Database.Main.Insert (user, "OR REPLACE"); } return tweet; }
public override void FavoriteChanged(Tweet tweet) { if (!loaded) return; CancelMenu (); try { Section main = Root [0]; if (tweet.Favorited){ // Lame, inserted at top, but does it matter that much? main.Insert (0, UITableViewRowAnimation.None, new TweetElement (tweet)); } else { for (int i = 0; i < main.Count; i++){ var te = main [i] as TweetElement; if (te == null) continue; if (te.Tweet == tweet){ main.Remove (i); return; } } } } catch { } }
// Once we have a full tweet, setup the rest of the view. void SetTweet(Tweet fullTweet) { this.tweet = fullTweet; userTimeline.UserReference = User.FromId (tweet.UserId); shortProfileView.UpdateFromUserId (tweet.UserId); shortProfileView.PictureTapped += delegate { PictureViewer.Load (this, tweet.UserId); }; shortProfileView.Tapped += LoadFullProfile; shortProfileView.UrlTapped += delegate { WebViewController.OpenUrl (this, User.FromId (tweet.UserId).Url); }; if (tweet.InReplyToStatus != 0){ var in_reply = new ConversationRootElement (Locale.Format ("In reply to: {0}", tweet.InReplyToUserName), tweet); main.Add (in_reply); } }
// Populates a Tweet object with cached and useful user information static void PopulateUser(Tweet tweet, User user) { if (tweet.Retweeter != null){ tweet.UserId = tweet.RetweeterId; tweet.Screename = tweet.Retweeter; tweet.PicUrl = tweet.RetweeterPicUrl; tweet.RetweeterId = user.Id; tweet.Retweeter = user.Screenname; tweet.RetweeterPicUrl = user.PicUrl; if (tweet.RetweeterPicUrl == null) Console.WriteLine ("TWEFF"); } else { tweet.UserId = user.Id; tweet.Screename = user.Screenname; tweet.PicUrl = user.PicUrl; } }
public void Quote(UIViewController parent, Tweet source) { ResetComposer(Locale.GetText("Quote"), "RT @" + source.Screename + " " + source.Text); Activate(parent); }
// // This method is called when the cell is reused to reset // all of the cell values // public void UpdateCell(Tweet tweet) { tweetView.Update (tweet); SetNeedsDisplay (); }
public ConversationRootElement(string caption, Tweet source) : base(caption) { this.source = source; }
public DetailTweetViewController(Tweet partialTweet) : base(UITableViewStyle.Grouped, null, true) { bool isMine = false; if (partialTweet.IsSearchResult) { Tweet.LoadFullTweet(partialTweet.Id, fullTweet => SetTweet(fullTweet)); } else { isMine = partialTweet.UserId == TwitterAccount.CurrentAccount.AccountId; // Hack until we figure out why DELETE is not working with OAuth // and making the server return 401 Unauthorized isMine = false; } var handlers = new EventHandler [] { Reply, Retweet, Direct, Delete }; var profileRect = new RectangleF(PadX, 0, View.Bounds.Width - PadX, 100); var detailRect = new RectangleF(PadX, 0, View.Bounds.Width - 30 - PadX * 2, 0); shortProfileView = new ShortProfileView(profileRect, partialTweet, true); profileRect.Height += 8; var triangle = new TriangleView(UIColor.White, UIColor.FromRGB(171, 171, 171)) { Frame = new RectangleF(43, shortProfileView.Bounds.Height + 1, 16, 8) }; var containerView = new UIView(profileRect); containerView.Add(shortProfileView); containerView.Add(triangle); main = new Section(containerView) { new UIViewElement(null, new DetailTweetView(detailRect, partialTweet, TapHandler, TapAndHoldHandler, this), false) { Flags = UIViewElement.CellFlags.DisableSelection } }; Section replySection = new Section(); if (partialTweet.Kind == TweetKind.Direct) { replySection.Add(new StringElement(Locale.GetText("Direct Reply"), delegate { Direct(this, EventArgs.Empty); })); } else { replySection.Add(new UIViewElement(null, new ButtonsView(isMine ? 4 : 3, buttons, handlers), true) { Flags = UIViewElement.CellFlags.DisableSelection | UIViewElement.CellFlags.Transparent }); } userTimeline = TimelineRootElement.MakeTimeline(partialTweet.Screename, Locale.GetText("User's timeline"), "http://api.twitter.com/1/statuses/user_timeline.json?skip_user=true&screen_name=" + partialTweet.Screename, User.FromTweet(partialTweet)); tweet = partialTweet; if (!partialTweet.IsSearchResult) { SetTweet(partialTweet); } Root = new RootElement(partialTweet.Screename) { main, replySection, new Section() { userTimeline } }; }
void TapAndHoldHandler(string data) { UIActionSheet sheet; if (Tweet.IndexOfUrlStarter(data, 0) != -1) { sheet = Util.GetSheet(data); sheet.AddButton(Locale.GetText("Open")); sheet.AddButton(Locale.GetText("Open in Safari")); sheet.AddButton(Locale.GetText("Copy")); sheet.AddButton(Locale.GetText("Cancel")); sheet.CancelButtonIndex = 3; sheet.Clicked += delegate(object sender, UIButtonEventArgs e) { if (e.ButtonIndex == 0) { AppDelegate.MainAppDelegate.Open(this, data); } else if (e.ButtonIndex == 1) { UIApplication.SharedApplication.OpenUrl(new NSUrl(data)); } else if (e.ButtonIndex == 2) { UIPasteboard.General.SetValue(new NSString(data), "public.utf8-plain-text"); } }; } else if (data [0] == '@') { sheet = Util.GetSheet(data); sheet.AddButton(Locale.GetText("Reply")); sheet.AddButton(Locale.GetText("Private Reply")); sheet.AddButton(Locale.GetText("Open profile")); sheet.AddButton(Locale.GetText("Search mentions")); sheet.AddButton(Locale.GetText("Cancel")); sheet.CancelButtonIndex = 4; sheet.Clicked += delegate(object sender, UIButtonEventArgs e) { switch (e.ButtonIndex) { case 0: Composer.Main.ReplyTo(this, tweet, data); break; case 1: Composer.Main.Direct(this, data.Substring(1)); break; case 2: AppDelegate.MainAppDelegate.Open(this, data); break; case 3: ActivateController(new SearchViewController(data) { Account = TwitterAccount.CurrentAccount }); break; } }; } else if (data [0] == '#') { sheet = Util.GetSheet(data); sheet.AddButton(Locale.GetText("Search mentions")); sheet.AddButton(Locale.GetText("Post with topic")); sheet.AddButton(Locale.GetText("Cancel")); sheet.CancelButtonIndex = 2; sheet.Clicked += delegate(object sender, UIButtonEventArgs e) { if (e.ButtonIndex == 0) { ActivateController(new SearchViewController(data) { Account = TwitterAccount.CurrentAccount }); } else if (e.ButtonIndex == 1) { Composer.Main.NewTweet(this, data + " "); } }; } else { return; } sheet.ShowInView(AppDelegate.MainAppDelegate.MainView); }
// Broadcast the change, since tweets can be instantiated multiple times. void FavoriteChanged(Tweet tweet) { favorites.FavoriteChanged (tweet); main.FavoriteChanged (tweet); mentions.FavoriteChanged (tweet); }
public TweetCellView(Tweet tweet) : base() { Update (tweet); Opaque = true; BackgroundColor = UIColor.White; }
// Returns an IEnumerable of tweets when parsing search // results from twitter. The returned Tweet objects are // not really complete and have the UserId busted (negative // numbers) since the userids returned by twitter for // searches have no relationship with the rest of the system public static IEnumerable<Tweet> TweetsFromSearchResults(Stream stream) { JsonValue root; try { root = JsonValue.Load (stream); } catch (Exception e) { Console.WriteLine (e); yield break; } foreach (JsonObject result in root ["results"]){ Tweet tweet; try { tweet = new Tweet () { CreatedAt = ParseCreationSearch (result), Id = (long) result ["id"], Text = ParseText (result), Source = Util.StripHtml (HttpUtility.HtmlDecode (result ["source"]) ?? ""), UserId = serial++, Screename = (string) result ["from_user"], PicUrl = (string) result ["profile_image_url"] }; } catch (Exception e){ Console.WriteLine (e); tweet = null; } if (tweet != null) yield return tweet; } }
public void Update(Tweet tweet) { this.tweet = tweet; userText = tweet.Retweeter == null ? tweet.Screename : tweet.Screename + "→" + tweet.Retweeter; // // For fake UserIDs (returned by the search), we try looking up by screename now // var img = ImageStore.GetLocalProfilePicture (tweet.UserId); if (img == null) img = ImageStore.GetLocalProfilePicture (tweet.Screename); if (img == null) ImageStore.QueueRequestForPicture (tweet.UserId, tweet.PicUrl, this); else tweet.PicUrl = null; tweetImage = img == null ? ImageStore.DefaultImage : img; if (tweet.Retweeter == null) retweetImage = null; else { img = ImageStore.GetLocalProfilePicture (tweet.RetweeterId); if (img == null) ImageStore.QueueRequestForPicture (tweet.RetweeterId, tweet.RetweeterPicUrl, this); else tweet.RetweeterPicUrl = null; retweetImage = img == null ? ImageStore.DefaultImage : img; } SetNeedsDisplay (); }
public DetailTweetViewController(Tweet partialTweet) : base(UITableViewStyle.Grouped, null, true) { bool isMine = false; if (partialTweet.IsSearchResult) Tweet.LoadFullTweet (partialTweet.Id, fullTweet => SetTweet (fullTweet)); else { isMine = partialTweet.UserId == TwitterAccount.CurrentAccount.AccountId; // Hack until we figure out why DELETE is not working with OAuth // and making the server return 401 Unauthorized isMine = false; } var handlers = new EventHandler [] { Reply, Retweet, Direct, Delete }; var profileRect = new RectangleF (PadX, 0, View.Bounds.Width-PadX, 100); var detailRect = new RectangleF (PadX, 0, View.Bounds.Width-30-PadX*2, 0); shortProfileView = new ShortProfileView (profileRect, partialTweet, true); profileRect.Height += 8; var triangle = new TriangleView (UIColor.White, UIColor.FromRGB (171, 171, 171)) { Frame = new RectangleF (43, shortProfileView.Bounds.Height+1, 16, 8) }; var containerView = new UIView (profileRect); containerView.Add (shortProfileView); containerView.Add (triangle); main = new Section (containerView){ new UIViewElement (null, new DetailTweetView (detailRect, partialTweet, TapHandler, TapAndHoldHandler, this), false) { Flags = UIViewElement.CellFlags.DisableSelection } }; Section replySection = new Section (); if (partialTweet.Kind == TweetKind.Direct) replySection.Add (new StringElement (Locale.GetText ("Direct Reply"), delegate { Direct (this, EventArgs.Empty); })); else replySection.Add (new UIViewElement (null, new ButtonsView (isMine ? 4 : 3, buttons, handlers), true) { Flags = UIViewElement.CellFlags.DisableSelection | UIViewElement.CellFlags.Transparent }); userTimeline = TimelineRootElement.MakeTimeline (partialTweet.Screename, Locale.GetText ("User's timeline"), "http://api.twitter.com/1/statuses/user_timeline.json?skip_user=true&screen_name=" + partialTweet.Screename, User.FromTweet (partialTweet)); tweet = partialTweet; if (!partialTweet.IsSearchResult) SetTweet (partialTweet); Root = new RootElement (partialTweet.Screename){ main, replySection, new Section () { userTimeline } }; }
public TweetElement(Tweet tweet) : base(null) { Tweet = tweet; }
// // This is necessary because the server-side tweet can // be instantiated in various ways // public virtual void FavoriteChanged(Tweet tweet) { // Should be abstract, but virtual until I fix all the derived classes }
public MemberPhotoElement (Tweet tweet, Action<int> goToMembersPhotoAction) : base (null) { Tweet = tweet; _GoToMembersPhotoAction = goToMembersPhotoAction; }
public override void FavoriteChanged(Tweet tweet) { if (Root.Count > 0){ Section main = Root [0]; foreach (var element in main.Elements){ var te = element as TweetElement; if (te != null && te.Tweet.Id == tweet.Id) te.Tweet.Favorited = tweet.Favorited; } } }
public PhotoLikersViewController (UIViewController msp, Tweet tweet) : base("PhotoLikersViewController", null) { _Tweet = tweet; _MSP = msp; }
public static User FromTweet(Tweet tweet) { if (tweet.UserId >= ImageStore.TempStartId){ var u = new User (); u.Screenname = tweet.Screename; u.Id = tweet.UserId; u.PicUrl = tweet.PicUrl; return u; } return FromId (tweet.UserId); }
public pickerDelegate(VCViewController msp, UINavigationController shareNavCont, Tweet tweet) :this(msp, shareNavCont) { this.tweet = tweet; }
// Replies to a tweet public void Reply(UIViewController controller, Tweet tweet) { if (tweet == null) throw new ArgumentNullException ("tweet"); int p = tweet.Text.IndexOf ('@'); if (p == -1){ Composer.Main.ReplyTo (controller, tweet, false); return; } // If we have a '@' make sure it is not just @user // but someone else is included if (tweet.Text.Substring (p+1).StartsWith (TwitterAccount.CurrentAccount.Username)){ p = tweet.Text.IndexOf ('@', p + 1 + TwitterAccount.CurrentAccount.Username.Length); if (p == -1){ Composer.Main.ReplyTo (controller, tweet, false); return; } } var sheet = Util.GetSheet (""); sheet.AddButton (Locale.GetText ("Reply")); sheet.AddButton (Locale.GetText ("Reply All")); sheet.AddButton (Locale.GetText ("Cancel")); sheet.CancelButtonIndex = 2; sheet.Clicked += delegate(object s, UIButtonEventArgs e) { if (e.ButtonIndex == 0) Composer.Main.ReplyTo (controller, tweet, false); else if (e.ButtonIndex == 1){ Composer.Main.ReplyTo (controller, tweet, true); } }; sheet.ShowInView (MainAppDelegate.MainView); }
// Populates a Tweet object with cached and useful user information static void PopulateUser(Tweet tweet, User user) { if (tweet.Retweeter != null){ tweet.UserId = tweet.RetweeterId; tweet.Screename = tweet.Retweeter; tweet.PicUrl = tweet.RetweeterPicUrl; tweet.RetweeterId = user.Id; tweet.Retweeter = user.Screenname; tweet.RetweeterPicUrl = user.PicUrl; } else { tweet.UserId = user.Id; tweet.Screename = user.Screenname; tweet.PicUrl = user.PicUrl; } }
public void ToggleFavorite(Tweet tweet) { tweet.Favorited = !tweet.Favorited; FavoriteChanged (tweet); TwitterAccount.CurrentAccount.Post (String.Format ("http://api.twitter.com/1/favorites/{0}/{1}.json", tweet.Favorited ? "create" : "destroy", tweet.Id),""); lock (Database.Main) tweet.Replace (Database.Main); }
protected override IEnumerable <Tweet> GetTweetStream(Stream result) { return(Tweet.TweetsFromSearchResults(result, ReferenceUser)); }
/// <summary> /// Loads as many tweets as possible from the database, and if they are missing /// requests them from the service. /// </summary> void ProcessConversation(Tweet previous) { convSection.Add (new TweetElement (previous)); while (previous != null && previous.InReplyToStatus != 0) { var lookup = Tweet.FromId (previous.InReplyToStatus); if (lookup == null){ QueryServer (previous.InReplyToStatus); return; } else convSection.Add (new TweetElement (lookup)); previous = lookup; } EndConversation (); }
// // Alternative version that just parses the users and tweets and returns them as lists // I thought it would be useful, but it is not. The JSon parsing is too fast, we // only get bogged down with the actual sqlite insert // public static void ParseJson(Stream stream, int localAccount, TweetKind kind, out List<User> users, out List<Tweet> tweets) { JsonValue root; string userKey; try { root = JsonValue.Load (stream); if (kind == TweetKind.Direct) userKey = "sender"; else userKey = "user"; } catch (Exception e) { Console.WriteLine (e); tweets = null; users = null; return; } users = new List<User> (root.Count/4); tweets = new List<Tweet> (root.Count); var start = DateTime.UtcNow; var usersSeen = new HashSet<long> (); var user = new User (); foreach (JsonObject jentry in root){ var juser = jentry [userKey]; bool result; try { user.UpdateFromJson ((JsonObject) juser); if (!usersSeen.Contains (user.Id)){ usersSeen.Add (user.Id); users.Add (user); user = new User (); } } catch { continue; } var tweet = new Tweet (); if (kind == TweetKind.Direct) result = tweet.TryPopulateDirect (jentry); else result = tweet.TryPopulate (jentry); if (result){ PopulateUser (tweet, user); tweets.Add (tweet); } // Repeat user loading for the retweet info if (tweet.Retweeter != null){ user.UpdateFromJson ((JsonObject)(jentry ["retweeted_status"]["user"])); if (!usersSeen.Contains (user.Id)){ usersSeen.Add (user.Id); users.Add (user); user = new User (); } } } var end = DateTime.UtcNow; Console.WriteLine ("Parsing time for tweet stream: {0} for {1} tweets", end-start, tweets.Count); }
// // Alternative version that just parses the users and tweets and returns them as lists // I thought it would be useful, but it is not. The JSon parsing is too fast, we // only get bogged down with the actual sqlite insert // public static void ParseJson(Stream stream, int localAccount, TweetKind kind, out List <User> users, out List <Tweet> tweets) { JsonValue root; string userKey; try { root = JsonValue.Load(stream); if (kind == TweetKind.Direct) { userKey = "sender"; } else { userKey = "user"; } } catch (Exception e) { Console.WriteLine(e); tweets = null; users = null; return; } users = new List <User> (root.Count / 4); tweets = new List <Tweet> (root.Count); var start = DateTime.UtcNow; var usersSeen = new HashSet <long> (); var user = new User(); foreach (JsonObject jentry in root) { var juser = jentry [userKey]; bool result; try { user.UpdateFromJson((JsonObject)juser); if (!usersSeen.Contains(user.Id)) { usersSeen.Add(user.Id); users.Add(user); user = new User(); } } catch { continue; } var tweet = new Tweet(); if (kind == TweetKind.Direct) { result = tweet.TryPopulateDirect(jentry); } else { result = tweet.TryPopulate(jentry); } if (result) { PopulateUser(tweet, user); tweets.Add(tweet); } // Repeat user loading for the retweet info if (tweet.Retweeter != null) { user.UpdateFromJson((JsonObject)(jentry ["retweeted_status"]["user"])); if (!usersSeen.Contains(user.Id)) { usersSeen.Add(user.Id); users.Add(user); user = new User(); } } } var end = DateTime.UtcNow; Util.Log("Parsing time for tweet stream: {0} for {1} tweets", end - start, tweets.Count); }
float Layout() { float max = Bounds.Width, segmentLength, lastx = 0, x = 0, y = 0; int p = 0; UIFont font = regular, lastFont = null; string line = ""; blocks.Clear(); while (p < text.Length) { int sidx = text.IndexOf(' ', p); if (sidx == -1) { sidx = text.Length - 1; } var segment = text.Substring(p, sidx - p + 1); if (segment.Length == 0) { break; } // if the word contains @ like ".@foo" or "foo@bar", split there as well int aidx = segment.IndexOf('@'); if (aidx > 0) { segment = segment.Substring(0, aidx); sidx = p + segment.Length - aidx; } var start = segment [0]; if (start == '@' || start == '#' || Tweet.IndexOfUrlStarter(segment, 0) != -1) { font = bold; } else { font = regular; } segmentLength = StringSize(segment, font).Width; // If we would overflow the line. if (x + segmentLength >= max) { // Push the text we have so far, go to next line if (line != "") { blocks.Add(new Block() { Bounds = new RectangleF(lastx, y, x - lastx, lineHeight), Value = line, Font = lastFont ?? font, }); lastFont = font; y += lineHeight; lastx = 0; } // Too long to fit even on its own line, stick it on its own line. if (segmentLength >= max) { var dim = StringSize(segment, font, new SizeF(max, float.MaxValue), UILineBreakMode.WordWrap); blocks.Add(new Block() { Bounds = new RectangleF(new PointF(0, y), dim), Value = segment, Font = lastFont ?? font }); y += dim.Height; x = 0; line = ""; } else { x = segmentLength; line = segment; } p = sidx + 1; lastFont = font; } else { // append the segment if the font changed, or if the font // is bold (so we can make a tappable element on its own). if (x != 0 && (font != lastFont || font == bold)) { blocks.Add(new Block() { Bounds = new RectangleF(lastx, y, x - lastx, lineHeight), Value = line, Font = lastFont }); lastx = x; line = segment; lastFont = font; } else { lastFont = font; line = line + segment; } x += segmentLength; p = sidx + 1; } // remove duplicate spaces while (p < text.Length && text [p] == ' ') { p++; } //Console.WriteLine ("p={0}", p); } if (line == "") { return(y); } blocks.Add(new Block() { Bounds = new RectangleF(lastx, y, x - lastx, lineHeight), Value = line, Font = font }); return(y + lineHeight); }